1

我正在处理 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),而 filename[16] 将占用接下来的 16 个字节字节(08567504)。即使文件名溢出超过 16 个字节,如果它之后存在任何局部变量,它也可能会损坏。

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

4

3 回答 3

3

如果在您的架构上堆栈向下增长(通常是这种情况),fg filename. 这意味着,当你写过去时filename,你就粉碎了fg

于 2013-09-10T16:36:26.720 回答
2

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

于 2013-09-10T16:35:12.623 回答
1

正如其他人指出的那样,您正在写入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可能会截断用户的文件名并生成文件打开错误,或者更糟糕的是,打开错误的文件。

于 2013-09-10T16:38:20.943 回答