IO leak
字数 1696 2025-08-05 11:39:48

IO File结构利用技术详解

背景知识

在堆利用场景中,当程序没有提供show函数且开启了FULL RELRO保护时,无法通过unsortedbin泄露基址。此时可以利用IO File结构进行基址泄露。

基本概念

文件描述符与FILE结构

  • Linux初始文件描述符:0(stdin)、1(stdout)、2(stderr)
  • FILE文件流描述文件,初始创建的三个文件(stdin/stdout/stderr)位于libc上
  • 后续创建的FILE结构位于堆中,采用单向链表结构

_IO_FILE_plus结构

struct _IO_FILE_plus {
    _IO_FILE file;
    _IO_jump_t *vtable;
}
  • _IO_list_all:指向FILE文件链表头
  • 链表顺序:stderr → stdout → stdin

_IO_file_jumps结构

  • 所有FILE文件共用的函数指针表
  • 包含__finish__overflow__underflow等函数指针
  • 可通过修改这些指针或伪造vtable结构进行利用

泄露原理

通过篡改_IO_2_1_stdout_结构体中的字段:

  1. 修改flags字段绕过检查
  2. 修改_IO_write_base字段使write系统调用打印指定内存区域

puts函数调用链

puts → _IO_sputn → _IO_new_file_xsputn → _IO_overflow → _IO_new_file_overflow

关键检查绕过

  1. _IO_new_file_overflow检查:

    • f->_flags & _IO_NO_WRITES = 0
    • f->_flags & _IO_CURRENTLY_PUTTING = 1
  2. new_do_write检查:

    • 设置fp->_flags | _IO_IS_APPENDING避免进入else if分支
    • fp->_IO_write_base不能大于fp->_IO_write_end

常用payload构造

# 泄露_IO_file_jumps
payload = p64(0xfbad1800) + p64(0)*3 + b"\x58"

# 泄露_IO_2_1_stdin_
payload = p64(0xfbad3887) + p64(0)*3 + p8(0)

利用流程

  1. 申请_IO_2_1_stdout_结构体
  2. 向结构体写入构造好的数据
  3. 执行puts函数泄露libc地址

不同libc版本的申请方式

  • 2.27和2.31:利用tcache poisoning修改fd指针
  • 2.23:fastbin size检查,只能伪造malloc_hook-0x23stdout结构体地址-0x43

爆破技巧

当ASLR开启时,stdout结构体地址后三位固定,倒数第四位随机。可通过爆破预测该位:

  1. 利用unsorted bin中的fd指针(指向main_arena+88/96)
  2. 修改fd指针为stdout结构体地址
  3. 爆破倒数第四位

高级利用技巧

realloc_hook调整栈帧

当只能劫持malloc_hook时,结合realloc_hook调整栈帧使onegadget生效:

malloc  malloc_hook  realloc  realloc_hook  onegadget

通过realloc_addr+offset调整push次数(offset可取0,2,4,6,11,12),抬高栈满足onegadget条件。

实战案例

de1ctf_2019_weapon (libc2.23)

漏洞点:UAF漏洞,无show函数

利用步骤

  1. 扩展fastbin到unsorted bin
  2. 将unsorted bin链放入fastbin
  3. 修改main_arena+0x88为&_IO_2_1_stdout_-0x43
  4. 构造payload泄露libc
  5. fastbin attack修改malloc_hook

关键payload

add(0x60, 11, b'\x00'*0x33 + p64(0xfbad1887) + p64(0)*3 + b'\x00')

nsctf_online_2019_pwn1

漏洞点:负数溢出漏洞

利用步骤

  1. 利用负数溢出找到_IO_2_1_stdout_结构体指针
  2. 修改_IO_write_base_flags泄露libc
  3. 伪造vtable,篡改_flags_lock、vtable、_IO_save_base字段
  4. 劫持_IO_new_file_xsputn为system

关键payload

pl = flat([
    b'/bin/sh\x00',
    p64(0)*8,
    libc.symbols['system'] + libc_base,  # _IO_save_base
    p64(0)*6,
    p64(0),
    libc_base + 0x3c6780,  # lock
    p64(0),
    p64(0)*8,
    libc_base + libc.symbols['_IO_2_1_stdout_'] + 0x10  # vtable
])

总结

IO File结构利用是一种强大的技术,适用于无show函数和FULL RELRO保护场景。关键在于理解FILE结构布局和函数调用链,通过精心构造的payload可以绕过各种检查实现信息泄露和代码执行。

IO File结构利用技术详解 背景知识 在堆利用场景中,当程序没有提供show函数且开启了FULL RELRO保护时,无法通过unsortedbin泄露基址。此时可以利用IO File结构进行基址泄露。 基本概念 文件描述符与FILE结构 Linux初始文件描述符:0(stdin)、1(stdout)、2(stderr) FILE文件流描述文件,初始创建的三个文件(stdin/stdout/stderr)位于libc上 后续创建的FILE结构位于堆中,采用单向链表结构 _ IO_ FILE_ plus结构 _IO_list_all :指向FILE文件链表头 链表顺序:stderr → stdout → stdin _ IO_ file_ jumps结构 所有FILE文件共用的函数指针表 包含 __finish 、 __overflow 、 __underflow 等函数指针 可通过修改这些指针或伪造vtable结构进行利用 泄露原理 通过篡改 _IO_2_1_stdout_ 结构体中的字段: 修改 flags 字段绕过检查 修改 _IO_write_base 字段使write系统调用打印指定内存区域 puts函数调用链 关键检查绕过 _IO_new_file_overflow 检查: f->_flags & _IO_NO_WRITES = 0 f->_flags & _IO_CURRENTLY_PUTTING = 1 new_do_write 检查: 设置 fp->_flags | _IO_IS_APPENDING 避免进入else if分支 fp->_IO_write_base 不能大于 fp->_IO_write_end 常用payload构造 利用流程 申请 _IO_2_1_stdout_ 结构体 向结构体写入构造好的数据 执行puts函数泄露libc地址 不同libc版本的申请方式 2.27和2.31 :利用tcache poisoning修改fd指针 2.23 :fastbin size检查,只能伪造 malloc_hook-0x23 或 stdout结构体地址-0x43 爆破技巧 当ASLR开启时,stdout结构体地址后三位固定,倒数第四位随机。可通过爆破预测该位: 利用unsorted bin中的fd指针(指向main_ arena+88/96) 修改fd指针为stdout结构体地址 爆破倒数第四位 高级利用技巧 realloc_ hook调整栈帧 当只能劫持malloc_ hook时,结合realloc_ hook调整栈帧使onegadget生效: 通过realloc_ addr+offset调整push次数(offset可取0,2,4,6,11,12),抬高栈满足onegadget条件。 实战案例 de1ctf_ 2019_ weapon (libc2.23) 漏洞点 :UAF漏洞,无show函数 利用步骤 : 扩展fastbin到unsorted bin 将unsorted bin链放入fastbin 修改main_ arena+0x88为 &_IO_2_1_stdout_-0x43 构造payload泄露libc fastbin attack修改malloc_ hook 关键payload : nsctf_ online_ 2019_ pwn1 漏洞点 :负数溢出漏洞 利用步骤 : 利用负数溢出找到 _IO_2_1_stdout_ 结构体指针 修改 _IO_write_base 和 _flags 泄露libc 伪造vtable,篡改 _flags 、 _lock 、vtable、 _IO_save_base 字段 劫持 _IO_new_file_xsputn 为system 关键payload : 总结 IO File结构利用是一种强大的技术,适用于无show函数和FULL RELRO保护场景。关键在于理解FILE结构布局和函数调用链,通过精心构造的payload可以绕过各种检查实现信息泄露和代码执行。