IO_file劫持利用—fsop
字数 2383 2025-08-07 00:34:54

IO_FILE劫持利用—FSOP技术详解

0x00 前置知识

1. IO_FILE相关知识

IO_FILE是glibc中用于文件操作的结构体,包含文件描述符、缓冲区指针和各种标志位。攻击者可以通过伪造IO_FILE结构来劫持程序执行流程。

关键结构成员:

  • _flags:文件状态标志
  • _IO_read_ptr_IO_read_end_IO_read_base:输入缓冲区指针
  • _IO_write_ptr_IO_write_base:输出缓冲区指针
  • _chain:指向下一个FILE结构的指针
  • vtable:虚函数表指针(位于偏移0xd8处)

2. FSOP利用原理

FSOP(File Stream Oriented Programming)是通过伪造IO_FILE结构来利用glibc中文件流处理函数的攻击技术。主要利用点包括:

  • exit()函数调用链
  • malloc_printerr错误处理路径

3. _IO_str_jumps查找方法

从glibc 2.24开始引入了vtable检查机制,需要定位_IO_str_jumps符号:

  1. 通过nmreadelf查找_IO_str_underflow符号
  2. _IO_str_jumps位于_IO_str_underflow向上偏移0x20处
  3. 使用gdb的search -p命令查找存储指针的位置

4. House of Orange技术

House of Orange是一种堆利用技术,主要步骤:

  1. 通过堆溢出修改top chunk的size为较小值
  2. 申请比top chunk size更大的堆块
  3. 导致top chunk被释放到unsorted bin中
  4. 从而在没有free函数的情况下获得一个free chunk

0x01 exit劫持利用

调用路径

exit -> __run_exit_handlers -> _IO_cleanup -> _IO_flush_all_lockp -> stderr -> stderr+0xd8

利用思路

  1. 修改_IO_2_1_stderr_ + 0x68为fake_io_file地址
  2. 将fake_io_file的vtable(偏移0xd8)修改为_IO_str_jumps
  3. 通过_IO_str_overflow设置rdx寄存器并调用malloc
  4. 结合提前设置的malloc_hook为setcontext实现堆上ROP

关键汇编指令

  • mov rbx, stderr:将rbx设置为stderr
  • stderr+0x68是chain字段,用于链接fake_io_file
  • mov rax, [rbx+0xd8]:获取vtable指针
  • call [rax+XX]:调用vtable中的函数

0x02 malloc_printerr劫持利用

调用路径

malloc -> _int_malloc -> __libc_message -> abort -> _IO_flush_all_lockp

利用思路

  1. 使unsorted bin中有且仅有一个堆块
  2. 修改该堆块的bk指针为_IO_list_all
  3. 修改堆块size为0x60(对应small bin[4])
  4. 触发malloc error进入_IO_flush_all_lockp
  5. 伪造IO_FILE结构绕过检查并控制执行流

检查绕过条件

需要满足以下条件之一:

  1. fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base
  2. _IO_vtable_offset(fp) == 0 && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)

0x03 例题分析

例题1:bytectf2020 gun

利用步骤

  1. 泄露libc和heap地址
  2. 构造fake IO_FILE结构
  3. 设置malloc_hook为setcontext+61
  4. 通过exit触发FSOP
  5. 使用SROP实现ORW读取flag

关键exp代码

# 构造fake IO_FILE
IO = '\x00'*0x28
IO += p64(heap_base + 0x360 + 0xE0)  # rdx
IO = IO.ljust(0xD8, '\x00')
IO += p64(IO_str_jumps)

# 设置SROP帧
frame = SigreturnFrame()
frame.rax = 0
frame.rdi = 0
frame.rsi = address
frame.rdx = 0x2000
frame.rsp = address
frame.rip = Read

# 触发利用
menu(4)
p.sendlineafter('Goodbye!', orw)

例题2:BUUOJ-house of orange

利用步骤

  1. 使用House of Orange释放top chunk到unsorted bin
  2. 泄露libc和heap地址
  3. 构造fake IO_FILE和small bin chunk
  4. 修改unsorted bin chunk的bk为_IO_list_all-0x10
  5. 触发malloc error执行system("/bin/sh")

关键exp代码

# House of Orange释放top chunk
add(0x30, 'nameless')
pd = 'a'*0x30 + p64(0) + p64(0x21) + 'a'*16 + p64(0)+ p64(0xf80)
edit(len(pd)+1, pd)
add(0x1000, 'nameless')

# 构造fake IO_FILE
fake_io = '/bin/sh\x00' + p64(0x60) + p64(0) + p64(_IO_list_all-0x10)
fake_io += p64(0) + p64(1)
fake_io = fake_io.ljust(0xc0, '\x00')
pd += fake_io
pd += p64(0)*3
pd += p64(heap+0x5e8)
pd += p64(0)*2 + p64(system)
edit(0x800, pd)

0x04 调试技巧

  1. 关键函数断点:

    • exit
    • __run_exit_handlers
    • _IO_cleanup
    • _IO_flush_all_lockp
    • _IO_str_overflow
  2. 关键寄存器观察:

    • RBX:通常指向当前IO_FILE结构
    • RAX:通常指向vtable或函数指针
    • RDX:可通过_IO_str_overflow控制
  3. 内存布局检查:

    • _IO_list_all链表
    • small bin和unsorted bin状态
    • fake IO_FILE结构完整性

0x05 防护绕过

  1. glibc 2.24+的vtable检查:

    • 必须使用合法的vtable如_IO_str_jumps
    • 伪造的vtable必须在_IO_vtable段内
  2. 指针完整性检查:

    • _IO_write_ptr必须大于_IO_write_base
    • _mode字段需要合理设置
  3. 堆布局控制:

    • 精确控制堆块大小和位置
    • 避免破坏关键堆元数据

0x06 总结

FSOP是一种强大的利用技术,通过伪造IO_FILE结构可以绕过多种现代防护机制。关键点在于:

  1. 理解IO_FILE结构和虚函数调用机制
  2. 掌握exit和malloc_printerr的调用路径
  3. 精确控制堆布局和内存数据
  4. 合理绕过各种运行时检查

这种技术在CTF比赛中经常出现,也是现实世界中高级漏洞利用的重要手段。

IO_ FILE劫持利用—FSOP技术详解 0x00 前置知识 1. IO_ FILE相关知识 IO_ FILE是glibc中用于文件操作的结构体,包含文件描述符、缓冲区指针和各种标志位。攻击者可以通过伪造IO_ FILE结构来劫持程序执行流程。 关键结构成员: _flags :文件状态标志 _IO_read_ptr 、 _IO_read_end 、 _IO_read_base :输入缓冲区指针 _IO_write_ptr 、 _IO_write_base :输出缓冲区指针 _chain :指向下一个FILE结构的指针 vtable :虚函数表指针(位于偏移0xd8处) 2. FSOP利用原理 FSOP(File Stream Oriented Programming)是通过伪造IO_ FILE结构来利用glibc中文件流处理函数的攻击技术。主要利用点包括: exit() 函数调用链 malloc_printerr 错误处理路径 3. _ IO_ str_ jumps查找方法 从glibc 2.24开始引入了vtable检查机制,需要定位 _IO_str_jumps 符号: 通过 nm 或 readelf 查找 _IO_str_underflow 符号 _IO_str_jumps 位于 _IO_str_underflow 向上偏移0x20处 使用gdb的 search -p 命令查找存储指针的位置 4. House of Orange技术 House of Orange是一种堆利用技术,主要步骤: 通过堆溢出修改top chunk的size为较小值 申请比top chunk size更大的堆块 导致top chunk被释放到unsorted bin中 从而在没有free函数的情况下获得一个free chunk 0x01 exit劫持利用 调用路径 利用思路 修改 _IO_2_1_stderr_ + 0x68为fake_ io_ file地址 将fake_ io_ file的vtable(偏移0xd8)修改为 _IO_str_jumps 通过 _IO_str_overflow 设置rdx寄存器并调用malloc 结合提前设置的malloc_ hook为setcontext实现堆上ROP 关键汇编指令 mov rbx, stderr :将rbx设置为stderr stderr+0x68 是chain字段,用于链接fake_ io_ file mov rax, [rbx+0xd8] :获取vtable指针 call [rax+XX] :调用vtable中的函数 0x02 malloc_ printerr劫持利用 调用路径 利用思路 使unsorted bin中有且仅有一个堆块 修改该堆块的bk指针为 _IO_list_all 修改堆块size为0x60(对应small bin[ 4 ]) 触发malloc error进入 _IO_flush_all_lockp 伪造IO_ FILE结构绕过检查并控制执行流 检查绕过条件 需要满足以下条件之一: fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base _IO_vtable_offset(fp) == 0 && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base) 0x03 例题分析 例题1:bytectf2020 gun 利用步骤 泄露libc和heap地址 构造fake IO_ FILE结构 设置malloc_ hook为setcontext+61 通过exit触发FSOP 使用SROP实现ORW读取flag 关键exp代码 例题2:BUUOJ-house of orange 利用步骤 使用House of Orange释放top chunk到unsorted bin 泄露libc和heap地址 构造fake IO_ FILE和small bin chunk 修改unsorted bin chunk的bk为 _IO_list_all-0x10 触发malloc error执行system("/bin/sh") 关键exp代码 0x04 调试技巧 关键函数断点: exit __run_exit_handlers _IO_cleanup _IO_flush_all_lockp _IO_str_overflow 关键寄存器观察: RBX:通常指向当前IO_ FILE结构 RAX:通常指向vtable或函数指针 RDX:可通过 _IO_str_overflow 控制 内存布局检查: _IO_list_all 链表 small bin和unsorted bin状态 fake IO_ FILE结构完整性 0x05 防护绕过 glibc 2.24+的vtable检查: 必须使用合法的vtable如 _IO_str_jumps 伪造的vtable必须在 _IO_vtable 段内 指针完整性检查: _IO_write_ptr 必须大于 _IO_write_base _mode 字段需要合理设置 堆布局控制: 精确控制堆块大小和位置 避免破坏关键堆元数据 0x06 总结 FSOP是一种强大的利用技术,通过伪造IO_ FILE结构可以绕过多种现代防护机制。关键点在于: 理解IO_ FILE结构和虚函数调用机制 掌握exit和malloc_ printerr的调用路径 精确控制堆布局和内存数据 合理绕过各种运行时检查 这种技术在CTF比赛中经常出现,也是现实世界中高级漏洞利用的重要手段。