缓冲区溢出漏洞

时间:2016-02-22 06:09:30

标签: buffer-overflow c

以下计划:

#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的情况下使这个程序安全,那怎么可能?

3 个答案:

答案 0 :(得分:2)

易。 您将用户输入的验证更改为其他位置。 使用strlen,以便您可以检查字符串是否短于16个字节。

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

答案 1 :(得分:1)

我在Wiki上发现了这个:

  

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

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

请注意,上述代码也没有问题;而a   这次阻止了缓冲区溢出,strncpy库   如果源,函数不会空终止目标缓冲区   字符串的长度大于或等于缓冲区的大小   (传递给函数的第三个参数),因此A就是这个   case,not null-terminated,不能被视为有效的C风格   字符串。

答案 2 :(得分:1)

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

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

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->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;
}