我正在解决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])而被破坏;
答案 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
这样的函数可能会截断用户的文件名,并导致生成文件打开错误,或者更糟糕的是,打开错误的文件。