House Of Cat
House Of Cat 利用背景:
House of Cat 被广泛使用,主要是因为它可以解决传统 FSOP 在某些苛刻题目环境下面临的限制:
1. 应对极端的长度限制与堆块大小限制 House of Apple 2 虽然强大,但通常需要走 _IO_wfile_overflow 或 underflow 逻辑,这要求攻击者在堆上伪造相对完整的 _IO_FILE 结构体以及它所指向的 _wide_data 结构体(通常需要连续控制 0xe0 字节以上的内存)。而 House of Cat 将执行流劫持的目标转移到了 _IO_switch_to_wget_mode 函数(通过 _IO_wfile_seekoff 触发)。由于该函数内部对 _wide_data 的校验逻辑极为宽松,攻击者完全不需要伪造一整个完整的 _wide_data** 结构体**。在写入长度受限时,只需让 _wide_data 指针指向一个可控且带有特定残余数据的堆地址,即可绕过检查。
2. 与 Largebin Attack 的完美协同 在现代高难度 PWN 题中,漏洞往往只能提供单次地址的任意写(例如利用 Largebin Attack 将一个堆地址写入目标内存)。 House of Cat 的核心思路就是利用 Largebin Attack 的这一特性,直接将 stderr 等文件流结构体中的 _wide_data 指针([rdi+0xa0])覆盖为受控的堆块地址。因为 _IO_switch_to_wget_mode 内部只需要满足 _wide_data->_IO_write_ptr > _wide_data->_IO_write_base 即可继续执行并触发虚函数调用,Largebin Attack 写入的堆指针刚好能被利用来满足这一相对大小的比较条件,从而实现执行流劫持。
3. 规避繁杂的 IO 状态校验 传统的 _IO_FILE 利用链在触发 call 之前,需要绕过 _flags、_mode 等诸多严格的流状态校验。而 House of Cat 另辟蹊径,其执行路径上的条件判断极少,大大降低了构造 Fake Chunk 的精细度要求,提高了 exploit 的稳定性和容错率。
House of cat 大致利用范围:
一般来说 house of cat 的利用范围大致为 glibc 2.34 - glibc 2.38+ 原因归根结底还是 glibc-2.34 去除 hook
House of cat 利用原理:
house of apple2 和 house of cat 利用的大致思想是一样的(都是通过 wide_data->wide_vtable 中的函数指针进行的跳转。而 house of apple2 需要利用 exit()函数在最后触发攻击,假如题目中不存在 exit 函数,那就需要通过 malloc_assert 来触发最后的攻击,而 house of cat 就是通过这样的方式触发的攻击。
触发 malloc_assert:
触发 malloc_assert 的方式和 house of kiwi 的方式相似,都是利用篡改 top_chunk 的 size 导致 sysmalloc 函数检查 top_chunk 时候发现大小不合法触发 malloc_assert 断言并终止程序。
house of kiwi:[https://www.yuque.com/idcm/wnemg9/fpphb84no4i9uyzs](https://www.yuque.com/idcm/wnemg9/fpphb84no4i9uyzs)
__malloc_assert 在 2.35 的 glibc 中源码如下:
1 | static void |
这里有这样一条执行链 __malloc_assert-> __fxprintf->__vfxprintf->locked_vfxprintf->__vfprintf_internal->_IO_file_xsputn
最后触发的 _IO_file_xsputn 是通过 vtable 中的函数指针来触发的,我们想要去劫持的话,首先将 _IO_2_1_stderr 结构体中的 vtable 改成 _IO_wfile_jumps+0x10 的地址(加 0x10 的原因是 _IO_file_xsputn 的地址在 _IO_file_jumps 中比 IO_file_seekoff 的地址低 0x10 个字节),这样原本跳转执行 _IO_file_xsputn 时,实际上执行的是 _IO_wfile_seekoff 如下图

_IO_wfile_seekoff 函数源码如下
1 | _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode) |
我们执行 _IO_wfile_seekoff 函数的目的就是为了触发 _IO_switch_to_wget_mode 函数
_IO_switch_to_wget_mode 函数源码如下
1 | _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode) |
执行 _IO_switch_to_wget_mode 函数的目的就是为了触发 _IO_WOVERFLOW ,因为这个 _IO_WOVERFLOW 函数是通过 _wide_data->_wide_vtable 中所存放的函数指针进行跳转的, _wide_vtable 是我们可控的,从而在这里可以劫持程序的执行流。
想触发最后的 _IO_WOVERFLOW ,需要满足 fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base 这个条件。
剩下的利用方法就与 house of apple 2 无异了 ^_^
参考资料:https://zikh26.github.io/posts/7de5a5b7.html
更新: 2026-04-29 09:39:59
原文: https://www.yuque.com/idcm/wnemg9/xexm1m9dqo3tgndg