What is it?

A buffer overflow vulnerability occurs when data can be written outside the memory allocated for a buffer, either past the end or before the beginning.

Buffer overflows may occur on the stack, on the heap, in the data segment, or the BSS segment (the memory area a program uses for uninitialized global data), and may overwrite from one to many bytes of memory outside the buffer.

Buffer overflow vulnerabilities often permit remote attackers to run arbitrary code on a victim server or to crash server software and perform a denial of service (DoS) attack.

 

How it happens?

Buffer overflow normally happens in languages that do not have inherent bounds checking and pointer control. For example, C and C++.

Here are some examples of buffer overflow vulnerability and ways to handle them.

General Prevention Techniques:

A number of general techniques to prevent buffer overflows include:

  • Code auditing (automated or manual)
  • Developer training – bounds checking, use of unsafe functions, and group standards
  • Non-executable stacks – many operating systems have at least some support for this
  • Compiler tools – StackShield, StackGuard, and Libsafe, among others
  • Safe functions – use strncat instead of strcat, strncpy instead of strcpy, etc
  • Patches – Be sure to keep your web and application servers fully patched, and be aware of bug reports relating to applications upon which your code is dependent.
  • Periodically scan your application with one or more of the commonly available scanners that look for buffer overflow flaws in your server products and your custom web applications.

 

 

 

Storing data into a buffer without performing bounds checking

Example 1

What you should not do

Read data into a finite length buffer without doing any sort of bounds checking. This can lead to a buffer overflow if it writes past the end of the buffer which can overwrite program data, cause indeterminate program behavior (usually leading to a segfault), or hijack the program's flow.

char buff[5];              //initialise a buffer of size 5

buff[5] = 'a';

The preceding code has the potential for buffer overflow if the source of characters has a size greater than 5.

What you should do

Always check the bounds of data stored in buffers. Indexing in arrays start from 0.To make the above example safe, assigned a value for the array index between 0-4. In this case the size of the array has been declared as 5 but the element is assigned to an index position of 5.

buff[3]='a';

Most standard library functions in C do not do bounds checking  , including strcpy() , strcat(), sprintf(), scanf(), etc.

Concept Map

This example refers to the point GInput Validation and Assumption in the Concept Map.

Example 2

What you should not do

Read data into a finite length buffer without doing any sort of bounds checking. This can lead to a buffer overflow if it writes past the end of the buffer which can overwrite program data, cause indeterminate program behavior (usually leading to a segfault), or hijack the program's flow.

char buffer[1024];              //initialize a buffer of size 1024

int i = 0;

char c;

while((c = getchar()) != '\n')  //read in characters until newline character

{

    if (c == EOF)

        break;                  //exit the loop

    buffer[i++] = c;            //store read characters into buffer

}

The preceding code has the potential for buffer overflow if the source of characters has a size greater than 1024 because the while loop portion of the code reads in characters without checking if the end of the buffer has been exceeded.

What you should do

Always check the bounds of data stored in buffers. To make the above example safe, stop at the end of the buffer.

char buffer[1024];

int i = 0;

char c;

while(((c = getchar()) != '\n') && (i < 1024)) // read to the end of the line or

                                               // until the buffer is full

{

    if (c == EOF)

        break;

    buffer[i++] = c;

}

Or with a for loop:

char buffer[1024];

int i;

char c;

for(i=0; ((c = getchar()) != '\n') && (c != EOF) && (i < 1024); i++)

{

  buffer[i] = c;

}

Most standard library functions in C do not do bounds checking , including strcpy(), strcat(), sprintf(), scanf(), etc.

Concept Map

This example maps to G, Input Validation and Assumption in the Concept Map.

Pointer accessing heap memory

What you should not do

Allocate space in memory using malloc(), and then character pointer is assigned a value, beyond the space allocated.This can cause indeterminate program behavior (usually leading to a segfault), or hijack the program's flow.

char *ptr = (char*) malloc(10);              //initialise a buffer of size 10

ptr[10]='c';

The pointer is not allowed to access heap memory that does not belong to it.

What you should do

Always check the bounds of data stored in buffers.To make the above example safe, Array assignment should be between the indices 0-9.In this case the size of the array has been declared as 10 but the element is assigned to an index position of 10.Also malloc() may return a NULL pointer. Thus, a null check is necessary.

char *ptr = (char*) malloc(10);              //initialise a buffer of size 10

if(ptr != NULL){

   ptr[9]='c';

}

else{

   exit(1);

}

Concept Map

This example points F2 and Assumptions in the Concept Map.

Using gets( ) causes buffer overflow

What you should not do

Do not use gets( ) to read data.This can cause indeterminate program behavior (usually leading to a segfault), or hijack the program's flow.

#include <stdio.h>

int main(void)

{

  char buffer[16];

  int pass=0

  printf("\n Enter the password : \n");

  if(gets(buffer)!=NULL)

  {

   if(strcmp(buffer, "thegeekstuff"))

   {

     printf ("\n Wrong Password \n");

   }

   else

   {      printf ("\n Correct Password \n");

     pass = 1;

   }     if(pass)

    {

     /* Admin rights given to the user*/

     printf ("\n You are root \n");

    }

    return 0;

  }

}

Here gets() does no bound checking on the buffer. This leads to the user gaining admin rights even if the password entered is wrong. For example , the user enters the following string as password pppppppppppppppppppp The output is going to be as follows: Wrong Password You are root

What you should do

Use fgets() which is a buffer safe function.

fgets(buffer, sizeof(buffer), stdin);

Concept Map

This example refers to the point C, DBad Code and Input in the Concept Map.

Printing or copying a string with a printf( ) function

What you should not do

You need to print a string, so you call printf(mystring). This can lead to problems if the string can be constructed by an attacker. By crafting the string using formatting characters that expect additional parameters to printf(), the program can inappropriately read data off the stack, and even write over values on the stack!

int main(int argc, char **argv)

{

    if(argc <= 1)

        printf("error, no arguments (other than program name)!");

    else

    {

        printf(argv[1]);

    }

}

If argv[1] contains any special format string characters, then printf() will look for additional arguments to fill in the formatting characters. A carefully crafted attack could exploit this. It also affects other *printf() functions including sprintf(), snprintf(), fprintf, etc.

What you should do

When using one of the *printf() functions, always use a format string, such as printf("%s",mystring). This way formatting characters cannot be arbitrarily injected into printf.

int main(int argc, char **argv)

{

    if(argc <= 1){

        printf("error, no arguments (other than program name)!");

     }

    else

    {

        printf("%s",argv[1]);

    }

}

By statically specifying the format string, no one else can put arbitrary formatting characters in.

Concept Map

This example points to N8 and Input Validation in the Concept Map.

Numeric Overflow

 

What you should not do

Not checking the size or range of integer values input or stored in a program. This can cause indeterminate behavior or program failure.

unsigned short j = 65535;

...

j++;

...

if (j < 500)

{

    grant access to file X;

}

The range of an unsigned short int is 0 to 65,535. What happens if j is somehow changed to a value greater than 65,535? It loops back around beginning at 0 which may result in an incorrect file access.

What you should do

Checking or verifying integer values that can be set beyond the intended range or the range of the type. The key to this error is where and how j is set. If it is not possible to incorrectly set j, then the code will be safe. However, it is still a good programming practice to verify that a given value is in the intended range.

unsigned short j;

...

j++;

...

if(j < 65535){

   j++;

}

else{

    printf("error!");

if (j < 500)

{

  grant access to file X;

}

Concept Map

This example points to M and Bad Code in the Concept Map.

Using sprintf( ) when the input size might be larger than the buffer size

What you should not do

Using the sprintf() function to write an unchecked string to a character buffer. This can cause overwriting of program data and indeterminate program behavior such as segmentation faults or hijacking the the program's flow.

#include <stdio.h>

 int main(int argc, char **argv)

{

    char buf[4];

    sprintf(buf, argv[1]); // if the size of the supplied argument is greater than 5, overflow occurs

    printf("%s\n", buf);

}

What you should do

Avoid using sprintf() because it does not perform argument checking. Use either an alternative function that performs the same function with bounds checking, or check bounds manually befor any use of sprintf().

C offers the alternative function snprintf() which allows the programmer to specify the maximum number of characters to copy into the buffer (including the terminating null) before truncating the rest.

#include <stdio.h>

void  main(int argc, char **argv)

{

    char buf[4];

    snprintf(buf, 4, argv[1]); /* snprintf allows the programmer to specify the max. number of bytes to write  

    to buf (including the '\0' at the end)*/

    printf("%s\n",buf);

}

Linux and BSD-based systems also have a sprintf(), which dynamically allocates enough space for the new string using malloc().

Concept Map

This example points CD and Bad Code, in the Concept Map.

Use standard functions that lack bounds checking

What you should not do

Using certain functions from the standard C library that perform no argument checking. These functions are vulnerable buffer overflows which can result in the overwriting of program data, segmentation faults, or the execution of arbitrary code.

whatsYourName()

{

    char buffer[8];

    printf("Enter your name:");

    gets(buffer); /* If buffer (which is on the stack) has overflowed it could be used to hijack the

    program and have it run "injected" code.*/

    printf("Hello, %s!\n",buffer);

}

The function gets() reads a line from standard input and stores it into buffer. The function gets() does not check to see if the size of the input is greater than the size of the buffer. Other potentially dangerous calls include strcpy(), strcat(), sprintf(), and scanf().

What you should do

Avoid standard C functions that do not perform bounds checking either by using alternative functions that perform the same function with bounds checking or by checking bounds manually for all uses of potentially dangerous functions, if possible.

whatsYourName()

{

    char buffer[8];

    printf("Enter your name:");

    fgets(stdin,8,buffer); /* fgets() reads one less character than is specified from stdin to leave room for

    the terminating null. The rest of the input is truncated.*/

    printf("Hello, %s!\n",buffer);

}

Concept Map

This example points to CD and Bad Code in the Concept Map.

Avoid the use of strcat( ) when the source size might be larger than the residual space in the destination

What you should not do

Using the strcat()function to write an unchecked string to a string buffer. This may cause overwriting of program data, a segmentation fault, or program control flow hijacking (stack smashing).

#include <stdio.h>

 

#define MAXBUF 10

 

int main(int argc, char **argv)

{

    char buf[MAXBUF];           // enough room for 9 characters and one '\0'

    

    strcpy(buf,"hello ");       // use 6 characters

    strcat(buf, "world!\n"); /* append 7 more characters for a total of 13  characters and a '\0': overflow!*/

    printf("%s\n", buf)

    return 0;

}

What you should do

Avoid using strcat() because it does not perform bounds checking. Use either an alternative function that performs the same function with bounds checking or check bounds manually before using strcat(). The C standard library offers strncat() which allows the programmer to specify the maximum number of characters to append to the first argument (note that this should be the number of free characters left, not the maximum length of the resulting string).

#include <stdio.h>

#define MAXBUF 10

int main(int argc, char **argv)

{

    char buf[MAXBUF];           // enough room for 9 characters and one '\0'

    strcpy(buf,"hello ");       // use 6 characters

    strncat(buf, "world!\n", 3);/* Strncat() wants the maximum number of characters it can copy (not counting

    the terminating null). In this case, there are 3 free characters left in buf. The length passed to strncat()

    would typically be equivalent to MAXBUF-1-strlen(buf).*/

    printf("%s\n", buf)

    return 0;

}

Yet another solution would be to create a function that creates a new, dynamically allocated string that would be large enough to hold the combined contents of the initial strings, although you would then need to make sure you do not cause a memory leak. (this is essentially what higher level languages do behind the scenes).

Also note that other replacement functions may exist, such as strlcat(), although strlcat() and strlcpy() are fairly controversial. There is also strcat_s() for Windows.

#include <stdio.h>

#define MAXBUF 10

int main(int argc, char **argv)

{

    char buf[MAXBUF];           // enough room for 9 characters and one '\0'

    strcpy(buf,"hello ");       // use 6 characters

    strlcat(buf, "world!\n", MAXBUF);/* Strlcat() just needs the size of the destination buffer.*/

    printf("%s\n", buf)

    return 0;

}

Concept Map

This example points to CD and Bad Code in the Concept Map.

Improperly bounded string copies

What you should not do

Improperly bounded string copies occur when data is copied from a source to a fixed-length character array. The below program shows that reading from standard input using gets() function into a fixed-length character array until a newline character is read or an end-of-file (EOF) condition is encountered leads to a buffer overflow.

#include <stdio.h>

#include < stdlib.h>

void get_y_or_n(void){

     char response[8];

     puts("Continue? [y] n: ");

     gets(response);

     if (response[0] == 'n')

        exit(0);

     return;

}

The above program has undefined behavior if more than eight characters (including the null terminator) are entered at the prompt. The above code was taken from Chapter 2, page 42 from Robert C. Seacord's book, "Secure Coding in C and C++".

What you should do

The below program has defined behavior for any input, including the assumption that an extremely long line that exhausts all available memory to hold it should be treated as if it were a "no" response. Since, the getline() function dynamically allocates the response buffer, any allocated memory should be released by calling free().

#define _STDC_WANT_LIB_EXT2_1

#include <stdio.h>

#include <stdlib.h>

void get_y_or_n(void){

     char *response = NULL;

     size_t len;

     puts("Continue? [y] n:");

     if ((getline(&response,&len,stdin) <0) || (len && response[0] == 'n')){

          free(response);

          exit(0);

     }

     free(response);

}

The above code was taken from Chapter 2, page 77 from Robert C. Seacord's book, "Secure Coding in C and C++".

Concept Map

This example points CDBad Code and Input, in the Concept Map.

Avoid the use strcpy( ) when the source buffer might be larger than the destination buffer

What you should not do

Using the strcpy()[1] function to write an unchecked string to a string buffer. This can result in overwriting program data, segmentation fault, or the execution of arbitrary code.

#include <stdio.h>

int main(int argc, char **argv)

{

    char buf[4];

    strcpy(buf, "how ya doing?); /* Because the src string's length is greater than 4 (including termination

    \0), overflow will occur, overwriting other data on the stack.*/

    printf("%s\n", buf);

    return 0;

}

What you should do

Avoid using strcpy() because it does not perform bounds checking. Use either an alternative function that performs the same function with bounds checking or check bounds manually for any use of strcpy().

The C standard library usually offers strncpy() which allows the programmer to specify the maximum number of characters to copy into the buffer. Also note that many other replacement functions exist. Use strncpy() carefully as well, due to how it behaves. It does not guarrantee a '\0' at the end of the dest string, and having a truncated string may introduce other problems to the program.

#include <stdio.h>

int main(int argc, char **argv)

{

    char buf[4];

    strncpy(buf, "how ya doing?", 4); /* Copy up to 4 characters into buf, so buf will only be "how", but this

    way it will not overflow. buf[4] = '\0';  strncpy() does not null terminate strings if the limit is

    reached, so do this to be safe*/

    printf("%s\n", buf);

    return 0;

}

In some cases, using dynamically allocated strings might be preferable. You could create a function that creates a new, dynamically allocated string that would be large enough to hold the copied string, although you would then need to make sure you do not cause a memory leak. (this is essentially what higher level languages do behind the scenes, including C++'s std::string class.)

Also note that other replacement functions may exist, such as strlcpy(), although strlcat() and strlcpy() are fairly controversial. There is also strcpy_s()[6] for Windows.

#include <stdio.h>

#define MAXBUF 10

int main(int argc, char **argv)

{

    char buf[MAXBUF];           // enough room for 9 characters and one '\0'

    strcpy(buf,"hello ");       // use 6 characters

    strlcpy(buf, "world!\n", MAXBUF);// strlcpy() just needs the size of the destination buffer

    printf("%s\n", buf)

    return 0;

}

Concept Map 

This example refers to the point CD and Bad Code in the Concept Map.

Improperly bounded string copies

What you should not do

Improperly bounded string copies occur when data is copied from a source to a fixed-length character array. The below program shows that reading from standard input using gets() function into a fixed-length character array until a newline character is read or an end-of-file (EOF) condition is encountered leads to a buffer overflow.

#include <stdio.h>

#include < stdlib.h>

void get_y_or_n(void){

     char response[8];

     puts("Continue? [y] n: ");

     gets(response);

     if (response[0] == 'n')

        exit(0);

     return;

}

The above program has undefined behavior if more than eight characters (including the null terminator) are entered at the prompt. The above code was taken from Chapter 2, page 42 from Robert C. Seacord's book, "Secure Coding in C and C++".

What you should do

The below program has defined behavior for any input, including the assumption that an extremely long line that exhausts all available memory to hold it should be treated as if it were a "no" response. Since, the getline() function dynamically allocates the response buffer, any allocated memory should be released by calling free().

#define _STDC_WANT_LIB_EXT2_1

#include <stdio.h>

#include <stdlib.h>

void get_y_or_n(void){

     char *response = NULL;

     size_t len;

     puts("Continue? [y] n:");

     if ((getline(&response,&len,stdin) <0) || (len && response[0] == 'n')){

          free(response);

          exit(0);

     }

     free(response);

}

The above code was taken from Chapter 2, page 77 from Robert C. Seacord's book, "Secure Coding in C and C++".

Concept Map

This example refers to the point CDBad Code and Input in the Concept Map.

JSN Teki template designed by JoomlaShine.com