网络黑客常常针对系统和程序自身存在的漏洞,编写相应的攻击程序。其中最常见的就是对缓冲区溢出漏洞的攻击,几乎占到了网络攻击次数的一半以上。而在诸多缓冲区溢出中又以堆栈溢出的问题最具有代表性。
世界上第一个缓冲区溢出攻击——Internet蠕虫,曾造成全球多台网络服务器瘫痪。缓冲区溢出漏洞被攻击的现象以越来越普遍,各种操作系统上出现的此类漏洞数不胜数。
对缓冲区溢出漏洞进行攻击的后果包括程序运行失败、系统崩溃和重新启动等。更为严重的是,可利用缓冲区溢出执行非授权命令,甚至取得系统特权,进而进行各种非法操作。于是如何防止和检测利用缓冲区溢出漏洞进行得攻击,成为防御网络入侵和入侵检测得重点之一。
简而言之,缓冲区溢出通常是因gets()、scanf()、strcpy()等函数未对数组越界加以监视和限制,导致有用得堆栈数据被覆盖而引起的。因此,这些函数常称为黑客的攻击对象。
例题1:请分析下面这段程序存在的漏洞。
#include <stdio.h>
#include <string.h>
#define N 10
int main(void)
{char str[N];gets(str);puts(str);return 0;
}
此程序看似简单,但却存在者“缓冲区溢出”的隐患。原因就出在函数gets()上面,它不能限制用户输入字符串的长度,当用户输入的字符串长度超过N时就会发生缓冲区溢出。
为防止发生缓冲区溢出,应将程序第7行语句修改为能够限制输入字符串长度的函数。
fgets(str,N*sizeof(char),stdin);
例题2:请分析下面这段程序存在的漏洞。
#include <stdio.h>
#include <string.h>
#define N 1024
int main(int argc,char *argv[])
{char buffer[N];if(argc>1){strcpy(buffer,argv[1]);}return 0;
}
当被压入栈的数据大于1024,超出1024个字节的内容就会依次覆盖堆栈中保存的寄存器、函数调用的返回地址。
执行函数调用时,操作系统一般要完成如下几个工作:
(1)将函数参数argc和argv压入堆栈;
(2)在堆栈中,保存函数调用的返回地址(即函数调用结束后要执行的语句的地址);
(3)在堆栈中,保存一些其他内容(如有用的系统寄存器等);
(4)在堆栈中,为函数的局部变量分配存储空间;
(5)执行函数代码。