堆栈中的缓冲区溢出

Posted

技术标签:

【中文标题】堆栈中的缓冲区溢出【英文标题】:Bufferoverflow on stack 【发布时间】:2013-09-10 16:33:07 【问题描述】:

我正在处理 C 中的安全问题。我无法理解以下代码如何破坏堆栈,

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

int chk_perm()
        printf("\n Check Perm \n");
        return 2;

int main(int argc,char* argv[])
        int fg;
        char filename[16];

        if(argc != 2)
                fprintf(stderr,"Usage : %s filename\n",argv[0]);
                exit(1);
        

        fg = chk_perm();
        strcpy(filename,argv[1]);
        if(fg == 0xdeadbeef)
                //execute as root or deposit million dollars in bank account
        
        else
                //execute as a normal user , deduct $10 from an account
        

        return 0;

传递的 argv[1] 可能会改变 fg 的值。 据说,如果传递的 argv[1] 是一个完整的二进制文件,可能会导致不希望的结果可以作为参数与返回地址一起传递,那么就会发生损坏。

我不明白,str​​cpy 如何破坏堆栈 check_perm 从而改变 fg 的值。

我对程序的假设,

当程序开始执行时,它为 main 函数创建一个堆栈,并将其参数、返回地址、局部变量放入堆栈。因此 int fg 将占用堆栈的 4 个字节(08567500 loc),文件名 [16] 将占用接下来的 16 个字节(08567504)。即使文件名溢出超过 16 个字节,如果它之后存在任何局部变量,它也可能会损坏。

那么 fg 是如何因为 strcpy(filename,argv[1]); 而损坏的?

【问题讨论】:

【参考方案1】:

如果在您的架构上堆栈向下增长(通常是这种情况),fg 将立即占用内存filename。这意味着当你写过去 filename 时,你会粉碎 fg

【讨论】:

这是唯一正确考虑堆栈增长方向的答案 @NPE:谢谢。我检查了 fg 的地址和文件名。 fg 位于文件名下方。但我有一个疑问。当堆栈加载时,参数、返回地址、局部变量按顺序存储到堆栈中。所以局部变量 fg 必须获得比文件名更高的地址。并且数组文件名从低到高 sddress 增长。为什么文件名的地址比 fg 最高。 @Angus:也许写这个例子的人说的是一个向下栈的系统,但你测试的系统使用的是向上栈。 我试图在文件名声明下面声明fg。那么 fg 也占据最低地址。如果我声明上面的文件名,我也会得到 fg 作为最低地址。当局部变量被压入堆栈时,第一个声明的变量必须获得比下面的最高地址是我的理解【参考方案2】:

fg 在堆栈上。 filename 也是如此。当你 strcpy()filename 的东西大于 16 时,它会覆盖 fg

【讨论】:

【参考方案3】:

正如其他人指出的那样,您正在写超过 filename 缓冲区。当您这样做时,堆栈中的下一项是 fg 变量,因此如果输入文件名的长度超过 15 个字符(然后再包含一个字节:零终止符),它将获得写入它的字节)。

您需要使filename 足够大以容纳用户可能为argv[1] 提供的任何内容,或者防止复制太多字节。但最好在这种情况下分配您需要的空间:

char filename[PATH_MAX+1];

如果你想动态地做:

char *filename;

if ( !(filename = malloc(strlen(argv[1]) + 1))) ) 
    ... (failure leg)

将文件名长度限制为16 字节(实际上是15 加上零终止符)对用户来说是极其不切实际的,尤其是因为他们可能会为文件参数提供完整的路径名。使用 strncpy 之类的函数可能会截断用户的文件名,并且可能会生成文件打开错误,或者更糟糕的是,会打开错误的文件。

【讨论】:

strncpy() 是个坏建议。一个非常糟糕的建议。 @joop 是的,我同意。我什至不会自己使用这种方法。我只是在实践中展示了它,因为其他人提供了它并想让它更“可见”。我已将其删除。 为什么 strncpy() 是不好的建议? @TritonMan strncpy 在某些情况下有它的位置,但在这种情况下,使用strncpy 只会截断用户的文件名,如果它太长。所以你会在其他地方失败(例如,无法打开文件)。

以上是关于堆栈中的缓冲区溢出的主要内容,如果未能解决你的问题,请参考以下文章

(原创)攻击方式学习之 - 缓冲区溢出(Buffer Overflow)

怎么解决 LINUX 堆栈溢出内存的问题

缓冲区溢出及堆栈/堆操纵

系统在此应用程序中检测到基于堆栈的缓冲区溢出。溢出...

什么是堆栈溢出和缓冲区溢出错误? [复制]

堆栈缓冲区溢出会导致堆损坏吗?