Protostar二进制靶场堆溢出题目原理及基础解析
字数 1503 2025-08-29 08:30:31
堆溢出漏洞原理与利用技术详解
一、堆基础概念
堆是动态内存分配的区域,程序在运行时用来分配内存。与栈不同,堆具有以下特点:
- 使用如
malloc、calloc、realloc等函数动态分配内存 - 使用
free函数释放不再需要的内存 - 大小不固定,可以动态增长
堆内存分配示例:
char *buffer = (char *)malloc(64); // 分配64字节堆内存
free(buffer); // 释放内存
二、堆溢出漏洞原理
1. 基本堆溢出
漏洞通常发生在不安全的字符串操作函数如strcpy处:
strcpy不会检查目标缓冲区大小- 当输入超过目标缓冲区大小时会导致缓冲区溢出
- 可能覆盖关键数据结构如函数指针
利用步骤:
- 确定目标缓冲区大小
- 构造超出缓冲区大小的输入
- 覆盖关键数据(如函数指针)
- 控制程序执行流
2. Use-After-Free (UAF)漏洞
定义:程序释放了一块内存后再次错误地使用这块内存的情况。
发生条件:
- 内存被释放(通过
free函数) - 释放后程序仍尝试访问该内存
- 内存可能被重新分配给其他用途
危害:
- 可能导致程序行为异常
- 可能造成数据损坏或信息泄露
- 可能允许执行任意代码
3. Fastbins机制
在glibc的ptmalloc分配器中:
- 小于64字节的块使用Fastbins管理
- Fastbins是单向链表,不同于常规双向链表
- 忽略
prev_size、bk和size位 - 分配和释放速度更快但安全性较低
三、堆管理数据结构
malloc_chunk结构
在malloc.c中定义的内存块结构:
chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Size of previous chunk, if unallocated (P clear) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Size of chunk, in bytes |A|M|P|
mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| User data starts here... .
. .
. (malloc_usable_size() bytes) .
. |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| (size of chunk, but used for application data) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Size of next chunk, in bytes |A|M|P|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
关键字段:
prev_size: 前一个块的大小(如果前一个块空闲)size: 当前块大小,包含标志位A: NON_MAIN_ARENA标志M: IS_MMAPPED标志P: PREV_INUSE标志
空闲块管理
空闲块使用双向链表管理,包含:
fd(forward pointer): 指向下一个空闲块bk(backward pointer): 指向前一个空闲块
四、unlink操作原理
unlink是从双向链表中移除空闲块的操作:
#define unlink(P, BK, FD) {
FD = P->fd;
BK = P->bk;
FD->bk = BK;
BK->fd = FD;
}
unlink攻击条件:
- 能控制
P->fd和P->bk的值 (P->fd)+12和(P->bk)+8必须是可写内存
攻击效果:
- 可以覆盖任意内存
- 通常用于覆盖GOT表条目
五、实战漏洞利用
1. 基础堆溢出利用
步骤:
- 确定缓冲区大小和偏移
- 构造溢出payload覆盖函数指针
- 将函数指针指向目标地址(如
winner函数) - 触发函数调用
示例:
echo -e "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x74\x97\x04\x08" > payload
./vulnerable_program $(cat payload)
2. UAF漏洞利用
步骤:
- 分配并释放目标内存
- 重新分配相同大小内存并填充控制数据
- 利用残留指针访问被释放内存
- 修改关键数据(如认证标志)
示例:
auth AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
reset
service BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
login
3. unlink攻击利用
步骤:
- 构造伪造的堆块结构
- 设置
fd和bk指向目标地址 - 触发unlink操作
- 覆盖GOT表条目
关键点:
- 使用负数size(如
0xfffffffc) - 精确计算偏移量
- 选择合适的目标地址(通常是GOT表)
六、防护措施
-
使用安全函数替代不安全函数:
strncpy替代strcpysnprintf替代sprintf
-
启用堆保护机制:
GLIBC_SECURE_MALLOC- 堆cookie/canary
-
及时清空指针:
- 释放内存后将指针置为NULL
-
使用现代内存分配器:
- jemalloc
- tcmalloc
-
启用ASLR和DEP保护
七、调试技巧
-
GDB常用命令:
break *0x080485a1 # 设置断点 x/32wx 0x0804a000 # 查看堆内存 info proc mappings # 查看内存映射 -
自动化调试:
define hook-stop x/32wx 0x0804a000 end -
查看堆块信息:
p *(struct malloc_chunk*)0x0804a008 -
跟踪函数调用:
catch syscall exit
通过深入理解堆管理机制和常见漏洞模式,可以更有效地发现和利用堆相关漏洞,同时也能更好地防护此类安全问题。