Dies ist eine alte Version des Dokuments!


Dangerous Standard Library Functions and Safer Alternatives

The previous chapters explained different buffer overflow exploitation techniques. However, the effects of the overflows did not show up in the self-written code, but when calling standard library functions. One does not only need to be careful about writing safe code but also about using provided functions that make assumptions about the passed input. The standard library of the C programming language builds the foundation for larger applications but contains several functions which can - if they are used incorrectly - cause buffer overflows1).

Examples for Dangerous Standard Library Functions

Following functions of the C standard library are well-known examples causing buffer overflows. With each function description includes a demonstration of incorrect usage.

gets

gets() reads a string from the standard input. There is no way to restrict the length of the input.

stdlib/gets.c
// gcc -std=c99 gets.c
#include <stdio.h>
 
int main()
{
    char buffer[10];
    gets(buffer);
    return 0;
}

:!: As there is no way to use gets() safely, it was removed from the C standard with C11.

strcpy

strcpy() copies a string to another memory location. The destination buffer might be smaller than the source buffer.

stdlib/strcpy.c
// gcc strcpy.c
#include <string.h>
 
int main()
{
    char dst_buffer[10];
    char const *src_buffer = "This string is too long for the dst_buffer";
    strcpy(dst_buffer, src_buffer);
    return 0;
}

strcat

strcat() concatenates two strings. The destination buffer might be too small to also contain the source buffer in addition to the existing string.

stdlib/strcat.c
// gcc strcat.c
#include <string.h>
 
int main()
{
    char dst_buffer[10] = "This ";
    char const *src_buffer = "string is too long for dst_buffer";
    strcat(dst_buffer, src_buffer);
    return 0;
}

scanf

scanf() and its related functions (sscanf(), fscanf(), etc.) read formatted input. By default, there is no length restriction on the input.

stdlib/scanf.c
// gcc scanf.c
#include <stdio.h>
 
int main()
{
    char buffer[10];
    scanf("%s", buffer);
    return 0;
}

sprintf / vsprintf

sprintf() and vsprintf() write a formatted string to a buffer. By default, there is no length restriction on the generated string.

stdlib/sprintf.c
// gcc sprintf.c
#include <stdio.h>
 
int main()
{
    char buffer[10];
    sprintf(buffer, "Hallo %s!\n", "World");
    return 0;
}

Safer Alternatives

In order to prevent buffer overflows caused by standard library functions, it is important to either validate the input in advance or use safer alternatives.

fgets

fgets() is a safer alternative to the gets() or scanf() function.

stdlib/fgets.c
// gcc fgets.c
#include <stdio.h>
 
int main()
{
    char buffer[10];
    fgets(buffer, 10, stdin);
    return 0;
}

strncpy / strlcpy

When thinking about a safer alternative for strcpy(), the most obvious solution is probably strncpy().

stdlib/strncpy.c
// gcc strncpy.c
#include <string.h>
 
int main()
{
    char dst_buffer[10];
    char const *src_buffer = "This string is too long for the dst_buffer";
    strncpy(dst_buffer, src_buffer, 10);
    return 0;
}

It is important to note that also strncpy() can cause unintended effects. If the source buffer is larger than the size passed to strncpy(), there is no '\0' termination added to the destination string.

One alternative taking care of '\0' termination is strlcpy(). However, this function is not part of the C standard and only available on some Unix systems (e.g. BSD).

stdlib/strlcpy.c
// gcc strlcpy.c
#include <string.h>
 
int main()
{
    char dst_buffer[10];
    char const *src_buffer = "This string is too long for the dst_buffer";
    strlcpy(dst_buffer, src_buffer, 10);
    return 0;
}

strncat / strlcat

Similar to strncpy(), the obvious alternative to strcat() is strncat().

stdlib/strncat.c
// gcc strncat.c
#include <string.h>
 
int main()
{
    char dst_buffer[10] = "This ";
    char const *src_buffer = "string is too long for dst_buffer";
    strncat(dst_buffer, src_buffer, 4);
    return 0;
}

Again, also strcat() can cause problems if the existing string is not terminated by a '\0' character. Analogous to strlcpy(), there is a safer alternative called strlcat() taking the size of the destination buffer as a parameter on some Unix systems.

stdlib/strlcat.c
// gcc strlcat.c
#include <string.h>
 
int main()
{
    char dst_buffer[10] = "This ";
    char const *src_buffer = "string is too long for dst_buffer";
    strlcat(dst_buffer, src_buffer, 10);
    return 0;
}

snprintf / vsnprintf

snprintf() and vsnprintf() are safer alternatives to the sprintf() and vsprintf() functions.

stdlib/snprintf.c
// gcc snprintf.c
#include <stdio.h>
 
int main()
{
    char buffer[10];
    snprintf(buffer, 10, "Hallo %s!\n", "World");
    return 0;
}



← Back to heap overflows Overview Continue with ASCII-armored addresses →