堆栈上的缓冲区溢出

时间:2013-09-10 16:33:07

标签: c

我正在解决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]传递的是一个可以导致不良结果的整个二进制文件,可以作为参数和返回地址一起传递。

我无法理解,strcpy如何破坏堆栈check_perm,使得fg的值发生变化。

我对该计划的假设,

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

那么fg如何因strcpy(filename,argv [1])而被破坏;

3 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:2)

fg在堆栈中。 filename也是如此。如果strcpy() filename的某些内容大于16,则会覆盖fg

答案 2 :(得分: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这样的函数可能会截断用户的文件名,并导致生成文件打开错误,或者更糟糕的是,打开错误的文件。