【学习记录】Week11(三):House of Botcake 与 House of Pig——现代 CTF 堆利用的双子星

写在前面:在 Week11 的前两篇中,我们复盘了传统的 House of 系列(Spirit, Force, Lore, Einherjar, Rabbit, Orange)。随着 glibc 版本的迭代,传统的技术或被修补,或难以适配现代环境。今天,我们正式进入现代 CTF 高频考点的硬核环节。根据最新的 Week11 规划,本篇将用最高优先级、最大的篇幅,深度剖析House of BotcakeHouse of Pig这两项在现代堆漏洞利用中出场率极高的技术。

📑 目录

  1. 现代堆利用背景:为什么是 Botcake 和 Pig?
  2. House of Botcake:glibc 2.29+ 的重叠制造机
  3. House of Pig:Tcache 与 FSOP 的终极复合利用
  4. 综合实战思维:从 UAF 到 Shell 的现代路径
  5. 总结与下篇预告

1. 现代堆利用背景:为什么是 Botcake 和 Pig?

在 glibc 2.29 引入 Tcache Key 遏制了简单的 Double Free,并在后续版本中加强了prev_size一致性检查与 Safe-Linking 机制后,传统的利用链遭遇了毁灭性打击。现代 CTF PWN 题(特别是 glibc 2.31~2.35 环境)的解题思路发生了根本性转变:

  1. 如何制造堆重叠?->House of Botcake成为了绝对的主流答案。它巧妙地利用了 Tcache 和 Unsorted Bin 的释放顺序差异,在不破坏任何元数据校验的前提下,完美制造堆块重叠。
  2. 如何劫持控制流?-> 纯堆上的 Hook(如__free_hook)在 glibc 2.34 中被彻底移除。于是,攻击重心转移到了IO_FILE (FSOP)House of Pig作为 Tcache 与 FSOP 的集大成者,成为了获取 Shell 的王牌技术。

2. House of Botcake:glibc 2.29+ 的重叠制造机

2.1 核心思想

House of Botcake 的目标是让同一个 chunk 同时存在于 Tcache 和 Unsorted Bin 中。一旦达成这个目标,我们就可以通过 Unsorted Bin 中的指针泄露 Libc 地址,同时通过 Tcache 修改该 chunk 的next指针,实现 Tcache Poisoning。

2.2 利用条件

  1. 存在 UAF 漏洞,或者能够对已释放的 chunk 进行读写。
  2. 能够控制 chunk 的分配和释放顺序。
  3. Tcache 未满(通常需要 7 个 chunk 来填满一个 Tcache bin)。

2.3 详细利用步骤

假设我们要利用大小为0x100的 chunk。

阶段一:填满 Tcache 并释放进 Unsorted Bin

  1. 分配 9 个大小为0x100的 chunk:A, B, C, D, E, F, G, H, II用于防止与 Top Chunk 合并)。
  2. 依次释放AG填满 Tcache[0x100]
  3. 释放H。因为 Tcache 已满,H进入Unsorted Bin。此时Hfdbk指向main_arena

阶段二:制造双重存在
4. 分配一个 chunk(或调用malloc7 次),清空 Tcache[0x100]
5. 再次释放G。此时 Tcache[0x100] 为空,G进入Tcache
6.关键步骤:再次释放H。此时 Tcache[0x100] 已经有一个G,且未满。H会进入Tcache
* *等等,glibc 2.29 不是有 Key 检查吗?*
*这就是 Botcake 的精妙之处H之前是在 Unsorted Bin 中的,它的内存区域并没有被写入 Tcache Key(Key 是在进入 Tcache 时写入的)。当我们再次free(H)时,glibc 检查H->key,发现它不等于 Tcache 结构体地址,因此绕过了 Double Free 检查
* 此时,H既在 Tcache 链表中(Tcache -> H -> G),又在 Unsorted Bin 中(H仍然与前面的 chunk 连在一起,或者就是独立在 Unsorted Bin)。

阶段三:泄露与投毒
7.泄露 Libc:利用 UAF 读取Hfd指针(此时在 Unsorted Bin 状态下指向main_arena),计算出 Libc 基址。
8.Tcache Poisoning:利用 UAF 修改H在 Tcache 中的next指针,将其指向目标地址(如__free_hook或栈上的返回地址)。
9. 连续malloc两次:第一次返回H,第二次返回目标地址,实现任意地址写。

1. 填满 Tcache, 释放 H 进 Unsorted Bin

2. 清空 Tcache

3. 释放 G 进 Tcache

4. 再次释放 H
由于 H 无 Key, 绕过 Double Free 检查
H 进入 Tcache

5. 此时 H 同时在 Tcache 和 Unsorted Bin

6. UAF 读取 H 的 fd 泄露 Libc

7. UAF 修改 H 的 Tcache next 指针

8. 连续 Malloc 两次, 获取目标地址控制权

3. House of Pig:Tcache 与 FSOP 的终极复合利用

3.1 核心思想

House of Pig 是针对 glibc 2.34+ 移除 Hook 函数后的利用难题而设计的。它结合了Tcache PoisoningIO_FILE (FSOP)技术。
其核心在于:利用 Tcache Poisoning 劫持分配流,将一个伪造的IO_FILE_plus结构体分配到_IO_list_all附近或可控内存中,然后通过触发exit()malloc_printerr,执行 IO 流刷新操作,最终调用伪造的 IO 虚表(通常是_IO_str_jumps_IO_wstrn_jumps)中的函数,实现控制流劫持(如system("/bin/sh")或栈迁移 ROP)。

3.2 利用条件

  1. 拥有 Tcache Poisoning 能力(通常通过 House of Botcake 或 UAF 实现)。
  2. 能够泄露 Libc 地址和堆地址(用于伪造 IO 结构和计算 Tcache 异或密钥)。
  3. 程序存在正常的退出路径(exitreturn)或能触发堆错误。

3.3 详细利用步骤

阶段一:前置原语准备
通过 House of Botcake 或其他手段,实现:

  1. 泄露 Libc 基址。
  2. 泄露堆地址(用于绕过 glibc 2.32+ 的 Safe-Linking)。
  3. 拥有 Tcache Poisoning 能力,可以申请任意地址。

阶段二:伪造 IO_FILE 结构
在堆上布置一个伪造的IO_FILE_plus结构体。关键字段设置如下:

  • _flags: 设置为0或特定值以绕过检查。
  • _IO_read_ptr,_IO_read_end等:通常置零。
  • _IO_write_base: 设置为0
  • _IO_write_ptr: 设置为1(使得_IO_write_ptr > _IO_write_base,触发overflow逻辑)。
  • _chain: 指向下一个 IO 结构(如果是单结构可置零)。
  • vtable: 指向_IO_str_jumps_IO_wstrn_jumps(合法 vtable,绕过 vtable 范围检查)。
  • 关键利用点:在_IO_str_overflow函数中,存在如下逻辑:
// 伪代码 new_buf = malloc(new_size); memcpy(new_buf, old_buf, old_len); free(old_buf);

我们可以通过控制_IO_buf_base(old_buf) 和_IO_buf_end来控制new_sizeold_buf

阶段三:劫持 _IO_list_all 与触发

  1. 利用 Tcache Poisoning,将malloc的目标指向_IO_list_all(或利用 Largebin Attack 等将伪造的堆块地址写入_IO_list_all)。
  2. 修改_IO_list_all的值,使其指向我们在堆上伪造的IO_FILE_plus结构体。
  3. 触发 FSOP:调用exit()exit会调用_IO_flush_all_lockp,遍历_IO_list_all链表,对每个 FILE 结构调用overflow
  4. 由于我们伪造的vtable_IO_str_jumps,最终会调用_IO_str_overflow
  5. _IO_str_overflow内部,会执行mallocfree。此时,我们已经控制了 Tcache,可以让这里的malloc返回栈地址,然后通过memcpy将 ROP 链写入栈上,或者直接利用system("/bin/sh")完成利用。

House of Pig 的变体:在最新的 CTF 中,由于_IO_str_overflow的检查也变严,衍生出了利用_IO_wfile_overflowHouse of Apple系列和利用_IO_obstack_jumps的技术,但其核心架构(Tcache 劫持 + 伪造 IO 结构 + 触发刷新)依然是 House of Pig 奠定的。

4. 综合实战思维:从 UAF 到 Shell 的现代路径

在现代 CTF 中,一道题往往是多种技术的组合。以下是一个典型的现代堆题解题思维流:

漏洞点: UAF / Off-by-one

利用 House of Botcake
制造堆重叠

信息泄露
Libc Base & Heap Base

绕过 Safe-Linking
构造 Tcache Poisoning

控制流劫持
由于无 Hook, 转向 IO_FILE

利用 House of Pig
伪造 IO_FILE + 劫持 _IO_list_all

触发 exit/abort
执行伪造虚表

Getshell / ROP

这个流程图完美概括了目前 2.31~2.35 版本 glibc 堆题的通用解法。Botcake 负责“破局”制造原语,Pig(或 Apple)负责“收网”拿下控制流。

5. 总结与下篇预告

5.1 核心知识点总结

  1. House of Botcake:利用 Unsorted Bin 中的 chunk 没有 Tcache Key 的特性,二次释放使其同时存在于 Tcache 和 Unsorted Bin,完美绕过 glibc 2.29 的 Double Free 检查,是制造堆重叠的首选。
  2. House of Pig:在 glibc 移除 Hook 的背景下,将 Tcache Poisoning 与 FSOP 结合。通过伪造IO_FILE结构和合法 vtable,利用exit触发 IO 流刷新,在_IO_str_overflow等函数中劫持执行流。
  3. 技术组合:现代堆题不再是单一技术的单打独斗,而是“堆管理机制破坏 (Botcake) -> 信息泄露 -> 数据结构伪造 (Pig/IO_FILE)”的复合攻击。

5.2 下篇预告

在下一篇 Week11(四)中,我们将继续探索现代 House 系列的其他重要成员:

  • House of Apple:针对_IO_wfile_overflow的新一代 FSOP 技术。
  • House of Tangerine:2023 年高频出现的利用手法。
  • House of Corrosion:利用global_max_fast扩展 Fastbin 范围的强力攻击。
  • 综合练习:UAF + tcache poisoning 实战分析

最终结论:House of Botcake 和 House of Pig 是现代 CTF 选手必须熟练掌握的“左右互搏”术。前者是矛,撕开现代 glibc 的严密防线获取原语;后者是盾,在失去传统劫持点后提供可靠的控制流接管方案。掌握它们,你就掌握了现代堆利用的命脉。