【问题标题】:How can I invoke buffer overflow?如何调用缓冲区溢出?
【发布时间】:2011-01-20 23:49:04
【问题描述】:

我有一个家庭作业要求我调用一个函数而不显式调用它,使用缓冲区溢出。代码基本上是这样的:

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

void g()
{
    printf("now inside g()!\n");
}


void f()
{   
    printf("now inside f()!\n");
    // can only modify this section
    // cant call g(), maybe use g (pointer to function)
}

int main (int argc, char *argv[])
{
    f();
    return 0;
}

虽然我不确定如何进行。我考虑过更改程序计数器的返回地址,以便它直接转到 g() 的地址,但我不确定如何访问它。无论如何,提示会很棒。

【问题讨论】:

  • 4 票赞成家庭作业问题! OP甚至没有提出这个问题......哇,有些人很容易被打动。
  • @Lazarus,我赞成你的评论。哦哦! :-)
  • @Lazarus 这是一个家庭作业问题,这与我觉得它很有趣这一事实无关。我也赞成它,因为我想鼓励有趣的家庭作业问题,而不是简单的“我关闭了文件缓冲区,现在当我尝试从文件中读取它不起作用。为什么?” (换句话说,我赞成那些我不知道但想回答的问题)
  • @Alok,大声笑 - 它们都是我自己的话......这有助于缓解你的良心吗? ;)
  • 哇,这是一个硬件问题?我已经爱上了你的老师:D

标签: c pointers stack-trace buffer-overflow fortify-source


【解决方案1】:

试试这个:

void f()
{   
    void *x[1];
    printf("now inside f()!\n");
    // can only modify this section
    // cant call g(), maybe use g (pointer to function)
    x[-1]=&g;
}

或者这个:

void f()
{   
    void *x[1];
    printf("now inside f()!\n");
    // can only modify this section
    // cant call g(), maybe use g (pointer to function)
    x[1]=&g;
}

【讨论】:

  • x 是一个局部变量,所以它位于栈上。由于 x 是大小为 1 的数组,因此只有 x[0] 有效。通过在 x[-1] 或 x[1] 中写入 g 的地址,我们有可能会覆盖返回地址。这取决于堆栈的组织,哪个版本有效。
【解决方案2】:

这取决于编译器,因此无法给出单一答案。

以下代码将为 gcc 4.4.1 执行您想要的操作。在禁用优化的情况下编译(重要!)

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

void g()
{
    printf("now inside g()!\n");
}


void f()
{   
  int i;
  void * buffer[1];
  printf("now inside f()!\n");

  // can only modify this section
  // cant call g(), maybe use g (pointer to function)

  // place the address of g all over the stack:
  for (i=0; i<10; i++)
     buffer[i] = (void*) g;

  // and goodbye..
}

int main (int argc, char *argv[])
{
    f();
    return 0;
}

输出:

nils@doofnase:~$ gcc overflow.c
nils@doofnase:~$ ./a.out
now inside f()!
now inside g()!
now inside g()!
now inside g()!
now inside g()!
now inside g()!
now inside g()!
Segmentation fault

【讨论】:

  • 我正在使用 gcc 4.4.1,但不确定如何关闭优化:尝试过 gcc -O0 -o buff buff.c (哦,零)以及 gcc -O1 -fno- defer-pop -fno-thread-jumps -fno-branch-probabilities -fno-cprop-registers -fno-guess-branch-probability -fno-omit-frame-pointer -o buff buff.c 都不起作用。
  • 让应用程序退出 'g()' 函数以避免分段错误 =)
  • sa125,也许 gcc 会尝试针对不同的 cpu 架构进行优化。据我所知,它默认为您正在运行的系统的 cpu。这可以改变 f() 的堆栈帧的外观,并可以防止溢出发生。
  • Nils - 也许我今天早上有点慢 - 但是你是怎么得到“现在在 g() 中”要打印的 - 我知道你在哪里存储指向 g() 的指针,但我没有在您的示例代码中看到您取消引用指针并调用 g()
  • Dan,f() 从 main 中调用,在调用期间编译器会将返回地址放入堆栈,因此 f() 知道它在完成后必须跳转到的位置。但是,在 f() 内部,我用 g() 的地址覆盖了堆栈的大部分。我也有可能覆盖退货地址。所以当 f() 退出时,它不会返回 main 而是跳转到 g() 。这真的很脏,但这就是问题所在。
【解决方案3】:

基本思想是改变函数的返回地址,以便在函数返回时继续在新的被黑地址处执行。正如 Nils 在其中一个答案中所做的那样,您可以声明一块内存(通常是数组)并以这样的方式溢出它,即返回地址也被覆盖。

我建议您在没有真正了解它们的工作原理的情况下,不要盲目地接受这里给出的任何程序。这篇文章写得很好,你会发现它很有用:

A step-by-step on the buffer overflow vulnerablity

【讨论】:

    【解决方案4】:

    由于这是家庭作业,我想回复 codeaddict's suggestion 了解缓冲区溢出的实际工作原理。

    我通过阅读关于利用缓冲区溢出漏洞的优秀(如果有点过时)文章/教程来学习该技术Smashing The Stack For Fun And Profit

    【讨论】:

      【解决方案5】:

      虽然此解决方案不使用溢出技术来覆盖函数在堆栈上的返回地址,但它仍然会导致 g() 在返回到 main() 的途中被调用,只需修改 f()而不是直接调用g()

      Function epilogue-like inline assembly被添加到f()中,修改栈上返回地址的值,使f()通过g()返回。

      #include <stdio.h>
      
      void g()
      {
          printf("now inside g()!\n");
      }
      
      void f()
      {   
          printf("now inside f()!\n");
          // can only modify this section
          // cant call g(), maybe use g (pointer to function)
      
          /* x86 function epilogue-like inline assembly */
          /* Causes f() to return to g() on its way back to main() */
          asm(
              "mov %%ebp,%%esp;"
              "pop %%ebp;"
              "push %0;"
              "ret"
              : /* no output registers */
              : "r" (&g)
              : "%ebp", "%esp"
             );
      }
      
      int main (int argc, char *argv[])
      {
          f();
          return 0;
      }

      了解此代码的工作原理有助于更好地了解函数的堆栈帧是如何为构成缓冲区溢出技术基础的特定架构设置的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-12-16
        • 1970-01-01
        • 2010-11-11
        • 1970-01-01
        • 2013-11-06
        • 2013-04-11
        • 2015-07-07
        • 2012-02-05
        相关资源
        最近更新 更多