堆溢出攻击实现方式及GDB调试元数据异常问题咨询
堆溢出攻击相关问题解答
一、为什么调试malloc分配的内存时未找到函数指针类元数据?
现代Linux系统默认使用的ptmalloc2(glibc内存分配器)中,函数指针类元数据不会存储在已分配的chunk头部/尾部,而是存在以下位置:
- Free chunk结构:chunk被free后会加入fastbin、tcache或unsorted bin等链表,此时chunk头部包含
fd(向前指针)和bk(向后指针)用于维护链表——这些指针虽不是直接函数指针,但可被篡改实现流程劫持。 - 全局钩子函数:比如
__malloc_hook、__free_hook,属于malloc分配器的全局元数据,存储在固定内存区域,而非单个chunk内。 - Arena管理结构:内存分配器的arena中包含管理内存池的相关指针,同样不在单个已分配chunk中。
你调试时看到的仅为已分配chunk的元数据(prev_size和size字段),这类chunk本身不需要链表指针,自然看不到函数指针类数据。若要查看相关元数据,需调试被free后的chunk,或查看malloc全局钩子的地址。
二、堆溢出攻击的核心实现逻辑
堆溢出攻击的本质是超出分配内存边界,覆盖相邻区域的敏感元数据,进而劫持程序执行流,核心路径包括:
- 篡改free chunk链表指针:通过溢出覆盖free chunk的
fd/bk指针,让后续malloc调用返回恶意地址(如shellcode地址、全局函数表项地址)。 - 利用tcache/fastbin特性:针对ptmalloc2的tcache(小对象缓存)或fastbin(快速链表),通过溢出修改链表结构实现“缓存投毒”,让malloc分配到指定恶意地址。
- 覆盖自定义结构体函数指针:若程序自身维护的堆结构体包含函数指针(如回调函数指针),溢出可直接篡改该指针,程序调用该函数时执行恶意代码。
- 劫持全局钩子函数:通过溢出覆盖
__free_hook或__malloc_hook的地址,将其指向shellcode,后续调用free/malloc时触发恶意代码执行。
三、堆溢出攻击复现步骤(以Linux ptmalloc2 + 32位程序为例)
1. 环境准备
关闭内存地址随机化(ASLR):
echo 0 > /proc/sys/kernel/randomize_va_space
编译带漏洞的程序,关闭栈保护、RELRO、PIE等防护:
gcc -m32 -fno-stack-protector -z norelro -no-pie vuln.c -o vuln
2. 编写漏洞程序(vuln.c)
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { // 分配两个相邻的小chunk char *ptr1 = malloc(0x20); char *ptr2 = malloc(0x20); // 堆溢出:向ptr1写入超过0x20字节的数据,覆盖ptr2的chunk头部 strcpy(ptr1, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); // free ptr2时,被篡改的chunk元数据会被加入链表 free(ptr2); // 后续malloc会返回被篡改的地址 char *malicious_ptr = malloc(0x20); return 0; }
3. GDB调试复现
- 启动GDB加载程序:
gdb ./vuln
- 设置断点并运行:
b main r
- 查看初始堆布局:
x/40x ptr1
此时可看到ptr1和ptr2的相邻内存地址,以及各自的chunk头部(size字段)。
4. 执行strcpy后,查看ptr2的chunk头部是否被篡改:
x/8x ptr2
会发现ptr2的size字段已被溢出数据覆盖。
5. 进一步修改payload实现流程劫持:
将溢出数据改为包含__free_hook地址的内容,让free ptr2时将__free_hook指向shellcode,后续调用free即可触发shell。
内容的提问来源于stack exchange,提问作者ho tian
相关产品推荐
相关产品推荐

