IO FILE 之劫持vtable及FSOP
字数 2756 2025-08-05 08:20:09

IO FILE 利用技术详解:vtable劫持与FSOP

一、IO FILE基础回顾

IO FILE结构体是glibc中用于文件操作的核心数据结构,其中最重要的组件之一是vtable(虚函数表)。在之前的文章中已经详细分析了fopenfreadfwritefclose等函数的源码实现。

关键结构体定义:

struct _IO_FILE_plus {
    _IO_FILE file;
    const struct _IO_jump_t *vtable;
};

struct _IO_jump_t {
    JUMP_FIELD(size_t, __dummy);
    JUMP_FIELD(size_t, __dummy2);
    JUMP_FIELD(_IO_finish_t, __finish);
    JUMP_FIELD(_IO_overflow_t, __overflow);
    // ...共19个函数指针
};

二、vtable劫持技术

1. 基本原理

vtable劫持的核心思想是通过控制FILE结构体中的vtable指针,使其指向可控内存,从而在调用IO函数时劫持程序执行流。

适用条件

  • 仅适用于libc 2.23及之前版本
  • libc 2.24之后引入了vtable check机制,无法直接伪造vtable

2. 劫持方式

有两种主要方式实现vtable劫持:

  1. 修改已有FILE结构体的vtable字段

    • 直接修改内存中已存在的FILE结构体的vtable指针
    • 示例代码:
      FILE *fp = fopen("123.txt", "rw");
      long long *vtable_addr = (long long *)((long long)fp + 0xd8); // vtable偏移
      vtable_addr[0] = (long long)fake_vtable; // 指向伪造的vtable
      
  2. 伪造整个FILE结构体

    • 完全构造一个伪造的FILE结构体
    • 修改指针指向这个伪造结构体

3. 关键IO函数调用的vtable函数

函数 调用的vtable函数
fopen 不直接调用vtable函数
fread _IO_file_xsgetn, _IO_file_doallocate, __GI__IO_file_stat, __GI__IO_file_read
fwrite _IO_new_file_xsputn, _IO_new_file_overflow, _IO_file_doallocate, _IO_new_file_write
fclose __close, __finish

三、FSOP(File Stream Oriented Programming)

1. 基本原理

FSOP利用的是glibc中管理所有打开文件的单链表_IO_list_all。通过伪造链表节点,控制程序执行流。

关键数据结构:

  • _IO_list_all:指向FILE结构体链表的头部
  • _chain字段:链接下一个FILE结构体

2. 触发时机

_IO_flush_all_lockp函数会在以下情况下被调用:

  1. 程序调用abort()
  2. 程序调用exit()
  3. 程序从main函数正常返回时

3. 利用条件

要成功触发FSOP,需要满足以下条件:

if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
    || (_IO_vtable_offset (fp) == 0 && fp->_mode > 0 
        && (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base))
#endif
    ) && _IO_OVERFLOW (fp, EOF) == EOF)

即:

  • 对于普通文件(_mode <= 0):_IO_write_ptr > _IO_write_base
  • 对于宽字符文件(_mode > 0):_wide_data->_IO_write_ptr > _wide_data->_IO_write_base

4. 利用步骤

  1. 伪造一个FILE结构体
  2. 利用漏洞将_IO_list_all指向伪造的结构体
    • 或修改链表中的_chain字段指向伪造数据
  3. 触发_IO_flush_all_lockp调用
  4. 绕过检查条件,使程序调用_IO_OVERFLOW时劫持执行流

四、House of Orange攻击实例分析

以"东华杯2016-pwn450"为例,演示FSOP的实际利用。

1. 题目分析

  • 菜单题:创建、编辑、删除堆块
  • 限制:同一时间只能操作一个堆块
  • 漏洞:编辑函数存在堆溢出

2. 利用步骤

阶段一:信息泄露

  1. 通过创建函数泄露堆地址
  2. 申请大块内存(如0x200000)使mmap区域紧贴libc,计算libc基址

阶段二:构造unsorted bin

  1. 利用堆溢出伪造top chunk的size
    • size > 0x20
    • prev_inuse位为1
    • top chunk address + size必须页对齐(0x1000)
  2. 申请超过伪造size的内存,触发sysmalloc将旧top chunk释放到unsorted bin

阶段三:unsorted bin attack

  1. 利用unsorted bin attack修改_IO_list_all
    • 使其指向main_arena中的unsorted_bins数组
  2. 伪造一个0x60大小的small bin
    • 释放后其bk指针会被当作_chain字段

阶段四:FSOP利用

  1. _IO_flush_all_lockp遍历链表时:
    • 第一个节点(main_arena)不可控
    • 第二个节点(通过_chain字段)完全可控
  2. 伪造FILE结构体:
    • 设置_mode = 0
    • 设置_IO_write_ptr > _IO_write_base
    • 将vtable全部指针设置为system地址
  3. 最终执行system("bin/sh")获取shell

3. 伪造结构体示例

# 使用pwn_debug工具检查伪造结构体
from pwn_debug import IO_FILE_plus
IO_FILE_plus.orange_check(fake_file)  # 检查是否满足house of orange条件
IO_FILE_plus.show(fake_file)          # 显示伪造的FILE结构体

五、防御机制与绕过

1. libc 2.24的vtable check

libc 2.24引入了vtable检查机制:

  • 只允许vtable指向特定的合法区域
  • 防止直接伪造vtable

2. 可能的绕过方法

  1. 重用合法vtable中的函数指针
  2. 利用部分写修改合法vtable中的指针
  3. 结合其他漏洞绕过检查

六、总结

  1. vtable劫持

    • 通过修改vtable指针控制程序流
    • 适用于libc 2.23及之前版本
  2. FSOP

    • 利用_IO_list_all链表和_IO_flush_all_lockp机制
    • 需要精心构造FILE结构体满足检查条件
    • House of Orange是经典利用方式
  3. 防御

    • libc 2.24+的vtable check有效阻止了直接伪造
    • 需要寻找新的利用方式

七、扩展阅读

  1. [IO FILE之fopen详解]
  2. [IO FILE之fread详解]
  3. [IO FILE之fwrite详解]
  4. [IO_FILE之fclose详解]
  5. [unsorted bin attack分析]

注:本文所述技术仅用于安全研究和CTF比赛,请勿用于非法用途。

IO FILE 利用技术详解:vtable劫持与FSOP 一、IO FILE基础回顾 IO FILE结构体是glibc中用于文件操作的核心数据结构,其中最重要的组件之一是 vtable (虚函数表)。在之前的文章中已经详细分析了 fopen 、 fread 、 fwrite 和 fclose 等函数的源码实现。 关键结构体定义: 二、vtable劫持技术 1. 基本原理 vtable劫持的核心思想是通过控制FILE结构体中的vtable指针,使其指向可控内存,从而在调用IO函数时劫持程序执行流。 适用条件 : 仅适用于libc 2.23及之前版本 libc 2.24之后引入了vtable check机制,无法直接伪造vtable 2. 劫持方式 有两种主要方式实现vtable劫持: 修改已有FILE结构体的vtable字段 : 直接修改内存中已存在的FILE结构体的vtable指针 示例代码: 伪造整个FILE结构体 : 完全构造一个伪造的FILE结构体 修改指针指向这个伪造结构体 3. 关键IO函数调用的vtable函数 | 函数 | 调用的vtable函数 | |--------|---------------------------------------------------------------------------------| | fopen | 不直接调用vtable函数 | | fread | _IO_file_xsgetn , _IO_file_doallocate , __GI__IO_file_stat , __GI__IO_file_read | | fwrite | _IO_new_file_xsputn , _IO_new_file_overflow , _IO_file_doallocate , _IO_new_file_write | | fclose | __close , __finish | 三、FSOP(File Stream Oriented Programming) 1. 基本原理 FSOP利用的是glibc中管理所有打开文件的单链表 _IO_list_all 。通过伪造链表节点,控制程序执行流。 关键数据结构: _IO_list_all :指向FILE结构体链表的头部 _chain 字段:链接下一个FILE结构体 2. 触发时机 _IO_flush_all_lockp 函数会在以下情况下被调用: 程序调用 abort() 时 程序调用 exit() 时 程序从main函数正常返回时 3. 利用条件 要成功触发FSOP,需要满足以下条件: 即: 对于普通文件( _mode <= 0 ): _IO_write_ptr > _IO_write_base 对于宽字符文件( _mode > 0 ): _wide_data->_IO_write_ptr > _wide_data->_IO_write_base 4. 利用步骤 伪造一个FILE结构体 利用漏洞将 _IO_list_all 指向伪造的结构体 或修改链表中的 _chain 字段指向伪造数据 触发 _IO_flush_all_lockp 调用 绕过检查条件,使程序调用 _IO_OVERFLOW 时劫持执行流 四、House of Orange攻击实例分析 以"东华杯2016-pwn450"为例,演示FSOP的实际利用。 1. 题目分析 菜单题:创建、编辑、删除堆块 限制:同一时间只能操作一个堆块 漏洞:编辑函数存在堆溢出 2. 利用步骤 阶段一:信息泄露 通过创建函数泄露堆地址 申请大块内存(如0x200000)使mmap区域紧贴libc,计算libc基址 阶段二:构造unsorted bin 利用堆溢出伪造top chunk的size size > 0x20 prev_ inuse位为1 top chunk address + size必须页对齐(0x1000) 申请超过伪造size的内存,触发sysmalloc将旧top chunk释放到unsorted bin 阶段三:unsorted bin attack 利用unsorted bin attack修改 _IO_list_all 使其指向main_ arena中的unsorted_ bins数组 伪造一个0x60大小的small bin 释放后其bk指针会被当作 _chain 字段 阶段四:FSOP利用 当 _IO_flush_all_lockp 遍历链表时: 第一个节点(main_ arena)不可控 第二个节点(通过 _chain 字段)完全可控 伪造FILE结构体: 设置 _mode = 0 设置 _IO_write_ptr > _IO_write_base 将vtable全部指针设置为 system 地址 最终执行 system("bin/sh") 获取shell 3. 伪造结构体示例 五、防御机制与绕过 1. libc 2.24的vtable check libc 2.24引入了vtable检查机制: 只允许vtable指向特定的合法区域 防止直接伪造vtable 2. 可能的绕过方法 重用合法vtable中的函数指针 利用部分写修改合法vtable中的指针 结合其他漏洞绕过检查 六、总结 vtable劫持 : 通过修改vtable指针控制程序流 适用于libc 2.23及之前版本 FSOP : 利用 _IO_list_all 链表和 _IO_flush_all_lockp 机制 需要精心构造FILE结构体满足检查条件 House of Orange是经典利用方式 防御 : libc 2.24+的vtable check有效阻止了直接伪造 需要寻找新的利用方式 七、扩展阅读 [ IO FILE之fopen详解 ] [ IO FILE之fread详解 ] [ IO FILE之fwrite详解 ] [ IO_ FILE之fclose详解 ] [ unsorted bin attack分析 ] 注:本文所述技术仅用于安全研究和CTF比赛,请勿用于非法用途。