House Of Force(topchunk)
什么是 House Of Force?
_House Of Force(HoF)_的命名,核心是用「House」指代堆内存空间、「Force」指代 “强制篡改堆布局以劫持分配” 的核心攻击逻辑 。House Of Force 是一种堆的利用方法 其主要原理是控制 heap 中的 top_chunk 并 malloc 来达到控制任意内存的空间。既然是控制 top_chunk,那就先了解一下 top_chunk:
top_chunk
top_chunk 是 glibc 的 ptmalloc 内存管理中,位于堆物理地址最高处的特殊空闲 chunk,不属于任何 bin 链表,是内存分配的 “最后备选”,还负责堆扩容与内存归还操作系统。
位置:处于堆顶,brk 指针位于其顶部,是堆中最后一块空闲块。
申请内存时,依次查询 tcache → fastbins → smallbins → largebins → unsorted bin。
上述均无匹配时,尝试从 top_chunk 切割;若 top_chunk 不足,则调用 sysmalloc 扩容。
切割后,剩余部分作为新的 top_chunk,分配部分返回给用户。
引入实例 top_chunk_demo
我们先通过一个例子去了解 top_chunk 的分配过程,之后再去讲解 HOF 的利用,这样会更清晰。
1 |
|
先对文件进行检查,发现什么都没有开
1 | ctfshow@ubuntu:~/Desktop$ checksec top_chunk_demo |
用 gdb 调试,在 main 函数下断点,运行到常见第一个堆块之后,看一下堆情况:
1 | ───────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]──────────────────────────────────────────────────────────────────────────────── |
1 | pwndbg> x/20gx 0x602300 |
此时 top_chunk 的大小为 0x20ce1,我们再进行 malloc(0x20)看一看对快的内存大小:
1 | ───────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]──────────────────────────────────────────────────────────────────────────────── |
1 | pwndbg> x/20gx 0x602300 |
对比第一次 malloc 的堆情况,我们发现,系统新开辟了一个 0x31 大小的内存空间,但是 top_chunk_size 却减小了 0x30 的大小,我们继续调试看看执行完第三次 malloc 的堆块:
1 | ───────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]──────────────────────────────────────────────────────────────────────────────── |
1 | pwndbg> x/30gx 0x602300 |
可以发现,系统又开辟了一个 0x41 大小的内存空间,此时 top_chunk_size 减小了 0x40。
tip):这里对多出的 1 做个解释: 观察到的top_chunk_size 减少 0x40、但实际分配 0x41 空间,核心原因是因为 glibc 堆的 size 段低 3 位是标志位,并不参与实际内存大小计算。
综上得出:在分配比 top_chunk 小的 chunk 的时候,会从 top_chunk 中分割,并且 top_chunk 向下移动(::前提是没有可以使用的 bins,否则先从 bins 中取)
House Of Force 利用原理
如果一个堆漏洞想要通过 House Of Force 进行利用,就必须满足以下条件:
能够以溢出等方式控制 top_chunk 的 size 域且能够自由控制堆分配尺寸的大小。
我们知道,在分配堆块时,如果所有空闲的 bins 都无法满足需求,就会从 top_chunk 中分割出相应的大小作为堆块的空间。如果我们可以控制 top_chunk_size 的值,就可以使 top_chunk 指向我们所期望的任何位置,就相当于是一次任意地址写。
不过在 glibc 中,会对用户请求的大小和 top_chunk 现有的 size 进行验证:
libc 2.23 源码 3793-3809 行

1 | victim = av->top; //获取当前top_chunk的大小 |
如果 top_chunk_size 被篡改成很大的值,就可以轻松通过这个验证。若要绕过这个验证,我们一般的做法是将 top_chunk_siza 修改为-1,因为在进行比较的时候会将 size 转换为无符号数,也就是将-1 转换为 unsigned long 中最大的时候,因此无论如何都可以通过验证。验证通过之后,会将 top_chunk 指针进行更新,接下来的堆块就会分配到这个位置。用户只要控制了这个指针就相当于控制了任意地址。与此同时 top_chunk 的 size 也会更新。
如果我们想要下次再指定位置分配大小为 x 的 chunk,我们需要确保 remainder_size 不小于 x+MINSIZE
HOF 向前控制内存
下面会举例说明 House Of Force 的利用:
该例子是通过 House Of Force 来篡改 malloc@got.plt 实现劫持程序流程。
示例的源代码如下:top_chunk_demo1
1 |
|
ptr=(long *)(((long)ptr)+24);:让 ptr 精准指向 top_chunk 的 size 域,直接调试到这一步之前更清晰:ptr 本身指向的是就是 chunk1 的 data 域即第 16 字节处,+16+8=24 恰好修改到 top_chunk 的 size 字节。
1 | In file: /home/kali/Desktop/top_chunk_demo1.c:6 |
我们按照程序运行过程继续调试
1 | In file: /home/kali/Desktop/top_chunk_demo1.c:7 |
执行到运行完*ptr=-1,我们可以看见 top_chunk 的 size 域已经被修改为最大无符号长整型
1 | 7 *ptr=-1; // <=== 这里把top chunk的size域改为0xffffffffffffffff |
在我们真正的题目当中,这一步可以通过堆溢出漏洞来实现,直接赋值-1 即可。
我们一开始的目标是利用 HOF 篡改 malloc@got.plt 实现劫持程序流程,之后就要执行 malloc(-4120);
继续运行到执行完 malloc(-4120)之后,再进行 malloc(0x10)就可以控制 malloc@got.plt 了
由于本机可能因为版本原因,无法达到程序运行完预想的效果,就不再演示,在实际题目中思路是相同的。
HOF 向后控制内存
1 |
|
思路一样,增大 topchunk 指针,使其往后指,控制关键地址
更新: 2026-03-17 21:31:53
原文: https://www.yuque.com/idcm/wnemg9/vt5mrvnq9qeeukc7