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-oneoff-by-null 漏洞修改下一个 chunk 的元数据,最终实现任意地址写。

1.1 核心思想

  • 通过修改下一个 chunk 的 prev_sizePREV_INUSE 位,欺骗 Glibc 的堆管理器,使其错误地合并一个伪造的 chunk。
  • 利用合并操作造成堆块重叠,从而进一步控制堆布局,实现任意地址分配。

2. 攻击条件

要成功利用 House of Einherjar,需满足以下条件:

  1. 存在堆溢出漏洞:能够修改下一个 chunk 的 prev_size 字段和 PREV_INUSE 位(例如通过 off-by-one 或 off-by-null)。
  2. 能够分配大于等于 unsorted bin 大小的 chunk(通常 ≥ 0x80)。
  3. 能够控制伪造 chunk 的内容:确保伪造 chunk 的 fdbk 指针指向自身,以通过 unlink 校验。

3. 攻击过程详解

3.1 初始堆布局

假设存在三个 chunk:

  • chunk1:可控,用于伪造 fake chunk。
  • chunk2:用于溢出修改 chunk3 的元数据。
  • chunk3:目标 chunk,将被释放以触发合并。

3.2 步骤分解

  1. 伪造 Fake Chunk

    • 在 chunk1 中构造一个伪造的 chunk,其 fdbk 均指向自身(绕过 unlink 检查)。
    • 计算 fake chunk 与 chunk3 的偏移,并将该值写入 chunk3 的 prev_size(通过 chunk2 的溢出实现)。
  2. 修改元数据

    • 通过溢出将 chunk3 的 PREV_INUSE 位清零(标记前一个 chunk 为空闲)。
    • 确保 chunk3 的 prev_size 指向伪造的 fake chunk。
  3. 触发合并

    • 释放 chunk3,进入 _int_free() 流程。
    • Glibc 检查到 PREV_INUSE 为 0,根据 prev_size 找到伪造的 fake chunk。
    • 执行向后合并操作,将 fake chunk 和 chunk3 合并为一个大的空闲 chunk。
  4. 堆块重叠

    • 合并后的 chunk 包含 fake chunk 和 chunk3,造成堆块重叠。
    • 此时分配新 chunk 可能返回伪造的地址。
  5. 进一步利用

    • 通过分配操作控制伪造地址的内存,实现任意地址读/写。
    • 常见目标:修改 __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_chunk
  • bk = &fake_chunk

5. 实战案例:湾区杯2025 digital_bomb

5.1 题目分析

  • 程序模拟“猜数字”游戏,通过特定输入可进入堆功能菜单。
  • 堆菜单提供 addeditfreeshow 功能。
  • add 函数存在 off-by-null 漏洞(输入数据后追加 \x00 截断)。

5.2 漏洞利用步骤

  1. 绕过炸弹

    • 输入范围 499-500,炸弹数为 499
    • 输入 500 更新边界为 499-499,绕过炸弹检测。
  2. 泄露堆地址

    • 利用 large bin 和 edit 函数泄露 heap 地址。
  3. 触发 House of Einherjar

    • 利用 off-by-null 修改下一个 chunk 的 PREV_INUSE 位。
    • 伪造 fake chunk,构造 prev_size 触发合并。
  4. 泄露 libc 地址

    • 通过堆块重叠泄露 libc 地址。
  5. 获取 shell

    • 修改 strlen 的 GOT 表为 one_gadget

5.3 EXP 关键点

  • 伪造 fake chunk 并计算正确偏移。
  • 通过 showedit 函数泄露地址。
  • 利用合并后的重叠 chunk 修改 fd 指针,实现任意地址分配。

6. 防御与缓解

  1. 及时更新 Glibc:新版本 Glibc 增加了更多完整性检查。
  2. 静态分析:检测 off-by-one 等溢出漏洞。
  3. 堆布局随机化:使用 ASLR 增加预测难度。
  4. 使用安全机制:如 FORTIFY_SOURCE、堆保护机制(如 GLIBC_PTRACE_MACROS)。

7. 总结

House of Einherjar 是一种利用堆合并机制的先进利用技术,其核心在于:

  • 通过溢出修改元数据,欺骗 Glibc 合并伪造 chunk。
  • 通过精心构造的 fake chunk 绕过 unlink 检查。
  • 结合其他漏洞(如信息泄露)实现完整利用。

掌握此技术需深入理解 Glibc 堆管理机制,建议通过实验环境(如 Ubuntu 18.04 + Glibc-2.27)反复调试以加深理解。

附件:digtal_bomb.zip(需下载练习)

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 的溢出实现)。 修改元数据 : 通过溢出将 chunk3 的 PREV_INUSE 位清零(标记前一个 chunk 为空闲)。 确保 chunk3 的 prev_size 指向伪造的 fake chunk。 触发合并 : 释放 chunk3,进入 _int_free() 流程。 Glibc 检查到 PREV_INUSE 为 0,根据 prev_size 找到伪造的 fake chunk。 执行向后合并操作,将 fake chunk 和 chunk3 合并为一个大的空闲 chunk。 堆块重叠 : 合并后的 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() 中,需满足: 因此,伪造的 fake chunk 必须满足: fd = &fake_chunk bk = &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 地址。 触发 House of Einherjar : 利用 off-by-null 修改下一个 chunk 的 PREV_INUSE 位。 伪造 fake chunk,构造 prev_size 触发合并。 泄露 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(需下载练习)