Jas*_*son 148 c security buffer-overflow
int func(char* str)
{
char buffer[100];
unsigned short len = strlen(str);
if(len >= 100)
{
return (-1);
}
strncpy(buffer,str,strlen(str));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
此代码容易受到缓冲区溢出攻击,我正在试图找出原因.我认为它与len被宣布为一个short而不是一个int,但我不是很确定.
有任何想法吗?
orl*_*rlp 193
在大多数编译器中,a的最大值unsigned short为65535.
上面的任何值都会被包围,因此65536变为0,而65600变为65.
这意味着正确长度的长字符串(例如65600)将通过检查,并溢出缓冲区.
使用size_t存储的结果strlen(),而不是unsigned short,并比较len以直接编码的大小的表达buffer.例如:
char buffer[100];
size_t len = strlen(str);
if (len >= sizeof(buffer) / sizeof(buffer[0])) return -1;
memcpy(buffer, str, len + 1);
Run Code Online (Sandbox Code Playgroud)
Dan*_*udy 28
问题出在这里:
strncpy(buffer,str,strlen(str));
^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
如果字符串大于目标缓冲区的长度,strncpy仍将复制它.您将字符串的字符数作为要复制的数字而不是缓冲区的大小.正确的方法如下:
strncpy(buffer,str, sizeof(buff) - 1);
buffer[sizeof(buff) - 1] = '\0';
Run Code Online (Sandbox Code Playgroud)
这样做是限制复制到缓冲区实际大小的数据量减去空终止字符的一个.然后我们将缓冲区中的最后一个字节设置为空字符作为添加的安全措施.原因是因为strncpy将复制最多n个字节,包括终止空值,如果strlen(str)<len - 1.如果不是,则不复制null并且您有崩溃场景,因为现在您的缓冲区没有终止串.
希望这可以帮助.
编辑:经过进一步审查和其他人的意见,可能编写的功能如下:
int func (char *str)
{
char buffer[100];
unsigned short size = sizeof(buffer);
unsigned short len = strlen(str);
if (len > size - 1) return(-1);
memcpy(buffer, str, len + 1);
buffer[size - 1] = '\0';
return(0);
}
Run Code Online (Sandbox Code Playgroud)
由于我们已经知道字符串的长度,因此我们可以使用memcpy将字符串从str引用的位置复制到缓冲区中.请注意,根据strlen(3)的手册页(在FreeBSD 9.3系统上),说明如下:
Run Code Online (Sandbox Code Playgroud)The strlen() function returns the number of characters that precede the terminating NUL character. The strnlen() function returns either the same result as strlen() or maxlen, whichever is smaller.
我解释为字符串的长度不包括null.这就是为什么我复制len + 1个字节以包含null,并且测试检查以确保长度<缓冲区的大小 - 2.减1因为缓冲区从位置0开始,减去另一个以确保有空间为null.
编辑:结果,某些东西的大小从1开始,而访问从0开始,所以前面的-2是不正确的,因为它会返回任何> 98字节的错误,但它应该> 99字节.
编辑:虽然关于无符号短路的答案通常是正确的,因为可以表示的最大长度是65,535个字符,但这并不重要,因为如果字符串比这长,则值将环绕.这就像取75,231(即0x000125DF)并屏蔽前16位,给你9695(0x000025DF).我看到的唯一问题是超过65,535的前100个字符,因为长度检查将允许复制,但它只会在所有情况下复制到字符串的前100个字符,并且null终止字符串.因此,即使存在环绕问题,缓冲区仍然不会溢出.
这可能会也可能不会产生安全风险,具体取决于字符串的内容以及您使用它的内容.如果它只是人类可读的直文,那么通常没有问题.你只是得到一个截断的字符串.但是,如果它类似于URL或甚至是SQL命令序列,则可能会出现问题.
Pat*_*rts 11
即使你正在使用strncpy,截止的长度仍然取决于传递的字符串指针.你不知道该字符串有多长(空终止符相对于指针的位置,即).因此,strlen单独调用可以让您了解漏洞.如果您想要更安全,请使用strnlen(str, 100).
完整代码更正将是:
int func(char *str) {
char buffer[100];
unsigned short len = strnlen(str, 100); // sizeof buffer
if (len >= 100) {
return -1;
}
strcpy(buffer, str); // this is safe since null terminator is less than 100th index
return 0;
}
Run Code Online (Sandbox Code Playgroud)