House Of Force 例题
gyctf_2020_force(House of Force&劫持 malloc_hook)
参考资料:https://tamoly.github.io/2025/07/12/BUUCTF-PWN%E9%A2%98%E8%A7%A3/gyctf_2020_force(House%20of%20Force%E5%92%8Csystem(‘bin%20sh’))/,不得不说这道题坑了我好久,libc 必须使用 BUUCTF 本地的,自己的 libc 还打不通,幸好有这一篇博客,赞
需要注意的是house offorse 只在libc2.23中可用 该漏洞在libc2.27中就被修复了
add
1 | unsigned __int64 add() |
put
1 | unsigned __int64 put() |
mmap 申请空间:
1 | mmap |
泄露 libc 基地址
首先申请一个超级大的 chunk 触发 mmap,然后去打印这个 chunk 地址,减去对应偏移获取 libc 基地址。
libc.address 只在知道 libc 文件的时候使用,是 pwntools 里的一个属性,其用途是设置 libc 库在内存中的基地址。一旦这个基地址被设置好哦,pwntools 就能自动计算出 libc 中各个函数和变量的实际地址。
1 | from pwn import * |


0x7f93b0600000 - 0x7f93b03ff010 = 0x200ff0 获取堆块地址与libc 的固定偏移,可以计算我们的 libc 基地址
1 | from pwn import * |
得到我们的 libc 基地址:
验证一下,我们打印出来的 libc_address 确实是 libc 基地址。
House of force 修改 top_chunk
有了 libc 基址后,开始使用 House of Force 手法通过溢出去修改 top chunk 的 size,同时把 ‘/bin/sh’ 写入 top chunk。溢出需覆盖到 top chunk 的 size 字段时篡改后的 size 需满足 (size & 1) == 1(即 PREV_INUSE 位为 1),否则 glibc 会认为前一个块空闲,触发合并逻辑,导致利用失败。)
1 | libc.address=add(0x200000, 'aaa\n')+0x200ff0 |
地址+0x10 是为了直接覆盖到 size 位
这里使用 p64(0xFFFFFFFFFFFFFFFF | 0x1) 强制设置PREV_INUSE 标志位
把 ‘/bin/sh’ 写在 0xFFFFFFFFFFFFFFFF 前,以便后面通过 top chunk 调用 ‘/bin/sh’
往 malloc_hook 中写入 system
1 | libc.address=add(0x200000, 'aaa\n') + 0x200ff0 |
先计算 malloc_hook 和 top_chunk_addr + 0x20 之间的偏移,0x20 恰好是上面填充过后的位置
将 top chunk 扩展到 __malloc_hook 附近
1 | addr = add(offset, 'a') |
addr1 就是创建新堆之后的 top_chunk 地址
利用 offset 申请一次堆块:
- top chunk 会被 延伸到 __malloc_hook 附近
- addr → 返回 payload 起始地址(下次 malloc 就会覆盖 __malloc_hook)
这里在创建一个堆块,内容是 system ,前面的 memalign_hook 和 realloc_hook 用做堆块头,内容输入开始的地方直接是 malloc_hook
创建内容为 system 的堆块
1 | addr2=add(0x10,p64(system)) |
此时可以知道我们的内容就写在了 addr2 当中,也就是把 system 写入了 malloc_hook
再次申请触发 system(‘/bin/sh’);
1 | io.recvuntil("2:puts\n") |
再次调用 malloc:
- 申请大小 = top
- malloc 内部会执行 __malloc_hook(size)
- 由于我们已经把 __malloc_hook 改成 system,所以实际上执行了:
1 | system(top) |
- top 内部之前写了 /bin/sh\x00 → 得到 shell
size 值原本我们给的是数值,会把这个数值给 rdi,现在给的是 top chunk 地址,给 rdi 的值就是 top 的内容
获取 shell
由于 BUU 平台只给了 libc,并没有给相应的 ld 文件,我们只能寻找对应版本的 glibc_all_in_one 进行 patch
打本地自然就需要用自己的 glibc_all_in_one 中的 libc,不过打远程却需要 BUUCTF 官方给的 libc-2.23.so
本地
1 | from pwn import * |
远程
1 | from pwn import * |
更新: 2026-03-18 17:32:16
原文: https://www.yuque.com/idcm/wnemg9/tkc0o0zwuec67fd4