[湖湘杯 2021]house_of_emma

程序分析:
main:
1 | void __fastcall __noreturn main(__int64 a1, char **a2, char **a3) |
开启沙箱,循环开辟了 0x2000 个字节的空间,可以往里读取 0x500 的内容,当作 vuln 函数的参数
vuln
1 | __int64 __fastcall vuln(__int64 a1) |
malloc
1 | _DWORD *__fastcall malloc_0(__int64 a1) |
- *(_BYTE *)(a1 + 0):第 0 个字节应该是操作码 Opcode。
- v2 = *(_BYTE *)(a1 + 1);:提取第 1 个字节,作为 Chunk 的索引号(Index/ID),即第几个堆块。
- v3 = *(_WORD *)(a1 + 2);:提取第 2、3 两个字节,WORD16位,作为 Chunk 的大小。
之后对各个参数进行了限制,要求大小范围是 0x40F-0x500,堆块数量不超过 0x10 个
del
1 | void __fastcall del(__int64 a1) |
很明显的 UAF
show
1 | int __fastcall show(__int64 a1) |
打印堆块内容
edit
1 | void *__fastcall edit(__int64 a1) |
不是直接写入,这里选择的是直接覆盖,存在 off-by-null 漏洞,memcpy 也算是比较常见的一种漏洞了
EXP 思路:
逆向 opcode
1 | opcode = b"" |
泄露 libc:
1 | add(0x480,0) # index 0 size = 0x480 Large chunk |

Large Bin Attack 泄漏堆地址并劫持 stderr
1 | free(0) # 将 chunk 0 释放,进入 Unsorted Bin |
- 利用 edit 篡改 largebin_bk_nextsize 准备进行 larbinattack,但此时并没有进入到 largebin
- add(0x4b0,15) 进行清理 UnSortedbin 到 Largebin 当中 bk_nextsize ->fd_nextsize = stderr - 0x20,导致原本指向 chunk1 的 bk_nextsize 变成了 stderr - 0x20,可以利用 show 打印出 stderr 地址进行泄露 heap_base:
- 同时
victim->bk_nextsize->fd_nextsize = victim;进行的 larbin_attack,让 stderr 指向 chunk1, 我们可以利用 stderr 触发标准错误,利用 fflush 刷新流调用 stderr 找到 chunk1

构造 ORW
1 | syscall = read_addr + 16 # 寻找 syscall 的 gadget 地址 |
伪造 _IO_FILE 结构体进行 FSOP
因为 stderr 指向了 chunk 1,现在要在 chunk 1 中伪造一个合法的 _IO_FILE 结构体,让 fflush 在解析它时,劫持指令执行流。这里使用的是经典的 House of Emma 链条。
1 | # 伪造IO_FILE |
触发 House Of Emma 执行:
1 | edit(1,file) # 将精心构造好的恶意 _IO_FILE 写入 chunk 1。此时 libc 的 stderr 已经死死盯着这里了。 |
总 EXP:
1 | from pwn import * |
更新: 2026-05-20 02:20:24
原文: https://www.yuque.com/idcm/wnemg9/eob78891d9gc2tic