【问题标题】:Buffer Overflow Attack缓冲区溢出攻击
【发布时间】:2011-11-12 17:46:00
【问题描述】:

我正在尝试执行一个非常简单的缓冲区溢出攻击。我对此几乎是新手。所以,如果这个问题很愚蠢,请原谅:-)

代码:

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

int i, n;

void confused(int i) 
{
 printf("**Who called me? Why am I here?? *** %x\n ", i);
}

void shell_call(char *c) 
{
 printf(" ***Now calling \"%s\" shell command *** \n", c);
 system(c);
}

void victim_func()
{
 int a[4];
 printf("Enter n:  ");  scanf("%d",&n);
 printf("~~~~~~~~~~~~~ values and address of n locations ~~~~~~~~~~");
 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);

 // Buffer Overflow vulnerability HERE!

 for (i=0;i<n;i++)  scanf("%x",&a[i]);
   printf("Done reading junk numbers\n");
}

int main() 
{
 victim_func();
 printf(“\n done”);
 return 0; 
}

当我使用 objdump 获取函数地址时,我有以下内容:

main(): 0x804854d
Address of main() where printf() is called: 0x8048563
victim_func(): 0x8048455
confused(): 0x8048414

现在,我想要的是从victim_func() 跳转到函数'confused()',方法是溢出那里的缓冲区,并将返回地址覆盖到confused() 的地址。我想从confused()返回到main中的printf()语句,然后正常退出。所以,我提供以下输入

Enter n: 7
Enter 7 HEX values:
1
2
3
4
5
8048414 (This is to jump to confused)
8048563 (this is to jump to printf() in main)

尽管程序从该 printf 语句中打印出“Done”,但它会跳回到victim_func() 并打印出“Enter n:”

我做错了什么?任何帮助将不胜感激!

PS:我不确定我的问题是否正确。如果需要更多信息,请告诉我。

【问题讨论】:

  • 其实这是学校的作业!
  • 如果这真的是家庭作业,请标记它。
  • @VJo 我认为这是一项很棒的教育任务——我很想亲自尝试一下:它需要对代码的汇编程序实现有深入的理解和直接的实验。白帽子也需要掌握这些想法。
  • LOL 哪所学校教如何滥用缓冲区溢出?确实,您需要深入了解二进制代码。上面的尝试是苍白的尝试,不会奏效
  • @VJo:实际上,我看过的所有计算机安全课程都包含这样的内容。了解这些攻击是如何工作的很重要,如果没有别的,那么了解为什么在编程时应该小心。

标签: c buffer-overflow objdump


【解决方案1】:

缓冲区溢出攻击比这复杂得多。首先,您需要了解汇编程序才能执行此操作。在你反汇编你想要定位的程序和函数之后,你需要在它执行该函数时确定堆栈布局。 这是使用 Visual Studio 的缓冲区溢出示例,但原理相同。

#include "stdafx.h"
#include <math.h>

volatile double  test;

double function3()
{
    test++;
    return exp(test);
}

double  function2()
{
    return log(test);
}

double  function1()
{
    int a[5] = {0};           
    a[7] = (int)&function3;
    return exp(function2());

}
int _tmain(int argc, _TCHAR* argv[])
{
    double a = function1();
    test = a;
    return a;
}

感谢反汇编,我们知道函数 1 中的 a 是在函数保存堆栈帧指针的位置之前分配的。之后的值是 function1 完成后应该去的返回地址。

00401090 55               push        ebp    <- we save the stack pointer
00401091 8B EC            mov         ebp,esp 
00401093 83 EC 1C         sub         esp,1Ch <- save space to allocate a[5]
00401096 B8 CC CC CC CC   mov         eax,0CCCCCCCCh 
0040109B 89 45 E4         mov         dword ptr [ebp-1Ch],eax  <- crt debug init a[5]  
0040109E 89 45 E8         mov         dword ptr [ebp-18h],eax 
004010A1 89 45 EC         mov         dword ptr [ebp-14h],eax 
004010A4 89 45 F0         mov         dword ptr [ebp-10h],eax 
004010A7 89 45 F4         mov         dword ptr [ebp-0Ch],eax 
004010AA 89 45 F8         mov         dword ptr [ebp-8],eax 
004010AD 89 45 FC         mov         dword ptr [ebp-4],eax 

由此我们可以得出结论,如果我们用不同的地址覆盖 a[7],函数将不会返回 main,而是返回我们在 a[7] 中写入的任何地址。

希望这会有所帮助。

【讨论】:

  • 非常感谢耐心的解释。这就是我卡住的地方!为什么我们需要分配 1Ch 字来存储数组的 5 个字?您能详细说明一下这里的堆栈结构吗?
  • 而且,这是我反汇编的主程序的一部分。 0x0804855b &lt;main+14&gt;: sub $0x4,%esp 0x0804855e &lt;main+17&gt;: call 0x8048455 &lt;victim_func&gt; 0x08048563 &lt;main+22&gt;: movl $0x804872e,(%esp) 0x0804856a &lt;main+29&gt;: call 0x8048364 &lt;printf@plt&gt; 所以,我从 0x8048563 返回到 main(),因为我很困惑。将返回地址放在正确的内存位置没有问题。并且,main() 通过打印“完成”来恢复。但此时,它又回到了victim_func(),并打印出“Enter n:”这是我不明白的。
【解决方案2】:

首先,在我看来,您不应该在示例输入中输入数字 5。你的数组被声明为 a[4] 因此元素索引为 0-3 - 所以你的攻击输入对我来说似乎是错误的。

在我看来,您的程序还假设了有关架构的几件事:

  • sizof(int)==sizeof(内存地址)
  • 环境栈实现的发展方向和机制

如果这些假设之一是不正确的,它永远不会起作用。

这似乎是一项非常艰巨的工作任务。

缓冲区溢出攻击的例子比更改代码的控制流更简单。例如,您可能能够覆盖另一条本应受到用户保护的数据(例如安全设置)

【讨论】:

  • 超出数组范围的索引正是此类攻击的工作方式。而且这种攻击总是非常依赖平台;它们取决于堆栈的布局方式,并且通常涉及一些汇编程序。通常的解决方案是将执行某些操作的机器代码放在缓冲区中,然后将堆栈上的返回地址替换为缓冲区的地址。
【解决方案3】:

您没有向我们展示带有 a[i] 地址的程序的输出。我怀疑编译器正在做一些事情,比如将堆栈上的数据对齐到 16。它可能比您预期的要远得多。

【讨论】:

    【解决方案4】:

    现在,我想要的是通过溢出那里的缓冲区,从victim_func()跳转到函数'confused()',并将返回地址覆盖到confused()的地址......

    在现代 Linux 平台上,您还需要确保关闭两个安全功能以进行测试。首先是 NX 堆栈,其次是堆栈保护器。

    要关闭 NX-Stacks,请使用 -Wl,z,execstack(而不是 -Wl,z,noexecstack)。要关闭堆栈保护器,请使用 -fno-stack-protector(而不是 -fstack-protector-fstack-protector-all)。

    您可能需要关闭第三种保护。该保护是 FORTIFY_SOURCE。 FORTIFY_SOURCE 使用“更安全”的高风险函数变体,例如 memcpystrcpy。当编译器可以推断目标缓冲区大小时,它会使用更安全的变体。如果副本超出目标缓冲区大小,则程序调用abort()。要禁用 FORTIFY_SOURCE,请使用 -U_FORTIFY_SOURCE-D_FORTIFY_SOURCE=0 编译程序。

    安全功能默认是开启的,因为过去有很多问题。总的来说,这是一件好事,因为它可以解决很多问题(比如您正在试验的问题)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-10-23
      • 2019-04-14
      • 2021-12-03
      • 2021-02-25
      • 1970-01-01
      • 1970-01-01
      • 2014-05-14
      相关资源
      最近更新 更多