多手法联合IO利用之House of pig 学习利用
字数 1991 2025-08-23 18:31:08
House of Pig 利用技术详解
1. 简介
House of pig 是一种在 libc 2.31 环境下结合多种堆利用技术的攻击方法,主要适用于程序中仅有 calloc 函数而没有 malloc 函数的情况。它通过以下技术组合实现利用:
- large bin attack
- IO_FILE 结构体利用
- tcache stashing unlink attack
2. 前置知识
2.1 Large Bin Attack
2.1.1 攻击效果
- libc 2.23:可以向任意两个地址分别写入一个堆地址
- libc 2.31:只能向一个任意地址写入堆地址(由于新增安全检查)
2.1.2 利用原理
在 libc 2.31 中,当较大的 chunk 进入 large bin 时会有额外的检查:
if (__glibc_unlikely(fwd->bk_nextsize->fd_nextsize != fwd))
malloc_printerr("malloc(): largebin double linked list corrupted (nextsize)");
if (bck->fd != fwd)
malloc_printerr("malloc(): largebin double linked list corrupted (bk)");
因此只能通过向 large bin 中链入较小的 chunk,同时修改原有的 size 比较大的 chunk 的 bk_nextsize 指针来实现攻击。
2.1.3 利用步骤
- 准备两个大小不同的 large bin chunk
- 将 size 较小的 chunk 放入 large bin 中
- 将 size 较大的 chunk 放在 unsorted bin 中
- 修改 size 较小的 chunk 的 bk_nextsize 指针为目标地址-0x20
- 将 size 较大的 chunk 链入 large bin 中
2.2 Tcache Stashing Unlink Attack
2.2.1 漏洞来源
small bin 处理代码中的检查不充分:
bck = victim->bk;
if (__glibc_unlikely(bck->fd != victim))
malloc_printerr("malloc(): smallbin double linked list corrupted");
2.2.2 利用条件
- 能控制 Small Bin Chunk 的 bk 指针
- 程序可以越过 Tcache 取 Chunk(使用 calloc 即可)
- 程序至少可以分配两种不同大小且大小为 unsorted bin 的 Chunk
2.2.3 利用步骤
- 在 tcache 中放入 5 个 chunk(预留两个空位)
- 在 small bin 中放入两个大小相同的 chunk
- 修改 small bin 中 chunk 的 bk 指针为 fake chunk 地址
- 使用 calloc 触发攻击,将 fake chunk 链入 tcache
2.3 calloc 函数特性
calloc 函数不会从 Tcache 拿 Chunk,因此可以绕过"不能越过 Tcache 从 SmallBin 中取出 Chunk"的限制。
3. House of Pig 利用流程
3.1 整体思路
- 利用 UAF 等漏洞泄露 libc 和 heap 基地址
- 进行 tcache bin 布置,在 tcache 中放入 5 个 chunk
- 在 small bin 中放入两个大小相同的 chunk
- 进行第一次 large bin attack,将堆地址写入
__free_hook-0x8 - 利用 tcache stashing unlink attack,构造 fake chunk 链入 tcache
- 进行第二次 large bin attack,将堆地址写入
_IO_list_all - 劫持 IO_FILE 结构体,将 vtable 由
_IO_file_jumps修改为_IO_str_jumps
3.2 IO_FILE 结构体劫持
3.2.1 关键函数分析
将 vtable 改为 _IO_str_jumps 后,程序会调用 _IO_str_overflow 而非 _IO_file_overflow。
_IO_str_overflow 函数会:
- 计算缓冲区长度
len = _IO_buf_end - _IO_buf_base - 使用 malloc 申请
len*2 + 100大小的空间 - 调用 memcpy 将 old_buf 内容复制到 new_buf
- 调用 free(old_buf)
3.2.2 构造思路
- 计算好 len 使 malloc 分配到 tcache 中伪造的 fake chunk
- 让 old_buf 指向写有 system 函数地址的空间
- 通过 memcpy 将 system 地址复制到
__free_hook - 让 old_buf 开头写有 "/bin/sh"
3.3 伪造 IO_FILE 结构体模板
fake_IO_FILE = 2 * p64(0)
fake_IO_FILE += p64(1) # _IO_write_base = 1
fake_IO_FILE += p64(0xffffffffffff) # _IO_write_ptr = 0xffffffffffff
fake_IO_FILE += p64(0)
fake_IO_FILE += p64(heap_base + 0x148a0) # v4
fake_IO_FILE += p64(heap_base + 0x148b8) # v5
fake_IO_FILE = fake_IO_FILE.ljust(0xb0, '\x00')
fake_IO_FILE += p64(0) # _mode = 0
fake_IO_FILE = fake_IO_FILE.ljust(0xc8, '\x00')
fake_IO_FILE += p64(IO_str_vtable) # vtable
payload = fake_IO_FILE + '/bin/sh\x00' + 2 * p64(system_addr)
4. 防御措施
- 及时更新 glibc 版本
- 检查堆操作中的边界和指针有效性
- 对用户输入进行严格验证
- 使用安全的内存分配器
5. 总结
House of pig 技术展示了如何在高版本 glibc 下通过组合多种利用技术绕过安全机制。它代表了现代堆利用的发展方向 - 不再是单一技术的应用,而是多种技术的组合利用。理解这些技术需要扎实的堆管理知识和丰富的调试经验。