CTF_pwn_堆入门知识及例题分析
字数 2836 2025-08-24 07:48:33
堆漏洞利用全面指南
1. 堆基础知识
1.1 堆概述
堆是一种线性分布的数据结构,与栈不同,堆由低地址向高地址伸展。堆位于bss段的高地址处,提供动态内存分配功能。Linux标准发行版使用glibc中的ptmalloc2作为堆分配器,通过malloc/free函数管理内存。
1.1.1 堆数据结构与操作
-
malloc流程:
malloc→__libc_malloc→_int_malloc- 首先检查
__malloc_hook,然后调用_int_malloc进行实际分配
-
free流程:
free→__libc_free→_int_free- 检查是否为fastbin、mmap分配等,然后进行合并操作
1.1.2 系统调用
- brk/sbrk:扩展堆空间的主要系统调用
- mmap/munmap:用于大内存分配和释放
1.2 Chunk结构
struct malloc_chunk {
INTERNAL_SIZE_T mchunk_prev_size; // 前一个chunk的大小(如果空闲)
INTERNAL_SIZE_T mchunk_size; // 当前chunk大小+标志位
struct malloc_chunk *fd; // 前向指针(fastbins/smallbins)
struct malloc_chunk *bk; // 后向指针(smallbins/largebins)
struct malloc_chunk *fd_nextsize; // 大chunk的前向指针
struct malloc_chunk *bk_nextsize; // 大chunk的后向指针
};
1.3 Bin分类
-
Fast bins:
- 单链表结构,LIFO(后进先出)
- 大小范围:32-128字节(0x20-0x80)
- 不合并相邻空闲chunk
-
Small bins:
- 双向循环链表,FIFO(先进先出)
- 大小范围:32-1024字节(0x20-0x400)
-
Large bins:
- 双向循环链表,按大小排序
- 大小大于1024字节(0x400)
-
Unsorted bin:
- 双向循环链表
- 释放的chunk先放入此处,作为"垃圾桶"
1.4 Arena
- main_arena:主线程的堆区域
- thread arena:子线程的堆区域,可以有多个
- 包含堆的管理结构和各种bin的指针
2. 堆漏洞类型
2.1 堆溢出
当向堆块写入超过其可用大小的数据时发生,可以覆盖相邻堆块的数据。
利用条件:
- 程序向堆写入数据
- 写入大小未正确控制
- 可以覆盖相邻chunk的关键数据
利用方法:
- 覆盖下一个chunk的size字段
- 修改fd/bk指针实现任意地址读写
- 通过unlink等机制实现控制流劫持
2.2 Use-After-Free (UAF)
释放后继续使用堆指针,分为:
- 指针被置NULL后使用 → 崩溃
- 指针未置NULL且内存未被修改 → 可能正常执行
- 指针未置NULL且内存被修改 → 可利用漏洞
典型利用场景:
- 释放后重新分配,修改函数指针等关键数据
- 结合其他漏洞实现控制流劫持
2.3 Double Free
同一块内存被多次释放,可能导致:
- 内存管理数据结构损坏
- 实现任意地址读写
3. 堆利用技术
3.1 信息泄露
目标:
- 堆基地址
- libc基地址
泄露方法:
-
通过unsorted bin泄露:
- 当unsorted bin只有一个chunk时,其fd/bk指向main_arena
libc_base = fd_addr - 0x58 - 0x3c4b20(偏移可能因版本不同)
-
通过fast bin泄露:
- 利用fast bin的单链表特性泄露堆地址
漏洞利用:
- 堆内存未初始化
- 堆溢出
- UAF
- 越界读
- heap extend
3.2 Fastbin Attack
原理:
利用fast bin的单链表特性,通过修改fd指针实现任意地址分配。
步骤:
- 分配并释放fast chunk
- 通过漏洞修改fd指针指向目标地址
- 再次分配获取目标地址的控制权
绕过检测:
- 目标地址的size字段需要满足:
- 大小在fast bin范围内
- PREV_INUSE位为1
示例:
# 分配两个fast chunk
p0 = malloc(0x20)
p1 = malloc(0x20)
# 释放
free(p0)
free(p1)
# 修改p1的fd指向目标地址
# 需要确保目标地址的size字段满足条件
p1.fd = target_addr
# 重新分配
malloc(0x20) # 得到p1
malloc(0x20) # 得到target_addr
3.3 Unsorted Bin Attack
原理:
通过修改unsorted bin中chunk的bk指针,实现向任意地址写入一个大数值。
利用场景:
- 通常用于配合fastbin attack构造合适的size字段
- 可以用于修改全局变量等
步骤:
- 分配并释放一个unsorted bin大小的chunk
- 修改其bk指针指向目标地址-0x10
- 再次分配触发写入
3.4 __malloc_hook攻击
原理:
将__malloc_hook修改为one_gadget或system地址,在调用malloc时获取shell。
步骤:
- 泄露libc基地址
- 计算
__malloc_hook和one_gadget地址 - 通过fastbin attack修改
__malloc_hook- 通常使用
__malloc_hook-0x23处的伪造size(0x7f)
- 通常使用
3.5 House of Spirit
原理:
在任意地址构造fake chunk并free,使其进入fast bin,然后重新分配实现控制。
条件:
- 能在目标地址附近构造合法的fake chunk
- 能够控制free的指针
4. 实战案例分析
4.1 babyheap解题思路
-
泄露libc基地址:
- 创建fast chunk和unsorted chunk重叠
- 释放unsorted chunk后通过fast chunk泄露地址
-
fastbin attack修改__malloc_hook:
- 计算合适的fake chunk位置(
__malloc_hook-0x23) - 通过修改fd指针实现控制
- 计算合适的fake chunk位置(
-
写入one_gadget:
- 计算偏移正确写入one_gadget地址
4.2 hacknote解题思路
-
UAF漏洞利用:
- 申请两个note并释放
- 重新申请小note覆盖函数指针
-
控制流劫持:
- 将打印函数指针覆盖为shell地址
- 调用打印函数实际执行shell
4.3 easyheap解题思路
-
House of Spirit:
- 在bss段构造fake chunk
- 通过堆溢出修改指针
-
GOT劫持:
- 修改free的GOT表项为system
- 释放包含"/bin/sh"的chunk
5. 防御措施
-
安全机制:
- 堆Cookie
- Safe-Linking (glibc 2.32+)
- tcache hardening
-
开发建议:
- 及时置空释放的指针
- 严格检查输入大小
- 使用现代内存分配器
-
缓解技术:
- 地址随机化(ASLR)
- 堆隔离
- 敏感数据加密
6. 调试技巧
-
gdb命令:
# 查看堆 x/40gx 0x555555757000 # 查看fast bins heap bins fast # 查看unsorted bin heap bins unsorted -
关键断点:
_int_malloc_int_free__malloc_hook__free_hook
-
有用工具:
- pwndbg
- gef
- libc-database
- one_gadget
7. 扩展知识
-
tcache (glibc 2.26+):
- 每个线程的缓存,提高分配速度
- 引入新的安全机制和攻击面
-
不同glibc版本的差异:
- 安全机制增强
- 偏移变化
- 数据结构调整
-
其他堆分配器:
- jemalloc
- mimalloc
- tcmalloc
通过系统学习这些堆利用技术和防御措施,可以更好地理解现代堆漏洞的利用方式和防护方法。实际应用中需要结合具体环境和保护机制进行调整。