堆栈中的缓冲区溢出
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] 是一个完整的二进制文件,可能会导致不希望的结果可以作为参数与返回地址一起传递,那么就会发生损坏。
我不明白,strcpy 如何破坏堆栈 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() 是不好的建议? @TritonManstrncpy
在某些情况下有它的位置,但在这种情况下,使用strncpy
只会截断用户的文件名,如果它太长。所以你会在其他地方失败(例如,无法打开文件)。以上是关于堆栈中的缓冲区溢出的主要内容,如果未能解决你的问题,请参考以下文章