写在前面欢迎来到 Week14 的收官篇在过去的几篇中我们攻克了信息泄露、沙箱 ORW、无 Libc 环境等硬核技术。然而在实际 CTF 综合题中出题人常通过多进程和复杂栈管理设置最后障碍。今天我们将探讨fork 环境下的联动利用与栈残留数据挖掘这是区分熟练选手与顶尖选手的关键技术细节。掌握它们你就能在别人止步的地方继续向前。 目录fork 环境下的利用策略内存共享与漏洞叠加栈残留数据被遗忘的“信息金矿”综合实战ChecklistWeek14 技术全景图Week14 总结与下期预告1. fork 环境下的利用策略内存共享与漏洞叠加在服务器类 PWN 题中常用fork创建子进程处理请求。这为我们提供了独特的利用机会。1.1 fork 的内存模型共享与差异当父进程调用fork后子进程是父进程的完整副本但采用写时复制技术。这意味着共享阶段fork后子进程的内存内容与父进程完全相同包括堆、栈、libc 数据段。地址空间布局也一致。写时复制一旦子进程或父进程修改了某页内存内核会为该页创建副本此后两者不再共享该页。1.2 利用策略利用共享内存泄露信息在 fork 模型中我们可以利用“共享”特性进行信息泄露。泄露堆地址父进程释放一个堆块进入 Unsorted Bin其fd/bk指向main_arena88。子进程继承此堆状态可通过 UAF 读取该指针从而泄露 Libc 基址。泄露栈地址父进程的栈帧如 RBP、返回地址被子进程继承。子进程通过栈溢出或格式化字符串可读取父进程栈上的残留数据甚至包括父进程的 Libc 返回地址从而精确计算栈基址。1.3 经典模型父子进程漏洞叠加更复杂的题目会设计父子进程漏洞叠加。父进程漏洞存在栈溢出但只能覆盖返回地址无法构造完整 ROP 链如缺少 gadgets。子进程漏洞存在 UAF 或格式化字符串可泄露地址。联动利用子进程通过漏洞泄露父进程栈地址或 Libc 地址。子进程将泄露信息通过管道或共享内存传递给父进程。礪进程利用泄露的地址在子进程返回时精准覆盖父进程的返回地址构造完整 ROP 链执行system(/bin/sh)或 ORW。父进程: 请求处理子进程: 存在格式化字符串漏洞子进程泄露父进程栈地址子进程将栈地址写入共享内存/管道父进程读取共享信息父进程利用栈溢出泄露地址构造完整 ROP 链父进程 Getshell子进程: 存在 UAF 漏洞子进程泄露 Libc 地址子进程将 Libc 地址写入共享内存2. 栈残留数据被遗忘的“信息金矿”函数调用结束后栈帧虽然被“弹出”但栈上的数据并未清零。这些残留数据往往是极有价值的信息泄露源。2.1 残留数据来源旧函数调用残留函数A调用函数BB返回后B的栈帧数据仍残留在原位置。当函数C被调用且复用该栈区时C的局部变量会初始化这些残留数据。初始化未清零的缓冲区gets或read读取输入时若输入长度小于缓冲区多余部分会保留旧数据。系统调用残留某些系统调用如stat返回后参数缓冲区可能残留内核数据。GDB 调试残留在某些题目中GDB 调试过程中可能改变内存状态导致本地能利用但远程失败需注意调试器污染。父进程残留在 fork 模型中父进程的栈数据会残留给子进程。libc 残留libc 函数调用后其内部临时栈帧可能残留指针。环境变量/参数残留main函数的argv和envp指针通常位于栈底如果程序误读这些指针可能泄露栈基址。初始化为零的内存虽然不完全是“残留”但初始化为零的内存如bss段在首次使用时其值为零这可用于构造特定条件如_lock指针需指向零值内存。2.2 实战利用案例案例1利用残留的 Libc 指针泄露基址假设程序流程为init()函数调用setvbuf设置缓冲区期间在栈上分配了临时缓冲区并存放了 libc 指针。init()返回栈帧弹出但指针数据残留。vuln()函数被调用复用同一栈区其局部变量char buf[0x20]初始化了残留数据。程序执行printf(buf)由于buf未以 null 结尾printf会持续打印直到遇到 null 字节从而泄露残留的 libc 指针。案例2利用残留栈指针实现栈迁移函数A存在栈溢出但只能覆盖返回地址无法覆盖足够长度进行 ROP。函数A返回后栈上残留了旧 RBP 指针。函数B被调用复用该栈区。函数B存在格式化字符串漏洞可泄露栈上残留的旧 RBP从而推算出栈基址。利用泄露的栈地址我们可以在堆上伪造一个栈帧并通过栈迁移技术将执行流转移到伪造栈帧上执行 ROP 链。2.3 棘手情况栈上无可用残留数据有时栈上确实没有可用的残留数据。此时需考虑以下策略主动制造残留在vuln之前通过其他函数调用在栈上留下有价值的指针如通过调用read读取数据到栈上然后返回。利用堆残留将残留数据从堆上迁移到栈上。例如通过 UAF 读取堆上的 libc 毞针然后通过栈溢出将该指针覆盖到栈上再利用格式化字符串泄露该栈地址。利用环境变量在main函数之前的初始化阶段环境变量和程序参数存储在栈底。如果程序误读这些指针可能泄露栈基址。接受“无泄露”现实在某些极端题目中可能需要放弃泄露直接采用爆破或ret2dlresolve等无需泄露的技术。利用 libc 内部残留某些 libc 函数调用后其内部临时栈帧可能残留指针。例如malloc调用后其分配的 chunk 头部可能残留堆地址。通过 UAF 读取该 chunk可泄露堆地址。3. 树立综合实战思维Week14 技术全景图将 Week14 学到的所有技术整合成一张实战流程图是打综合题的核心思维。栈溢出/UAF/格式化字符串是是否否有无是否是漏洞点触发漏洞类型判断信息泄露泄露 Libc/堆/栈地址是否有沙箱?沙箱分析seccomp-tools dumpopen 被禁?openat 替代或 /proc/self/mem基础 ORW ROPGet Flag是否有 Libc?ret2libc: system/execvePartial RELRO?got2plt 半盲劫持ret2dlresolve 或 ret2mprotectGetshell多进程环境?父子进程联动利用利用残留数据或共享内存构造完整 ROP 链4. Week14 总结与下期预告4.1 核心知识点总结fork 联动利用利用子进程继承父进程内存的特性通过共享内存泄露地址或通过子进程漏洞为父进程利用铺路。栈残留数据函数返回后栈帧未清零旧数据可能泄露 Libc/堆/栈地址或用于构造栈迁移条件。综合实战思维将信息泄露、沙箱 ORW、无 Libc 破局、多进程联动等技术系统化整合根据题目环境灵活组合。技术选型决策树根据漏洞类型、沙箱规则、Libc 可得性、RELRO 状态、进程模型等条件选择最优利用路径。“无泄露”应对策略在无可用残留数据时主动制造残留、利用堆残留迁移、或采用无需泄露的技术ret2dlresolve、ret2mprotect。Checklist 应用将信息泄露、沙箱分析、ORW 构造、GOT 劫持、ret2mprotect等步骤系统化成 Checklist打题时按图索骥极大提升效率。工具链整合熟练使用seccomp-tools、pwntools的Ret2dlresolvePayload、ROPgadget琁工具是现代 CTF PWN 的必备技能。环境适配思维根据远程环境glibc 版本、内核版本、保护机制动态调整利用策略是成熟 PWN 选手的标志。“最后一公里”思维在技术方案确定后如何精准控制寄存器、处理栈对齐、利用残留数据往往是决定成败的关键细节。4.2 下期预告在 Week14 的综合实战体系中我们经常需要根据远程环境动态调整利用策略。但这一切的基础是拥有一个稳定且可复现的调试环境。在 Week15 中我们将深入工具链整合与环境适配。patchelfglibc-all-in-one一键切换 Libc 版本模拟远程环境。pwninit GDB 脚本自动化秒级初始化 PWN 题调试环境。angr符号执行辅助解决复杂的路径约束问题。Docker 复现环境搭建与远程完全一致的调试环境。内核 PWN 入门理解用户态与内核态的区别搭建 Kernel PWN 调试环境。结语从信息泄露到 ORW从无 Libc 破局到多进程联动Week14 为你构筑了现代 CTF PWN 的完整技术体系。但记住技术只是工具真正的核心是系统化的利用思维。当你能将所有技术点融会贯通根据题目环境灵活组合时你将无往不利。