Fastbin DOUBLE FREE
Fastbin Attack 基本介绍
fastbin attack是一类漏洞的利用方法,是指所有基于fastbin机制的漏洞利用方法。这类利用的前提是:
- 存在堆溢出、UAF 等能够控制 chunk 内容的漏洞。
- 漏洞发生于 fastbin 类型的 chunk 当中。
Fastbin Attack 漏洞原理
fastbin attack 存在的原因在于 fastbin 是使用单链表来维护释放的堆块的,若一个 chunk 被释放之后进入 fastbin,那么其相邻下一个堆块的 prev_inuse 标志位不会被清空(prev_inuse 简写为 P,位于 size 的最低位,一般来说堆中第一个被分配的内存块的 size 字段的 P 位会被置 1,以便防止访问前面的非法内存。当一个 size 的 P 位置 0 时,我们就可以通过 prev_size 字段来获取上一个 chunk 的大小以及地址,这也方便进行 chunk 之间的合并)
我们来看一下 fastbin 是怎样管理空闲 chunk 的。
1 | int main(void) |
pwngdb 单步执行到 malloc 执行之后,free 之前:
1 | 0x602000: 0x0000000000000000 0x0000000000000041 <=== chunk1 |
执行三次 free(chunk)之后:
1 | 0x602000: 0x0000000000000000 0x0000000000000041 <=== chunk1 |
此时位于 main_arena 中的 fastbin 链表中已经储存了指向 chunk3 的指针,并且 chunk3,chunk2,chunk1 构成了一个单链表:
1 | Fastbins[idx=2, size=0x30,ptr=0x602080] |
当然这里还有一点问题,就是被释放的 chunk 为什么 prev_inuse 位迟迟不修改为 0:
1 | 只有当触发了 malloc_consolidate 时,这些 Fastbin 才会真正被合并入 Unsorted Bin。 |
Fastbin Double Free 漏洞利用
由于 fastbin 的 chunk 可以被多次释放,因此可以在 fastbin 链表中存在多次。这样导致的后果是可以多次分配从 fastbin 链表中取出一个堆块,相当于多个指针指向同一个堆块,结合堆块的数据内容可以实现类似于类型混淆的效果。
Fastbin Double Free 能够成功利用主要有两部分的原因
- fastbin 的堆块被释放后 next_chunk 的 pre_inuse 位不会被清空(这个前面提到过)
- fastbin 在执行 free 的时候仅验证了 main_arena 直接指向的块,即链表指针头部的块。对于链表后面的块,并没有进行验证。
1 | /* Another simple check: make sure the top of the bin is not the |
Fastbin Double Free 利用流程
1 | int main(void) |
我们直接在 linux 终端去运行程序,下面是 double free 导致程序崩溃爆出错误
1 | ➜ Desktop ./test2 |
如果我们在 chunk1 释放之后再释放 chunk2,这样子 main_arena 就指向 chunk2 而不是 chunk1,此时我们再释放 chunk1 就不会被爆 double free 导致程序崩溃了,我们可以修改一下 C 源代码:
1 | int main(void) |
第一次释放 chunk1 时main_arena 是指向 chunk1 的
第二次释放 chunk2 时根据 fastbin 的释放原则形成一个单链表结构
第三次释放 chunk1
由于 chunk1 时第二次被释放,因此其 fd 的值不再为 0 而是指向 chunk2,如果我们可以控制 chunk1 的内容,就可以写入其 fd 指针从而实现在任意地址分配 fastbin 块。
我们看下面一个例子:这是一个经典的 fastbin double free + 任意地址写入 利用代码,最终目的是让 malloc 返回到 &bss_chunk(全局变量地址)。
1 | typedef struct _chunk |
1 | typedef struct _chunk { |
1 | 初始: malloc(chunk1), malloc(chunk2) |
OK,通过以上陈述我们就以就大概了解这个程序 Double free 的运行流程了,下面我们可以通过 pwngdb 调试看一看程序堆内存具体的分布,去进一步了解程序的运行以及内存分配:
pwngdb 调试程序,直接运行到程序的最后一步,看到程序输出的 bss 段中的 bss_chunk :
1 | ──────────────────────────────[ DISASM / x86-64 / set emulate on ]────────────────────────────── |
直接查看堆内存的分布情况 x/50gx 0x601080 (后面的数据都是 0 就不放了)
1 | pwndbg> x/50gx 0x601080 |
1 | pwndbg> heap |
更新: 2026-04-23 15:18:27
原文: https://www.yuque.com/idcm/wnemg9/xt5r0lozxonquxxc