Chunk Extend & Overlapping
参考资料:https://ctf-wiki.org/pwn/linux/user-mode/heap/ptmalloc2/chunk-extend-overlapping/
[https://blog.csdn.net/weixin_43921239/article/details/107841328](https://blog.csdn.net/weixin_43921239/article/details/107841328)
tip) 一开始程序运行没有及时更换 libc,可能导致 bin 类型有一点点出入,但是对于示例没有太大的影响
什么是chunk extend
在日常的比赛中,常常会需要我们构造一个overlapping chunk,即一个重叠的chunk使chunk重叠
作用是泄露地址(libc/heap)泄露数据(泄露已经释放的堆中的数据/泄露chunk中的内容),覆盖指针
利用条件:1.程序中存在堆的漏洞 2.漏洞可以控制chunk header中的数据
chunk extend原理
chunk extend技术能够产生的原因在于** ptmalloc(glibc 的内存分配器)的堆块管理机制在设计上存在漏洞**
核心原因是通过修改chunk的size段,使得内存分配器对该堆块的大小认知与实际物理布局产生不一致。攻击者利用这种不一致,让一个堆块”扩展”到相邻堆块的空间,从而实现对相邻堆块内容的越界读写。
ptmalloc 通过 chunk header 的数据判断 chunk 的使用情况和对 chunk 的前后块进行定位。简而言之,chunk extend 就是通过控制 size 和 pre_size 域来实现跨越块操作从而导致 overlapping 的。
对inuse的fastbin进行extend
先看一下示例的源码
1 | int main(void) |
1 | 低地址 高地址 |
1 | 用户指针ptr指向用户数据区的开始 |
图标实例
先用图表的形式来清晰地展示堆扩展,这样有助于去gdb的调试和理解


gdb调试查看程序运行过程
尽管图标已经把程序过程说的很清晰了,但是自己用gdb去动手调试是必不可少的,这样我们可以更清晰地理解堆的变化情况。下面我们用gdb进行调试并在第8行下断点运行
1 | ------- tip of the day (disable with set show-tips off) ------- |
查看一下新创建的heap的起始地址,我们可以看到0x62290是新创建的堆起始地址,接下来查看堆段的内存地址
1 | pwndbg> heap |
我们可以直接来看一下heap,找到我们新分配的两个堆

1 | pwndbg> x/20gx 0x602290 |
程序执行力malloc(0x10),并且prev_size和size部分各占8个字节,而size记录整个堆块大小,size最后一位用来记录前一个堆的状态,所以堆块的总大小为:
SIZE=0x08(prev_size)+0x08(size)+0x10(malloc-user_data)+0x1(标志位)=0x21
查看P指针指向的地址,执行info local可以看到p指针指向user_data的起始位置,这里和我们上面图标内容也是相符合的,即定义的指针是指向chunk的user_data的
1 | pwndbg> info local |
我们继续查看情况,我们在第九行下断点,continue执行
1 | pwndbg> b 9 |
这个时候程序已经执行过了 *(long long *)((long long)ptr-0x8)=0x41;代码,我们可以看一下堆内容
1 | pwndbg> x/20gx 0x602290 |
此时我们可以发现,size段已经被修改为41了,这就意味着除去prev_size和size段一共0x10个字节外剩下的全部都是user_data段,也就是0x30个字节,覆盖到0x6022c0处,也急速hi说chunk2被chunk1包含,造成了堆重叠
我们再在第十行设置断点,单步ni执行到free(p)之后
1 | 0x40058a <main+36> sub rax, 8 RAX => 0x602298 (0x6022a0 - 0x8) |
这个时候已经执行过了free(p),查看bin内容
1 | pwndbg> heap |
这个时候我们可以看到堆中的内容并没有被清空,free(p)只是将目标的堆内存标记为释放状态,其内容并没有被清空,这个和我们在UAF中所学的知识是一样的,我们接下来可以看看第十一行执行后的情况,继续单步执行
1 | b+ 0x400595 <main+47> mov rax, qword ptr [rbp - 0x10] RAX, [0x7fffffffdf10] => 0x6022a0 ◂— 0 |
1 | pwndbg> bins |
当我们重新申请一个大小为0x30的chunk时,bin中刚好有大小合适的chunk,这时候chunk1与chunk2合并的新chunk1就会被重新启用,启用的同时chunk2中原有的数据也会连带着被启用,然后就可以直接通过这个新申请的块对chunk2中的内容进行操作了。
对 free 的 smallbin 进行操作
1 | int main() |

我们先在第一行下断点,然后单步执行到两次 malloc 执行之后
1 | ──────────────────────────────[ DISASM / x86-64 / set emulate on ]────────────────────────────── |
我们继续单步执行到 free 执行之后看一看堆空间的分布情况
1 | ───────────────────────────────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────────────────────────────────────────────────────────────────── |
释放后的 chunk1 进入了 tcachebins,我们看一看执行完 *(int *)((int)ptr-0x8)=0xb1;之后的堆内存,单步执行
1 | ──────────────────────────────[ DISASM / x86-64 / set emulate on ]────────────────────────────── |
执行完修改 size 如上,此时再进行 malloc 分配就可以得到 chunk1+chunk2 的堆块,从而控制 chunk2 的内容
Chunk Extend 可以做什么?
当你可以控制 chunk 中的内容时,加入该 chunk 中存在字符串指针,函数指针等,就可以通过这些指针进行信息泄露和控制执行流程。此外 extend 可以实现 chunk overlapping,通过 overlapping 可以控制 chunk 的 fd/bk 指针,从而实现 fastbin attack 等利用
通过 extend 后向 overlapping
这里展示通过 extend 进行后向 overlapping,这也是在 CTF 中最常出现的情况,通过 overlapping 可以实现其它的一些利用。一下是示例源代码
1 | int main() |
在 malloc(0x50) 对 extend 区域重新占位后,其中 0x10 的 fastbin 块依然可以正常的分配和释放,此时已经构成 overlapping,通过对 overlapping 的进行操作可以实现 fastbin attack。
通过 extend 前向 overlapping
这里展示通过修改 pre_inuse 域和 pre_size 域实现合并前面的块
1 | int main(void) |
前向 extend 利用了 smallbin 的 unlink 机制,通过修改 pre_size 域可以跨越多个 chunk 进行合并实现 overlapping。
pre_size, 如果该 chunk 的物理相邻的前一地址 chunk(两个指针的地址差值为前一chunk 大小)是空闲的话,那该字段记录的是前一个 chunk 的大小 (包括 chunk 头)。否则,该字段可以用来存储物理相邻的前一个 chunk 的数据。这里的前一chunk 指的是较低地址的 chunk 。前面一个堆块在使用时并且pre_size为储存前面chunk的数据时,他的值始终为 0
size字段中的P(PRE_INUSE):记录前一个 chunk 块是否被分配。一般来说,堆中第一个被分配的内存块的 size 字段的 P 位都会被设置为 1,以便于防止访问前面的非法内存。当一个 chunk 的 size 的 P 位为 0 时,我们能通过 prev_size 字段来获取上一个 chunk 的大小以及地址。这也方便进行空闲 chunk 之间的合并。
更新: 2026-01-11 17:49:55
原文: https://www.yuque.com/idcm/wnemg9/fii6vgn27lmxk5qp