glibc堆all-in-one
字数 4397 2025-08-20 18:17:42
glibc堆利用全指南
1. 堆分配基础
1.1 malloc函数工作原理
-
fastbin分配:
- 大小范围: 0x20-0x80
- LIFO(后进先出)策略
- 流程:
- 根据size计算idx
- 如果fastbin[idx]不为空则取first chunk
- 如果为空则进入unsorted bins大循环
-
smallbin分配:
- 大小范围: ≤0x3f0
- FIFO(先进先出)策略
- 流程:
- 根据size计算idx
- 如果smallbin[idx]不为空则取last chunk
- 如果为空且已初始化则进入unsorted bins大循环
- 如果未初始化则调用malloc_consolidate后再进入unsorted bins大循环
-
largebin分配:
- 大小范围: ≥0x400
- 如果既不在fastbin也不在smallbin范围内:
- 无fastchunks则直接进入unsorted bins大循环
- 有fastchunks则调用malloc_consolidate后再进入unsorted bins大循环
1.2 malloc_consolidate函数
-
功能:
- 合并fastbin中的chunk并放入unsorted bin
- 与top chunk合并的chunk除外
-
流程:
- 遍历fastbinY数组(每个元素是单向链表头部)
- 检查prev inuse:
- 为0则unlink prev chunk
- 为1则检查next chunk
- 检查next chunk:
- 如果是top chunk则与之合并
- 否则检查next inuse:
- 为0则unlink next chunk
- 为1则不做操作
- 将合并后的chunk插入unsorted bins
- 循环直到fastbinY为空
1.3 unsorted bins大循环
-
遍历unsorted bin寻找满足条件的chunk:
- 大小刚好合适则返回
- 在small bin范围内则放入small bin
- large bin为空则放入large bin
- 其他情况从large bin尾部寻找合适位置
-
切割机制:
- 如果没有合适大小的free chunk
- 检查是否有大的free chunk可以切割(除fastbins外)
- 切割后的剩余部分成为last remainder并放入unsortedbin
1.4 free函数
-
释放流程:
- 检查能否放入fastbin
- 检查能否进行后向合并与unlink prev chunk
- 检查能否和top chunk合并
- 检查能否进行前向合并与unlink next chunk
- 放入unsorted bin头部
- 进行一系列安全检查
-
安全检查:
- 检查chunk大小是否小于max fast
- 防止fastbin double free
- 检查chunk是否是mmaped
- 检查当前chunk是否是inuse状态
2. 关键概念
2.1 基本概念
-
bins链表:
- 使用头插法
- fd和bk只在bins中存在
- 指向chunk头部而非mem区域
-
chunk关系:
- prev chunk: 地址较低的chunk
- next chunk: 地址较高的chunk
-
tcache:
- 大小范围: 0x20-0x410
- 高版本glibc中,tcache bin满后再free相同大小的chunk会尝试unlink
2.2 unlink操作
-
目的:
- 从双向链表中取出空闲块(如free时合并相邻free chunk)
-
检查缺陷:
- fd/bk指针通过与chunk头部的相对地址查找
- 可用于绕过安全检查
-
特殊情况:
- chunk大小<0x80时直接进入tcache,不参与unlink
- unlink后的overlapping chunk都会进入unsorted bin
2.3 常见漏洞
-
UAF(Use After Free):
- 条件: free后未置NULL,紧接着申请相同大小内存
- 利用: 操作系统会重新分配刚free的内存
-
chunk extend/overlapping:
- 条件: 可控制chunk header数据(常结合off-by-one使用)
- 方法: 修改size字段后free,导致next chunk被overlapping
- 作用: 控制chunk内容而非执行流程
-
off-by-one/off-by-null:
- 允许修改相邻chunk的size字段
- 常用于构造chunk overlapping
3. 利用技巧
3.1 信息泄露
-
泄露heap base:
- 通常为修改tcache_perthread_struct
- 方法: 让tcache结构变成1->0,通过show函数泄露
-
泄露libc base:
- 通过unsortedbin特性泄露
- 方法:
- 获取unsortedbin chunk
- show出main_arena附近地址
- 计算偏移得到libc base
- 替代方法:
- 利用largebin同时泄露libc和heap
- 打__IO_2_1_stdout泄露
- 利用fd/bk写入特性
3.2 常见攻击目标
-
__free_hook:
- 通过tcache poison修改
- 常用gadget: system或one_gadget
-
tcache_perthread_struct:
- 修改counts数组可控制tcache分配
- libc2.30以下: counts类型为char
- libc2.30及以上: counts类型为uint16_t
-
mp_结构体:
- 通过large bin attack修改mp_.tcache_bins
- 使large bin chunk进入tcache
-
stdout/IO_2_1_stdout:
- 用于泄露信息或FSOP
- 可泄露出_environ获取栈地址
3.3 特殊技巧
-
scanf触发malloc_consolidate:
- 输入长字符串会调用malloc分配内存
- 可用于合并fastchunks到unsorted bin
-
calloc绕过tcache:
- calloc不从tcache分配
- 可用于绕过tcache相关保护
-
environ变量利用:
- 储存系统环境变量地址
- 通过libc找到environ地址后可泄露栈地址
-
magic gadget:
- 如setcontext+53等
- 用于控制执行流
4. 保护机制与绕过
4.1 glibc版本差异
-
glibc-2.32:
- tcache/fastbin堆指针异或加密
- 堆内存对齐检查
-
glibc-2.33:
- tcachebin链数量检查
-
glibc-2.34:
- 移除__malloc_hook和__free_hook
- 引入tcache_key检查
-
glibc-2.36:
- 移除IO处理函数
-
glibc-2.37:
- 移除__malloc_assert函数
- global_max_fast类型改为uint8_t
4.2 绕过技巧
-
异或加密绕过:
- 泄露heap base计算加密key
- libc2.31: tcache-key为heapbase+0x10
-
检查绕过:
- libc2.31不对tcache 0x10对齐检查
- 利用large bin attack修改检查条件
-
hook移除后的利用:
- 转向FSOP或IO_FILE攻击
- 使用house of apple/cat等新技术
5. 高级利用技术
5.1 House of系列攻击
-
House of Orange:
- 修改top chunk size
- 分配大chunk使top进入unsorted bin
- unsorted bin attack修改_IO_list_all
- 布置FAKE FILE进行FSOP
-
House of Pig:
- 利用_IO_str_overflow的malloc/memcpy/free三连
- 设置参数使free_hook被覆盖为system
- 需要exit函数触发_IO_flush_all_lockp
-
House of Kiwi:
- 触发__malloc_assert
- 修改_IO_file_jumps和IO_helper_jumps
- 无需exit函数
-
House of Emma:
- 伪造_IO_cookie_file
- 劫持pointer guard
- libc2.34及以下可用
-
House of Cat:
- 在_IO_switch_to_wget_mode设置rdx
- 调用setcontext+61进行ORW
- 需要控制rcx不为0
-
House of Apple2:
- 覆盖vtable为_IO_wxxx_jumps
- 执行_IO_wfile_overflow
- 利用magic gadget
5.2 IO_FILE利用
-
FSOP(File Stream Oriented Programming):
- 劫持_IO_list_all伪造链表
- 触发_IO_flush_all_lockp
- 调用vtable中的_IO_overflow
-
关键结构:
- _IO_FILE: 文件流基础结构
- _IO_FILE_plus: 包含vtable
- _IO_jump_t: 虚函数表
- _IO_wide_data: 宽字符数据
-
利用条件:
- 控制_IO_list_all
- _lock设置为可写地址
- _mode=0
- _IO_write_ptr > _IO_write_base
-
常用目标:
- _IO_list_all
- IO_2_1_stderr
- stderr
6. 实战技巧
6.1 调试技巧
-
关键断点:
b *&_IO_cleanup b *&_IO_flush_all b *&_IO_flush_all_lockp b *&_IO_flush_all_lockp+223 b *&_IO_wfile_seekoff b *&_IO_switch_to_wget_mode -
符号表问题:
- 从glibc-all-in-one获取有符号表的同版本libc
- 便于pwndbg调试
6.2 利用模板
- House of Apple2利用:
fake_IO_addr = magic_gadget = libc_base + libc.sym["svcudp_reply"] + 0x1a
leave_ret = libc_base + 0x0000000000052d72
pop_rdi_ret = libc_base + 0x000000000002daa2
pop_rsi_ret = libc_base + 0x0000000000037c0a
pop_rdx_r12_ret = libc_base + 0x00000000001066e1
rop_address = fake_IO_addr + 0xe0 + 0xe8 + 0x70
orw_rop = b'./flag\x00\x00'
orw_rop += p64(pop_rdx_r12_ret) + p64(0) + p64(fake_IO_addr - 0x10)
orw_rop += p64(pop_rdi_ret) + p64(rop_address)
orw_rop += p64(pop_rsi_ret) + p64(0)
orw_rop += p64(libc_base + libc.sym['open'])
orw_rop += p64(pop_rdi_ret) + p64(3)
orw_rop += p64(pop_rsi_ret) + p64(rop_address + 0x100)
orw_rop += p64(pop_rdx_r12_ret) + p64(0x50) + p64(0)
orw_rop += p64(libc_base + libc.sym['read'])
orw_rop += p64(pop_rdi_ret) + p64(1)
orw_rop += p64(pop_rsi_ret) + p64(rop_address + 0x100)
orw_rop += p64(pop_rdx_r12_ret) + p64(0x50) + p64(0)
orw_rop += p64(libc_base + libc.sym['write'])
payload = p64(0) + p64(leave_ret) + p64(1) + p64(2)
payload = payload.ljust(0x38, b'\x00') + p64(rop_address)
payload = payload.ljust(0x90, b'\x00') + p64(fake_IO_addr + 0xe0)
payload = payload.ljust(0xc8, b'\x00') + p64(libc_base + libc.sym['_IO_wfile_jumps'])
payload = payload.ljust(0xd0 + 0xe0, b'\x00') + p64(fake_IO_addr + 0xe0 + 0xe8)
payload = payload.ljust(0xd0 + 0xe8 + 0x68, b'\x00') + p64(magic_gadget)
payload = payload + orw_rop
- 爆破模板:
while True:
try:
p=process(file)
exp()
break
except:
p.close()
continue
- 一字节覆盖泄露libc:
add(0x40, p64(0xfbad1887)+p64(0)*3+b'\x00')
7. 总结
-
利用选择:
- libc2.31以下: 优先打tcache和hook
- libc2.34以下: 可用house of kiwi/emma
- libc2.35+: 用house of apple2/cat
-
关键思路:
- 无UAF时考虑off-by-one构造overlapping
- 无edit功能时通过overlapping实现等效功能
- 限制多时考虑tcache_perthread_struct攻击
- 根据保护机制选择合适利用技术
-
发展趋势:
- 从hook转向IO_FILE利用
- 从直接控制执行流转向SROP/ORW
- 适应glibc新增保护机制