int func(char* str)
{
char buffer[100];
unsigned short len = strlen(str);
if(len >= 100)
{
return (-1);
}
strncpy(buffer,str,strlen(str));
return 0;
}
这段代码容易受到缓冲区溢出的攻击,我正在尝试找出原因。我认为这与len
被声明为short
而不是int
有关,但我不是很确定。
有什么想法吗?
发布于 2015-04-28 12:50:04
在大多数编译器上,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);
发布于 2015-04-28 13:00:42
问题出在这里:
strncpy(buffer,str,strlen(str));
^^^^^^^^^^^
如果字符串大于目标缓冲区的长度,strncpy仍会将其复制过来。您将字符串的字符数作为要复制的数量,而不是缓冲区的大小。正确的方法如下:
strncpy(buffer,str, sizeof(buff) - 1);
buffer[sizeof(buff) - 1] = '\0';
这样做的目的是将复制的数据量限制为缓冲区的实际大小减去空终止字符的1。然后我们将缓冲区中的最后一个字节设置为空字符,以此作为额外的保护措施。这样做的原因是,如果strlen(str) < len - 1,strncpy将复制最多n个字节,包括终止null。如果不是这样,则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);
}
因为我们已经知道字符串的长度,所以可以使用memcpy将字符串从str引用的位置复制到缓冲区中。请注意,对于strlen(3)的手册页(在FreeBSD 9.3系统上),说明如下:
函数的作用是:返回终止NUL字符之前的字符数。strnlen()函数返回与strlen()或maxlen ()相同的结果,取较小的值。
我将其解释为字符串的长度不包括null。这就是为什么我复制len +1个字节来包含null,并且测试检查以确保长度< size of buffer - 2.减1,因为缓冲区从位置0开始,并减去另一个以确保有容纳null的空间。
EDIT:结果是,某些东西的大小从1开始,而access从0开始,所以前面的-2是不正确的,因为它会为任何大于98字节的内容返回错误,但它应该大于99字节。
编辑:虽然关于无符号短整型的答案通常是正确的,因为可以表示的最大长度是65,535个字符,但这并不重要,因为如果字符串超过这个长度,值就会换行。这就好比取75,231 ( 0x000125DF),去掉前16位,得到9695 (0x000025DF)。我看到的唯一问题是超过65,535个字符的前100个字符,因为长度检查将允许复制,,但在所有情况下,它只复制字符串的前100个字符,并且null终止字符串。因此,即使存在环绕问题,缓冲区仍然不会溢出。
这本身可能会也可能不会带来安全风险,这取决于字符串的内容以及使用它的目的。如果它仅仅是人类可读的纯文本,那么通常没有问题。你只会得到一个截断的字符串。但是,如果它类似于URL,甚至是SQL命令序列,那么您可能会遇到问题。
发布于 2015-04-28 12:50:57
即使您使用的是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;
}
https://stackoverflow.com/questions/29910520
复制相似问题