#include <stdio.h>
int main(void){
int len;
char input[40]="";
printf("input length : \n");
scanf("%d", &len);
if(len > 40){
return 0;
}
read(0, input, len);
printf("%s", input);
return 0;
}
此代码容易受到缓冲区溢出攻击,我正在尝试找出原因。我尝试了很多,但每个攻击代码都无法绕过“if”语句。
如何利用此代码?
除了导致非空终止字符串的确切数字 40 之外,该程序还接受
-1
等作为输入。
read
又具有无符号 size_t
的参数,因此如果我输入 -1
那么 len
将转换为 0xFFFF...
- 一个非常大的数字。
最大的错误是将缓冲区大小声明为有符号整数。缓冲区的大小不能为负。它应该被声明为
size_t
并且输入应该通过 %zu
或更好地作为通过 fgets
和类似的字符串进行处理,然后进行解析和清理。
当
len == 40
时,read(0, input, len);
读取 40 个字符。
printf("%s", input);
尝试打印input
,期望它是一个字符串。然而,input
中肯定不再有空字符,因此
input
不包含
一个字符串。
结果:未定义的行为(UB)。
不要使用
printf("%s", input);
,而是使用 printf("<%.40s>\n", input);
查看(不带 UB)读取的内容。
类型一致性、适当的缓冲区长度和长度检查至关重要。例如,我建议进行以下更改:
int main(void)
{
size_t len = 0 ; // *** Correct type for read() length parameter
char input[41] = "" ; // *** Include room for nul terminator
printf( "Input length : \n" );
int cvt = scanf("%zu", &len); // *** Correct format specifier for size_t
if( cvt == 0 || // *** Check valid conversion of input
len > sizeof(input) - 1 ) // *** Leave room for nul terminator
// *** And no "magic" number
{
return 0;
}
read( 0, input, len ) ;
printf( "%s", input ) ;
return 0;
}