IO利用之House of kiwi & House of emma
字数 2087 2025-08-23 18:31:08
House of Kiwi & House of Emma 高级堆利用技术详解
1. House of Kiwi
1.1 背景与简介
在glibc 2.29之后开启了sandbox的堆题中,传统利用方法受限:
- 劫持free_hook利用特定gadget进行栈迁移
- 劫持malloc_hook为setcontext+61并劫持IO_list_all链表调用exit
glibc 2.34后取消了关键hook,使得上述方法难以实施,House of Kiwi应运而生。
1.2 利用原理
触发IO流的三种方式中,House of Kiwi利用malloc_assert刷新IO流:
static void __malloc_assert(const char *assertion, const char *file, unsigned int line, const char *function) {
(void) __fxprintf(NULL, "%s%s%s:%u: %s%sAssertion `%s' failed.\n",
__progname, __progname[0] ? ": " : "",
file, line,
function ? function : "", function ? ": " : "",
assertion);
fflush(stderr);
abort();
}
关键点:
- 调用
fflush(stderr)后会调用_IO_file_jumps中的sync指针 _int_malloc中的assert(chunk_main_arena(bck->bk))可触发- 当top_chunk大小不足时,进入
sysmalloc中的assert判断
1.3 利用条件
- 能够触发
__malloc_assert - 能够进行任意地址写
1.4 利用步骤
-
通过largebin attack等任意地址写方法:
- 将
_IO_file_jumps + 0x60的_IO_file_sync指针改为setcontext+61的gadget - 修改
IO_helper_jumps + 0xA0为ROP位置 - 修改
IO_helper_jumps + 0xA8为ret指令gadget位置
- 将
-
触发assert:
- 修改top_chunk的size|flags使其不满足assert条件
- 触发malloc分配失败进入assert流程
1.5 示例代码分析
// 设置关键指针
*((size_t *)IO_helper + 0xA0/8) = ROP; // 设置rsp
*((size_t *)IO_helper + 0xA8/8) = ret; // 设置rcx
*((size_t *)SYNC) = magic_gadget; // 设置fflush(stderr)中调用的指令地址
// 触发assert
size_t *top_size = (size_t *)((char *)malloc(0x10) + 0x18);
*top_size = (*top_size) & 0xFFE; // top_chunk size改小并将inuse写0
malloc(0x1000); // 触发assert
2. House of Emma
2.1 背景与简介
glibc 2.34彻底删除了常用hook函数,House of Emma利用_IO_cookie_jumps作为替代调用链。
2.2 利用原理
利用_IO_cookie_file结构体中的函数指针:
struct _IO_cookie_file {
struct _IO_FILE_plus __fp;
void *__cookie;
cookie_io_functions_t __io_functions;
};
关键点:
- 函数指针使用
pointer_guard加密(循环右移0x11再异或) - 通过控制IO内容控制函数调用
2.3 利用条件
- 能够进行任意地址写
- 能够控制IO_FILE结构内容
- 能够触发IO流操作
2.4 利用步骤
-
使用largeBin Attack:
- 在
stderr指针处写入可控地址 - 在
__pointer_chk_guard处写入已知地址
- 在
-
构造加密的函数指针与合理的IO_FILE结构
-
利用Unsorted Bin与Top Chunk合并机制修改Top Chunk Size,触发malloc_assert
-
进入调用链,利用gadget转移rdi到rdx,为Setcontext提供内容
-
执行ROP链进行ORW
2.5 示例分析
# 构造fake IO_FILE
fake_IO_FILE = 2 * p64(0)
fake_IO_FILE += p64(0) # _IO_write_base = 0
fake_IO_FILE += p64(0xffffffffffffffff) # _IO_write_ptr
fake_IO_FILE = fake_IO_FILE.ljust(0xC8, '\x00')
fake_IO_FILE += p64(libc.sym['_IO_cookie_jumps'] + 0x40) # vtable
fake_IO_FILE += p64(srop_addr) # rdi
fake_IO_FILE += p64(ROL(gadget_addr ^ (heap_base + 0x22a0), 0x11))
# 构造SROP链
frame = SigreturnFrame()
frame.rdi = fake_frame_addr + 0xF8
frame.rsi = 0
frame.rdx = 0x100
frame.rsp = fake_frame_addr + 0xF8 + 0x10
frame.rip = pop_rdi_addr + 1 # ret
3. 关键区别与选择
| 特性 | House of Kiwi | House of Emma |
|---|---|---|
| 适用版本 | glibc 2.29+ | glibc 2.34+ |
| 利用点 | _IO_file_jumps sync指针 | _IO_cookie_jumps函数指针 |
| 加密机制 | 无 | pointer_guard加密 |
| 触发方式 | malloc_assert | malloc_assert |
| 需要控制 | IO_helper_jumps | _IO_cookie_file结构 |
| 复杂度 | 相对简单 | 更复杂 |
4. 防御与缓解
- 更新glibc版本
- 启用Pointer Guard保护
- 加强堆内存管理
- 限制IO操作权限
- 使用现代防护技术如ASLR、DEP等
5. 总结
House of Kiwi和House of Emma是针对高版本glibc的高级堆利用技术:
- 都利用malloc_assert触发IO流操作
- 都需要精确控制内存布局和函数指针
- 在hook被移除后仍能发挥作用
- 需要结合ROP等技术完成最终利用
掌握这些技术需要深入理解glibc的IO实现和内存管理机制,是二进制安全研究中的重要课题。