繁体   English   中英

缓冲区溢出漏洞

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM