【问题标题】:Buffer overflow vulnerability缓冲区溢出漏洞
【发布时间】:2016-06-04 06:29:45
【问题描述】:

以下程序:

#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,这怎么可能?

【问题讨论】:

  • 最好的办法是用安全函数替换strcpy。通过保持strcpy,您希望完成什么?
  • “如果我们想让这个程序安全” 针对什么安全?
  • char password_buffer[strlen(password)+1]。欢迎来到堆栈溢出
  • 你为什么要复制password
  • @Micheal 这超出了这个问题的范围。我只是想尝试使其安全而不删除strcpy

标签: buffer-overflow c


【解决方案1】:

我在 Wiki 上找到了这个:

为了防止在本例中发生缓冲区溢出, 对 strcpy 的调用可以替换为 strncpy,它取最大值 A 的容量作为附加参数,并确保不超过 这么多数据写入A:

strncpy(password_buffer, password, sizeof(A));

请注意,上面的代码也不是没有问题;而一个 这次防止了缓冲区溢出,strncpy 库 如果源缓冲区,函数不会以空值终止目标缓冲区 字符串的长度大于或等于缓冲区的大小 (传递给函数的第三个参数),因此 A 是,在这个 case,不以 null 结尾,不能被视为有效的 C 样式 字符串。

【讨论】:

    【解决方案2】:

    简单。 您可以在其他地方更改用户输入是否符合预期的验证。 使用 strlen 以便您可以检查字符串是否短于 16 个字节。

    if(strlen(argv[1]) > 15)
    {
        printf("too long password\n");
        exit(0);
    }
    

    【讨论】:

    • 这个检查应该在check_authentication()函数内部完成。
    • 不,您应该在调用之前将它放在主函数中,以免浪费资源。
    • 浪费什么资源?
    • 一定要在 check_authentication() 函数中执行它,因为 A)这是控制密码缓冲区大小的函数,B)那么你不必 [忘记] 把这个检查放在任何地方@ 987654324@ 被调用。
    • 保存资源来构建堆栈框架不是这个例子的关注点。教导参数验证的正确位置比教导担心用于构建堆栈框架的资源(这在几乎所有情况下都可以忽略不计,除了最紧凑的循环之外)更有价值。除了无限递归之外,堆栈帧的创建可能是编程中需要关注的最低优先级的事情之一。
    【解决方案3】:

    有几种方法可以解决这个问题。


    首先,或许也是最重要的一点,是避免固定内存分配,尤其是在处理输入时。在上面的示例中,您可以将缓冲区设置为您需要的大小,而不是复制到固定大小的缓冲区。

    char password_copy[strlen(password) + 1];
    strcpy(password_copy, password);
    

    但这并不总是可能的。也许您已经分配了内存。也许您确实想截断输入(尽管16 is far too small for a password)。


    一个是根本不使用 C 字符串处理函数,它们充满了缺陷和安全漏洞。而是使用像 Gnome Lib 这样的库,它具有 the G_String type。 G_Strings 跟踪它们的长度和分配的大小。这需要更多的内存,但速度更快。查找字符串的长度,这种事情经常发生,不需要遍历字符串的每个字节。

    G_Strings have their own set of string handling functions 比 C 更方便。它还可以根据需要增加字符串或为您分配新字符串。

    /* Allocate memory for the copy and copy the password */
    G_String *password_copy = g_string_new(password);
    

    为了与常规字符串函数兼容,password_copy-&gt;str 返回一个普通的char *

    这是 IMO 的最佳方式。您不再需要记住检查字符串长度和分配的大小,也不必担心在使用字符串的任何地方出现空字节。你会忘记的。让电脑来做吧。


    如果您必须使用 C 标准函数,请不要使用 strncpy,因为它无法保证截断的字符串将以空值结尾。而是使用strlcpy。这就像strncpy,但它保证复制的字符串将以空值终止。 strlcpy 是 BSD 扩展,因此不保证可移植。 glibc refuses to implement it.

    为了获得最大的便携性、效率和安全性,请使用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;
    }
    

    【讨论】:

      猜你喜欢
      • 2020-07-13
      • 1970-01-01
      • 1970-01-01
      • 2013-02-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-18
      相关资源
      最近更新 更多