首先看一下gets函数的形式:
char *
gets(char *str);
很明显gets接收一个char类型的指针变量,或者也可以说是一个数组,遗传字符串。没有规定具体接收的大小,这就是gets函数的漏洞。
gets函数和fgets函数最大的不同是gets函数的缓冲区虽然由用户提供,但是用户无法指定其一次最多读入多少字节的内容。这一点导致gets变成了一个非常危险的函数。
下例演示了gets函数的危险性。该程序定义了一个缓冲区,但是使用gets函数接收用户输入的字符串时却会出现问题。
(1)在vi编辑器中编辑该程序如下:
程序清单21-5 risk.c 利用gets函数的漏洞进行缓冲区攻击
#include
int main(void)
{
/* 这个缓冲区已经很大了,如果用户输入是在命令行方式下的话,该缓冲的空间是足够的 */
char buf[2048];
while(gets(buf) != buf){ /* 从屏幕读入一行字符串 */
printf("%s\n", buf); /* 并且将该字符串显示输出到屏幕上 */
}
return 0;
}
(2)在shell中编译该程序如下:
$gcc risk.c -o risk
(3)在shell中运行该程序如下:
$./risk
hello world (输入)
hello world (输出)
welcome to the real world, it sucks, but you will love it(输入)
welcome to the real world, it sucks, but you will love it(输出)
到目前为止都没有出现问题,事实上,在命令行终端的情况下不会出现问题。因为shell终端的输入缓冲区只有1024个字节,也就是说我们的攻击实际上被shell挡住了。
(4)这个时候换一种方式,先结束该程序。
$^c
(5)将一个非常大的文件从定向到标准输入上。
$./risk < big_file.txt
Segmentation fault
段错误出现了,程序崩溃了。原因就是输入的字符过多,造成了gets函数的缓冲区越界。
因此我们在使用gets()函数时,会收到提示:warning: the `gets’ function is dangerous and should not be used.或者编辑器直接报错的情况。因此不建议大家使用gets()函数。 |
|