【学习记录】Week15(四):多漏洞叠加与纯 ROP 艺术一一综合实战的巅峰对决

发布时间:2026/7/5 17:17:07
【学习记录】Week15(四):多漏洞叠加与纯 ROP 艺术一一综合实战的巅峰对决 写在前面欢迎来到 Week15 的压轴篇经过前三篇的砺炼我们已经掌握了栈溢出、格式化字符串、UAF 与 Tcache 的独立利用。然而现代 CTF 的高分 PWN 题早已不再是“单打独斗”的舞台。出题人往往会将多个漏洞揉合在一个程序中并辅以沙箱、去符号表等严苛限制。今天我们将探讨如何将fmt、UAF、ORW等技术串联成完整的攻击链并在没有堆漏洞的情况下利用纯 ROP 完成沙箱逃逸与 Flag 读取。 目录循环的艺术loop 型 fmtstr 综合利用终极组合拳fmt UAF ORW 全链路打通盲人摸象无符号漏洞与 Heap 的结合纯粹的执行流无 Heap 漏洞的纯 ROP ORWWeek15 总结与下期预告1. 循环的艺术loop 型 fmtstr 综合利用在基础题中格式化字符串漏洞往往只能触发一次如printf(buf); exit(0);。但在综合题中常存在while(1)循环不断接收输入并触发printf。这赋予了我们强大的“无限写”与“无限读”能力。1.1 劣势反转从单次到无限单次 fmtstr 的痛点在于我们需要在栈上找到指向栈自身的指针才能实现任意地址写。而 loop 型 fmtstr 彻底解决了这个问题第一步泄露栈基址。通过%p泄露栈上的旧 RBP 或返回地址计算出当前栈帧的绝对地址。第二步布置目标地址。通过read将我们要写的目标地址如 GOT 表项、__free_hook写入栈上的某个已知偏移。第三步精准写入。利用%N$n将上一步布置在栈上的地址作为指针写入数据。1.2 实战场景劫持printf的返回地址当程序开启了 Full RELROGOT 表不可写时我们可以通过 loop 型 fmtstr 直接篡改栈上的返回地址。泄露栈地址与 Libc 基址。在栈上布置一段可写的内存地址如 bss 段或栈本身。利用%n将 ROP 链逐个字节或双字写入该栈地址。当循环结束时程序返回到我们伪造的 ROP 链上。2. 终极组合拳fmt UAF ORW 全链路打通设想这样一道“缝合怪”题目菜单题存在 UAF 漏洞。程序中某处存在格式化字符串漏洞如打印堆块内容时用了printf(chunk_ptr)。开启了 Seccomp 沙箱禁用execve。glibc 2.34无 Hook。2.1 攻击链路规划面对这种题目我们需要用 fmtstr 辅助 UAF最终走向 ORW。触发 fmtstr 漏洞泄露 Libc 基址与堆基址利用 UAF 构造 Tcache Poisoning劫持 _IO_list_all 或 stdout伪造 FILE 结构体 (House of Apple)利用 IO 伪造实现栈迁移执行布置在堆上的 ORW ROP 链读取 Flag2.2 细节剖析信息泄露UAF 释放进 Unsorted Bin 可以泄露 Libc但如果有其他干扰堆块利用 fmtstr 读取栈上的 Libc 残留往往是更稳定的手段。栈迁移的桥梁在 glibc 2.34 中UAF 劫持_IO_list_all后利用 House of Apple 2/3 可以调用setcontext或 ROP gadget。但 ROP 链写在哪我们可以利用 UAF 分配一块堆内存将 ORW 的 ROP 链写在堆上然后通过伪造 IO 结构体的_IO_save_base或利用_IO_wfile_overflow链中的leave; retgadget将 RSP 迁移到堆上执行 ORW。3. 盲人摸象无符号漏洞与 Heap 的结合当题目使用strip去除符号表时IDA 中只能看到sub_XXX我们无法直接通过elf.symbols[system]获取地址。3.1 静态分析与动态定位字符串定位法通过查看程序的字符串引用如/bin/sh、菜单文字反向定位main函数和各个功能函数。偏移特征法无符号的 libc 函数在 PLT 表中的跳转是有规律的。通过 GDB 动态调试x/10i 0x401020假设是某个 PLT 表项可以识别出这是puts还是malloc。堆结构特征即使没有符号我们依然可以通过释放堆块后的fd指针变化确认它是 Tcache (glibc 2.26) 还是 Fastbin (老版本)。3.2 无符号下的 ORW 构造在无符号环境下找 ROP gadget 极其困难。此时的核心策略是利用泄露出真实地址的 libc 函数在 libc 中寻找 gadget。只要通过 fmtstr 或 UAF 泄露了puts的真实地址查 Libc 数据库得知 libc 版本接下来所有的 gadget (pop rdi; ret,syscall; ret) 全部从 libc 中提取而不再依赖主程序。4. 纯粹的执行流无 Heap 漏洞的纯 ROP ORW有些题目没有堆操作只有纯粹的栈溢出且开了沙箱。由于execve失效我们必须构造 ORW 链。但这往往面临一个致命痛点程序本身太短找不到pop rdx; ret和syscall; ret。4.1 ret2csu 控制参数主程序中通常包含__libc_csu_init利用其中的 gadget 可以控制rdi, rsi, rdx。mov rdx, r14 mov rsi, r13 mov edi, r12d call [r15]通过这段代码我们可以调用read(0, bss_addr, 0x100)将我们的 Shellcode 或后续的 ROP 链读到 bss 段。4.2 ret2mprotect 执行 Shellcode既然能控制read为什么不用mprotect给 bss 段加上执行权限呢利用 ret2csu 调用mprotect(bss_page_addr, 0x1000, 7)(7 RWX)。利用 ret2csu 调用read(0, bss_addr, len)输入 ORW 的 Shellcode。通过jmp bss_addr跳转执行。4.3 纯 ROP 的 ORW 替代方案如果连mprotect的 PLT 都没有但程序中残留了__libc_start_main的地址通常在栈底我们可以部分覆盖它将其偏移到 libc 中的syscall; ret附近从而获得syscall指令再配合 ret2csu 完成纯 ROP 的 ORW。5. Week15 总结与下期预告5.1 核心知识点总结多漏洞协同fmtstr 用于信息泄露和绕过限制UAF 用于内存控制ORW 作为最终执行手段。根据题目环境三者可以灵活组合。loop 型 fmtstr赋予了攻击者任意地址写的绝对主动权是 Full RELRO 下的栈劫持利器。无符号对策静态特征识别结合动态调试将目光从主程序转向 libc利用 libc 中的庞大 gadget 库完成利用。纯 ROP 突破在缺乏 gadget 时__libc_csu_init(ret2csu) 是控制参数的万能钥匙结合mprotect可以完美降维打击 ORW 需求。5.2 Week16 预告历经 Week15 的综合实战我们对用户态的漏洞利用已驾轻就熟。下周我们将开启全新的篇章——工具链整合与内核 PWN 入门。工程化武器库pwninit自动化环境搭建、patchelf与glibc-all-in-one的无缝切换、GDB 脚本编写。符号执行辅助使用angr解决复杂的路径约束与迷宫类题目。内核初探从用户态跨入内核态理解 Ring 0 与 Ring 3 的边界。Kernel 环境搭建使用 QEMU GDB 调试 Linux 内核。ret2usr 攻击利用用户态进程“刺杀”内核的经典操作。结语多漏洞叠加题目就像是一组拼图单独看每一块都不复杂难点在于如何根据拼图的边缘漏洞触发的条件和限制将它们严丝合缝地拼接在一起。本周的综合训练到此结束当你能独立打通一条从信息泄露到 ORW 的全链路时你已经具备了在大型赛事中稳定拿分的能力。下周我们将升级我们的武器库向内核发起冲锋