如何使用GDB 14.2在缓冲区溢出实验中定位并覆盖EIP(附CTF挑战代码)
我来给你一步步拆解怎么用GDB 14.2搞定这个缓冲区溢出CTF题,先看看你提供的这段目标代码:
#define _GNU_SOURCE #include <stdio.h> #include <string.h> #include <unistd.h> int my_gets(char *buf) { int i = 0; char c; while (read(0, &c, 1) > 0 && c != '\n') { buf[i++] = c; } buf[i] = '\0'; return i; } int main() { int cookie; char buf[16]; printf("&buf: %p, &cookie: %p\n", buf, &cookie); my_gets(buf); return 0; }
这段代码里的my_gets是个完全没做边界检查的不安全读取函数,刚好给了我们缓冲区溢出的机会。下面是具体操作步骤:
第一步:编译代码(关闭栈保护)
首先得把代码编译成调试友好的版本,默认的栈保护机制会阻碍溢出操作,所以编译时要关掉这些保护:
gcc -fno-stack-protector -z execstack -m32 -o overflow overflow.c
-fno-stack-protector:关闭栈金丝雀保护-z execstack:允许栈执行(后续要放shellcode的话需要这个)-m32:编译成32位程序,调试起来更简单,符合大多数CTF入门题场景
第二步:启动GDB并初步观察栈布局
打开GDB加载编译好的程序:
gdb ./overflow
先运行一次程序,看看代码里打印的buf和cookie的地址:
run
你会看到类似&buf: 0xffffd040, &cookie: 0xffffd054的输出,记下来这两个地址,能帮我们大概判断栈的布局——buf是16字节,从buf到cookie的距离大概是16字节左右,接下来要找到从buf到EIP的准确偏移。
第三步:生成测试Pattern并定位偏移量
GDB自带的pattern工具可以帮我们快速找到偏移,先生成一段足够长的不重复字符串(这里生成40字节,足够覆盖buf、cookie和EIP):
pattern create 40
复制生成的字符串,重新运行程序并输入这段字符串,程序会因为缓冲区溢出崩溃。
崩溃后,查看EIP寄存器的值:
info registers eip
假设EIP的值是0x61413461,接着用pattern工具计算这个值对应的偏移:
pattern offset 0x61413461
工具会返回类似Found at offset 20的结果,这意味着从buf开始,填充20个字节后,接下来的4字节就会覆盖EIP寄存器(32位系统下EIP是4字节)。
第四步:验证偏移量是否正确
为了确保偏移没错,我们可以构造测试payload:20个A加上4个B(也就是AAAAAAAAAAAAAAAAAAAABBBB)。
在GDB里可以用以下命令快速运行并输入payload:
r <<< "AAAAAAAAAAAAAAAAAAAABBBB"
然后查看EIP:
info registers eip
如果EIP的值变成0x42424242(也就是'B'的ASCII码),说明我们已经准确覆盖了EIP,接下来就可以根据CTF需求,把EIP替换成想要跳转的地址(比如shellcode的地址、ROP gadget的地址等)。
备注:内容来源于stack exchange,提问作者hieuvm

