[英]Buffer overflow vulnerability
以下程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int check_authentication(char *password)
{
int auth_flag = 0;
char password_buffer[16];
strcpy(password_buffer, password);
if(strcmp(password_buffer, "unipi") == 0)
auth_flag = 1;
if(strcmp(password_buffer, "SSL") == 0)
auth_flag = 1;
return auth_flag;
}
int main(int argc, char *argv[]) {
if(argc < 2) {
printf("Usage: %s <password>\n", argv[0]);
exit(0);
}
if(check_authentication(argv[1])!=0)
{
printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
printf(" Access Granted.\n");
printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
}
else
{
printf("\nAccess Denied.\n");
}
}
在strcpy(password_buffer, password);
行strcpy(password_buffer, password);
它有一个缓冲区溢出漏洞。 如果我们想在不删除strcpy
情况下确保该程序的安全,那怎么可能?
简单。 您可以在其他地方更改验证,以确保用户输入符合预期。 使用strlen,以便您可以检查字符串是否短于16个字节。
if(strlen(argv[1]) > 15)
{
printf("too long password\n");
exit(0);
}
我在Wiki上找到了这个:
为了防止在此示例中发生缓冲区溢出,可以用strncpy代替对strcpy的调用,该调用将A的最大容量作为附加参数,并确保将不超过此数量的数据写入A:
strncpy(password_buffer, password, sizeof(A));
注意上面的代码也不是没有问题。 尽管这次防止了缓冲区溢出,但是如果源字符串的长度大于或等于缓冲区的大小(传递给该函数的第三个参数),则strncpy库函数不会以空终止终止目标缓冲区。在这种情况下,不是以Null结尾的,因此不能将其视为有效的C样式字符串。
有几种方法可以解决这个问题。
首先,也许是最重要的是避免固定的内存分配,尤其是在处理输入时。 在上面的示例中,可以将缓冲区设置为所需大小,而不是复制到固定大小的缓冲区。
char password_copy[strlen(password) + 1];
strcpy(password_copy, password);
但这并不总是可能的。 也许您已经分配了内存。 也许您确实想截断输入(尽管16对于密码来说太小了 )。
一种是根本不使用C字符串处理函数,它们充满了缺陷和安全漏洞。 而是使用Gnome Lib之类的具有G_String类型的库 。 G_String跟踪其长度和分配的大小。 这会占用更多的内存,但是速度更快。 查找字符串的长度(这种情况经常发生)并不要求遍历字符串的每个字节。
G_Strings有自己的字符串处理函数集,这些函数比C 函数要方便得多。 它还可以根据需要增加字符串或为您分配新的字符串。
/* Allocate memory for the copy and copy the password */
G_String *password_copy = g_string_new(password);
为了与常规字符串函数兼容, password_copy->str
返回一个常规char *
。
这是IMO的最佳方法。 您不再需要记住检查字符串的长度和分配的大小,而不必担心在使用字符串的任何地方都有空字节。 你会忘记的。 让计算机执行此操作。
如果必须使用C标准函数,请不要使用strncpy
因为它不能保证截断的字符串将以null终止。 而是使用strlcpy
。 就像strncpy
一样,但是它保证复制的字符串将以null结尾。 strlcpy
是BSD扩展,因此不能保证可移植。 glibc拒绝实现它 。
为了最大程度地提高便携性,效率和安全性,请使用strlcpy
并使用memmove
和#ifndef strlcpy
提供后备功能,因此只有在strlcpy
不可用时才使用它。
#include <string.h>
#include <stdio.h>
#ifndef strlcpy
size_t strlcpy(char * restrict dst, const char * restrict src, size_t dst_size) {
/* size is the allocated size. len leaves space for the null byte */
size_t dst_len = dst_size - 1;
size_t src_len = strlen(src);
/* Use the smaller of the two string lengths to avoid buffer overflow */
size_t move_len = src_len > dst_len ? dst_len : src_len;
/* Copy the string, truncate if necessary. It will work
* even if src and dst overlap. */
memmove(dst, src, move_len);
/* Guarantee there's a null byte */
dst[move_len] = '\0';
/* strlcpy returns the size of the string it tried to make.
* This is used to detect truncation. */
return src_len;
}
#endif
int main()
{
char dst[10];
char *src = "12345678901234567890";
printf("%zu\n", strlcpy(dst, src, 10));
printf("src: %s, dst: %s\n", src, dst);
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.