House of Cat: 绕过 glibc 2.24 后 Vtable 检查的 IO_FILE 利用技术详解
概述
House of Cat 是一种针对 glibc 2.24 及以上版本的 IO_FILE 利用技术,主要思路是通过覆盖 vtable 指针并利用 _IO_jump_t 中的函数来绕过 vtable 检查,从而劫持程序控制流。该技术可以通过两种方式触发攻击:FSOP (File Stream Oriented Programming) 或 __malloc_assert。
技术背景
自 glibc 2.24 起,引入了对 vtable 的检查机制,防止直接覆盖 vtable 为 system 等危险函数。House of Cat 通过利用 _IO_wfile_jumps 中的函数(特别是 _IO_wfile_seekoff 和 _IO_wfile_overflow)来绕过这些检查。
关键技术点
1. _IO_wfile_jumps 结构利用
_IO_wfile_jumps 是一个重要的虚表结构,其中我们关注两个关键函数:
_IO_wfile_seekoff(偏移 0x48)_IO_wfile_overflow(偏移 0x18)
_IO_wfile_seekoff 函数关键部分
该函数会调用 _IO_switch_to_wget_mode,需要满足以下条件:
fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_basefp->_mode != 0
_IO_switch_to_wget_mode 函数
该函数在满足条件后会调用 _IO_WOVERFLOW(fp, WEOF),关键点在于:
- 通过
fp->_wide_data指向的结构体_IO_wide_data中的_wide_vtable字段 - 调用
_wide_vtable指向的__overflow函数(偏移 0x18) - 关键优势:
_wide_vtable没有像 vtable 那样的检查机制,可以自由覆盖
2. 伪造 IO_FILE 结构要求
要成功利用,需要精心构造伪造的 IO_FILE 结构:
fp->_mode字段 (偏移 0xc0) 必须不为 0(通常设置为 -1)fp->_wide_data字段 (偏移 0xa0) 指向一个伪造的_IO_wide_data结构- 在伪造的
_IO_wide_data结构中:_IO_write_ptr(偏移 0x18) 设置为 1_IO_write_base(偏移 0x20) 设置为 0
- 伪造的
_wide_vtable可以指向 system 或其他目标函数
3. 触发路径
有两种主要方式触发 _IO_wfile_seekoff 函数:
方法一:FSOP (File Stream Oriented Programming)
调用链:
__GI_exit --> __run_exit_handlers --> _IO_cleanup --> _IO_flush_all_lockp --> _IO_wfile_seekoff --> _IO_switch_to_wget_mode
关键步骤:
- 通过 large bin attack 等方法覆盖
_IO_list_all指针 - 伪造的 IO_FILE 结构需要满足 FSOP 链的要求
- 在
_IO_flush_all_lockp中,vtable 被覆盖为_IO_wfile_jumps + 0x30 - 注意
mode参数的设置(在 glibc 2.31 中会被设为 0)
方法二:__malloc_assert
调用链:
_int_malloc --> sysmalloc --> __malloc_assert --> __fxprintf --> __vfxprintf --> locked_vfxprintf --> __vfprintf_internal --> _IO_file_xsputn
关键要求:
- 需要将
_flag设置为 0x8005(绕过__vfprintf_internal中的检查) - 覆盖
stderr指向伪造的结构 - vtable 需要覆盖为
_IO_wfile_jumps + 0x10(这样 +0x38 偏移就能得到_IO_wfile_seekoff)
4. 栈迁移技术
在 _IO_switch_to_wget_mode 函数中可以利用以下指令序列实现栈迁移:
mov rax, [rdi+0xa0] ; rdi = FILE*, 获取 _wide_data
mov rdx, [rax+0x20] ; 获取 _wide_vtable
这可以实现 rdi 到 rdx 的转换,进而可以衔接 setcontext + 61 完成栈迁移。
实际利用示例
例题分析:[HGAME 2023 week3]note_context
题目特点:
- 存在 UAF 漏洞
- 申请大小限制在 0x500 以上
- libc 版本为 2.32
- 开启了沙箱,需要 ORW 绕过
- 保护全开
利用步骤:
-
泄漏地址:
- 利用 large bin 的 fd 指针泄漏堆地址
- 通过 unsorted bin 泄漏 libc 地址
-
large bin attack:
- 覆盖
_IO_list_all指针 - 同时完成堆地址泄漏
- 覆盖
-
伪造结构:
- 在堆上布置完整的伪造结构:
- 伪造的 IO_FILE
- ORW 链
_wide_data结构- 寄存器传参设置
- 在堆上布置完整的伪造结构:
-
触发利用:
- 通过 exit() 触发 FSOP
- 完成栈迁移到堆上布置的 ORW
- 读取 flag
关键伪造结构:
伪造的IO_FILE:
+0xc0: -1 ; _mode
+0xa0: 指向伪造的_wide_data
伪造的_wide_data:
+0x18: 1 ; _IO_write_ptr
+0x20: 0 ; _IO_write_base
+0x20: 指向伪造的_wide_vtable
伪造的_wide_vtable:
+0x18: system或setcontext+61 ; _IO_wfile_overflow
总结
House of Cat 是一种强大的 IO_FILE 利用技术,主要特点包括:
- 通过
_IO_wfile_jumps中的函数绕过 vtable 检查 - 利用
_wide_vtable不受检查的特性 - 可通过 FSOP 或
__malloc_assert两种路径触发 - 结合栈迁移技术可以实现更灵活的利用
- 适用于 glibc 2.24 及以上版本的保护绕过
在实际利用中,需要注意不同 glibc 版本中函数偏移和检查条件的细微差别,精心构造伪造的结构以满足各种检查条件。