House of Einherjar堆利用技术解析与实战
字数 2718 2025-09-23 19:27:46
House of Einherjar 堆利用技术解析与实战
1. 技术概述
House of Einherjar 是一种由 Hiroki Matsukuma 提出的堆利用技术,其核心在于滥用 free() 函数中的后向合并操作(合并低地址的 chunk),从而使得 malloc() 返回一个几乎任意地址的 chunk。该技术的关键在于利用 off-by-one 或 off-by-null 漏洞修改下一个 chunk 的元数据,最终实现任意地址写。
1.1 核心思想
- 通过修改下一个 chunk 的
prev_size和PREV_INUSE位,欺骗 Glibc 的堆管理器,使其错误地合并一个伪造的 chunk。 - 利用合并操作造成堆块重叠,从而进一步控制堆布局,实现任意地址分配。
2. 攻击条件
要成功利用 House of Einherjar,需满足以下条件:
- 存在堆溢出漏洞:能够修改下一个 chunk 的
prev_size字段和PREV_INUSE位(例如通过 off-by-one 或 off-by-null)。 - 能够分配大于等于 unsorted bin 大小的 chunk(通常 ≥ 0x80)。
- 能够控制伪造 chunk 的内容:确保伪造 chunk 的
fd和bk指针指向自身,以通过 unlink 校验。
3. 攻击过程详解
3.1 初始堆布局
假设存在三个 chunk:
- chunk1:可控,用于伪造 fake chunk。
- chunk2:用于溢出修改 chunk3 的元数据。
- chunk3:目标 chunk,将被释放以触发合并。
3.2 步骤分解
-
伪造 Fake Chunk:
- 在 chunk1 中构造一个伪造的 chunk,其
fd和bk均指向自身(绕过 unlink 检查)。 - 计算 fake chunk 与 chunk3 的偏移,并将该值写入 chunk3 的
prev_size(通过 chunk2 的溢出实现)。
- 在 chunk1 中构造一个伪造的 chunk,其
-
修改元数据:
- 通过溢出将 chunk3 的
PREV_INUSE位清零(标记前一个 chunk 为空闲)。 - 确保 chunk3 的
prev_size指向伪造的 fake chunk。
- 通过溢出将 chunk3 的
-
触发合并:
- 释放 chunk3,进入
_int_free()流程。 - Glibc 检查到
PREV_INUSE为 0,根据prev_size找到伪造的 fake chunk。 - 执行向后合并操作,将 fake chunk 和 chunk3 合并为一个大的空闲 chunk。
- 释放 chunk3,进入
-
堆块重叠:
- 合并后的 chunk 包含 fake chunk 和 chunk3,造成堆块重叠。
- 此时分配新 chunk 可能返回伪造的地址。
-
进一步利用:
- 通过分配操作控制伪造地址的内存,实现任意地址读/写。
- 常见目标:修改
__malloc_hook、__free_hook或 GOT 表,获取 shell。
4. 攻击原理与源码分析
4.1 free() 合法性校验
在 _int_free() 中,释放 chunk 时会进行以下检查:
- 检查 chunk 大小是否合法(对齐、最小/最大大小)。
- 检查是否属于 tcache、fastbin 或 unsorted bin 范围。
- 若进入 unsorted bin 分支,会检查前后 chunk 的合并条件。
4.2 向前合并校验
- 若当前 chunk 的
PREV_INUSE为 0,则根据prev_size找到前一个 chunk。 - 检查前一个 chunk 的
size是否与prev_size一致。 - 调用
unlink_chunk()将前一个 chunk 从链表中摘下,并合并。
4.3 向后合并校验
- 若下一个 chunk 不是 top chunk 且未被使用,则合并当前 chunk 和下一个 chunk。
4.4 unlink 校验绕过
在 unlink_chunk() 中,需满足:
FD->bk == P && BK->fd == P
因此,伪造的 fake chunk 必须满足:
fd = &fake_chunkbk = &fake_chunk
5. 实战案例:湾区杯2025 digital_bomb
5.1 题目分析
- 程序模拟“猜数字”游戏,通过特定输入可进入堆功能菜单。
- 堆菜单提供
add、edit、free、show功能。 add函数存在 off-by-null 漏洞(输入数据后追加\x00截断)。
5.2 漏洞利用步骤
-
绕过炸弹:
- 输入范围
499-500,炸弹数为499。 - 输入
500更新边界为499-499,绕过炸弹检测。
- 输入范围
-
泄露堆地址:
- 利用 large bin 和
edit函数泄露 heap 地址。
- 利用 large bin 和
-
触发 House of Einherjar:
- 利用 off-by-null 修改下一个 chunk 的
PREV_INUSE位。 - 伪造 fake chunk,构造
prev_size触发合并。
- 利用 off-by-null 修改下一个 chunk 的
-
泄露 libc 地址:
- 通过堆块重叠泄露 libc 地址。
-
获取 shell:
- 修改
strlen的 GOT 表为one_gadget。
- 修改
5.3 EXP 关键点
- 伪造 fake chunk 并计算正确偏移。
- 通过
show和edit函数泄露地址。 - 利用合并后的重叠 chunk 修改
fd指针,实现任意地址分配。
6. 防御与缓解
- 及时更新 Glibc:新版本 Glibc 增加了更多完整性检查。
- 静态分析:检测 off-by-one 等溢出漏洞。
- 堆布局随机化:使用 ASLR 增加预测难度。
- 使用安全机制:如
FORTIFY_SOURCE、堆保护机制(如GLIBC_PTRACE_MACROS)。
7. 总结
House of Einherjar 是一种利用堆合并机制的先进利用技术,其核心在于:
- 通过溢出修改元数据,欺骗 Glibc 合并伪造 chunk。
- 通过精心构造的 fake chunk 绕过 unlink 检查。
- 结合其他漏洞(如信息泄露)实现完整利用。
掌握此技术需深入理解 Glibc 堆管理机制,建议通过实验环境(如 Ubuntu 18.04 + Glibc-2.27)反复调试以加深理解。
附件:digtal_bomb.zip(需下载练习)