2025古剑山第二题 || orange和largebin的两种打法
字数 2793 2025-12-16 12:34:08
House of Orange 与 Largebin Attack 利用技术详解
一、House of Orange 技术概述
1.1 核心原理
House of Orange 的核心思想是通过特殊的内存操作将 top chunk 释放到堆区中,从而为进一步的利用创造条件。该技术主要包含三个关键步骤:
- 将 top chunk 释放到 unsorted bin
- 进行 unsorted bin attack
- 结合 FSOP(File Stream Oriented Programming)实现代码执行
1.2 技术组合
- Unsorted Bin Attack:用于修改关键内存值
- FSOP:通过伪造 IO_FILE 结构体控制程序执行流
- 组合效果:单独使用效果有限,但组合使用威力显著
二、题目环境分析
2.1 程序基本信息
- 二进制菜单程序,运行在 GLIBC 2.23 环境
- 关键代码特征:
mallopt(1, 0); // 禁用 fastbin
- 功能选项:添加、删除、编辑、显示
2.2 保护机制
- 地址随机化(ASLR)启用
- 需要绕过保护获取 shell
三、House of Orange 详细实现
3.1 Top Chunk 释放条件
从 GLIBC 源码分析,释放 top chunk 需要满足以下条件:
old_top = av->top;
old_size = chunksize(old_top);
old_end = (char *)(chunk_at_offset(old_top, old_size));
assert((old_top == initial_top(av) && old_size == 0) ||
((unsigned long)(old_size) >= MINSIZE &&
prev_inuse(old_top) &&
((unsigned long)old_end & (pagesize - 1)) == 0));
assert((unsigned long)(old_size) < (unsigned long)(nb + MINSIZE));
关键条件说明:
| 条件 | 代码体现 | 目的 |
|---|---|---|
| old_size ≥ MINSIZE | (old_size) >= MINSIZE |
确保 old top 是合法 chunk |
| prev_inuse 为 1 | prev_inuse(old_top) |
防止 metadata 损坏 |
| old_end 页对齐 | (old_end & (pagesize-1)) == 0 |
保证堆边界对齐 |
| old_size < nb + MINSIZE | old_size < nb + MINSIZE |
确认需要 sysmalloc |
重点注意事项:
- 第三条条件最为关键:
address & 0xfff = 0x000 - 需要精确控制堆布局满足对齐要求
3.2 Unsorted Bin Attack 原理
3.2.1 基本机制
- Unsorted bin 采用头插法管理 chunk
- 取出 chunk 时从链表尾部开始(相对于指针链的尾端)
- 攻击利用
victim->bk->fd = unsorted_chunks(av)实现任意地址写
3.2.2 利用要点
// 关键代码路径
bck = victim->bk;
unsorted_chunks(av)->bk = bck;
bck->fd = unsorted_chunks(av);
通过控制 victim->bk,可以实现向任意地址写入 main_arena 地址。
3.3 FSOP(File Stream Oriented Programming)
3.3.1 IO_FILE 结构体链
- FILE 结构通过 chain 域形成链表,头部为全局变量
IO_list_all _IO_FILE_plus包含 vtable 指针,指向函数跳转表- 文件操作函数最终调用 vtable 中的函数指针
3.3.2 IO_jump_t 结构体
struct _IO_jump_t {
JUMP_FIELD(size_t, __dummy);
JUMP_FIELD(size_t, __dummy2);
JUMP_FIELD(_IO_finish_t, __finish);
JUMP_FIELD(_IO_overflow_t, __overflow);
// ... 其他函数指针
};
3.3.3 触发条件
需要满足以下条件之一来触发 _IO_OVERFLOW:
if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base) ||
(_IO_vtable_offset(fp) == 0 && fp->_mode > 0 &&
(fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base))) &&
_IO_OVERFLOW(fp, EOF) == EOF)
result = EOF;
伪造字段设置:
mode = 0_IO_write_ptr = 1_IO_write_base = 0- 满足
_IO_write_ptr > _IO_write_base即可触发
3.3.4 成功概率分析
- 第一个结构体的 mode 字段由
main_arena+88+0xc0处数据决定 - 由于 ASLR,该值可能为正或负(补码表示)
- 值大于
0x7fffffff为负,小于则为正 - 正负概率各为 1/2,因此成功概率为 50%
3.4 函数调用链
__libc_malloc
→ malloc_printerr
→ libc_message
→ abort
→ _IO_flush_all_lockp
四、调试技巧
4.1 环境配置
# 关闭地址随机化
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
# 使用 Ubuntu 16 进行调试(兼容性更好)
# Ubuntu 22 可能存在调试符号问题
4.2 GDB 调试命令
def duan(*address):
pay = ''
if pie:
for i in address:
pay += 'b *$rebase(' + str(i) + ')\n'
else:
for i in address:
pay += 'b *' + str(i) + '\n'
gdb.attach(io, pay)
五、两种攻击打法详解
5.1 House of Orange 打法(exp1)
5.1.1 攻击步骤
- 信息泄露:使用 largebin 泄露 libc 和堆地址
- 堆块伪造:构造合法的 0x60 大小堆块链
- 释放操作:先修改大小再释放(避免额外检查)
- Unsorted Bin Attack:实施攻击并将 0x60 堆块放入 smallbin
- FSOP 触发:通过虚表跳转执行 system
5.1.2 关键技术点
- 虚表位置偏移 0x18 调用 system 函数
- 需要精确计算 libc 基地址和堆地址
- 注意避免 \x00 截断问题
5.2 Largebin Attack 打法(exp2)
5.2.1 高低版本差异
- 高版本:小的 chunk 插入 largebin
- 低版本:大的 chunk 插入 largebin
- 链式处理逻辑不同,需要针对性利用
5.2.2 堆布局策略
- 使用大小组合:0x400 + 0x3f0 或 0x400 + 0x400
- 添加 0x3e0 大小的"冤种"chunk
- 利用 unsorted bin 的切割机制:优先从最符合大小的 chunk 切割
5.2.3 利用机制
# 示例利用代码
edit(3, 'a'*0x80 + '/bin/sh') # 准备命令字符串
heap_addr = heap_base + 0x910
# 伪造 IO_FILE 结构
fake = p64(0) + p64(io_list_all-0x10)
fake += p64(0) + p64(1)
fake = fake.ljust(0xd8-0x10, b"\x00")
fake += p64(heap_addr+0xd8+8)
fake += p64(0)*3 + p64(libc.sym['system'])
edit(4, fake)
5.2.4 内存分配机制
- unsorted bin 处理采用小循环而非大循环
- 先放入对应 bins 再进行切割
- 利用此机制将特定 chunk 分配至 largebin
六、关键技术问题分析
6.1 malloc_assert 触发条件
6.1.1 为什么 Unsorted Bin Attack 不会触发 malloc_printerr?
当进行 unsorted bin attack 时:
- 申请的 chunk 大小在 unsorted bin 中能被满足
- unsorted bin 直接返回 chunk,不检查伪造的 bk 指针指向的 fake chunk
- 因此不会触发 size 检查错误
6.1.2 触发 malloc_printerr 的场景
当 unsorted bin 中没有合适 chunk 时,会遍历检查每个 chunk:
for(;;) {
int iters = 0;
while((victim = unsorted_chunks(av)->bk) != unsorted_chunks(av)) {
bck = victim->bk;
if (__builtin_expect(victim->size <= 2 * SIZE_SZ, 0) ||
__builtin_expect(victim->size > av->system_mem, 0)) {
malloc_printerr(check_action, "malloc(): memory corruption",
chunk2mem(victim), av);
}
size = chunksize(victim);
}
}
如果伪造的 chunk size 为 0(满足 size <= 2 * SIZE_SZ),就会触发错误。
七、防御建议
7.1 开发层面
- 对堆块大小进行严格验证
- 实现堆内存隔离机制
- 使用现代堆保护技术
7.2 系统层面
- 保持 GLIBC 版本更新
- 启用完整的 ASLR 保护
- 使用堆栈保护机制
八、总结
House of Orange 和 Largebin Attack 是 GLIBC 2.23 环境下重要的堆利用技术,通过结合 unsorted bin attack 和 FSOP,能够实现从内存泄露到代码执行的完整攻击链。理解这些技术的原理和实现细节对于二进制安全研究和漏洞防护具有重要意义。