≡ Menu

Buffer Overflow Attack Explained with a C Program Example

Buffer overflow attacks have been there for a long time. It still exists today partly because of programmers carelessness while writing a code. The reason I said ‘partly’ because sometimes a well written code can be exploited with buffer overflow attacks, as it also depends upon the dedication and intelligence level of the attacker.

The least we can do is to avoid writing bad code that gives a chance to even script kiddies to attack your program and exploit it.

In this buffer overflow tutorial, we will discuss the basics of the following :

  • What is buffer overflow?
  • How a buffer overflow happens?
  • How a buffer overflow attack takes place?
  • How to avoid buffer overrun?

We’ll keep the explanation and examples simple enough for you to understand the concept completely. We’ll also use C programming language to explain the buffer overflow concept.

What is Buffer Overflow?

A buffer, in terms of a program in execution, can be thought of as a region of computer’s main memory that has certain boundaries in context with the program variable that references this memory.

For example :

char buff[10]

In the above example, ‘buff’ represents an array of 10 bytes where buff[0] is the left boundary and buff[9] is the right boundary of the buffer.

Lets take another example :

int arr[10]

In the above example, ‘arr’ represents an array of 10 integers. Now assuming that the size of integer is 4 bytes, the total buffer size of ‘arr’ is 10*4 = 40 bytes. Similar to the first example, arr[0] refers to the left boundary while arr[9] refers to the right boundary.

By now it should be clear what a buffer means. Moving on lets understand when a buffer overflows.

A buffer is said to be overflown when the data (meant to be written into memory buffer) gets written past the left or the right boundary of the buffer. This way the data gets written to a portion of memory which does not belong to the program variable that references the buffer.

Here is an example :

char buff[10];
buff[10] = 'a';

In the above example, we declared an array of size 10 bytes. Please note that index 0 to index 9 can used to refer these 10 bytes of buffer. But, in the next line, we index 10 was used to store the value ‘a’. This is the point where buffer overrun happens because data gets written beyond the right boundary of the buffer.

It is also important for you to understand how GCC compilation process works to create a C executable.

Why are buffer overflows harmful?

Some of us may think that though a buffer overflow is a bad programming practice but so is an unused variable on stack, then why there is so much hullabaloo around it? What is the harm buffer overrun can cause to the application?

Well, if in one line we have to summarize the answer to these questions then it would be :

Buffer overflows, if undetected, can cause your program to crash or produce unexpected results.

Lets understand a couple of scenarios which justify the answer mentioned above.

1. Consider a scenario where you have allocated 10 bytes on heap memory:

char *ptr  = (char*) malloc(10);

Now, if you try to do something like this :

ptr[10] = 'c';

Then this may lead to crash in most of the cases. The reason being, a pointer is not allowed to access heap memory that does not belong to it.

2. Consider another scenario where you try to fill a buffer (on stack) beyond it’s capacity :

char buff[10] = {0};
strcpy(buff, "This String Will Overflow the Buffer");

As you can see that the strcpy() function will write the complete string in the array ‘buff’ but as the size of ‘buff’ is less than the size of string so the data will get written past the right boundary of array ‘buff’. Now, depending on the compiler you are using, chances are high that this will get unnoticed during compilation and would not crash during execution. The simple reason being that stack memory belongs to program so any buffer overflow in this memory could get unnoticed.

So in these kind of scenarios, buffer over flow quietly corrupts the neighbouring memory and if the corrupted memory is being used by the program then it can cause unexpected results.

You also need to understand how you can prevent stack smashing attacks with GCC.

Buffer Overflow Attacks

Until now we discussed about what buffer overflows can do to your programs. We learned how a program could crash or give unexpected results due to buffer overflows. Horrifying isn’t it ? But, that it is not the worst part.

It gets worse when an attacker comes to know about a buffer over flow in your program and he/she exploits it. Confused? Consider this example :

#include <stdio.h>
#include <string.h>

int main(void)
{
    char buff[15];
    int pass = 0;

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

    if(strcmp(buff, "thegeekstuff"))
    {
        printf ("\n Wrong Password \n");
    }
    else
    {
        printf ("\n Correct Password \n");
        pass = 1;
    }

    if(pass)
    {
       /* Now Give root or admin rights to user*/
        printf ("\n Root privileges given to the user \n");
    }

    return 0;
}

The program above simulates scenario where a program expects a password from user and if the password is correct then it grants root privileges to the user.

Let’s the run the program with correct password ie ‘thegeekstuff’ :

$ ./bfrovrflw 

 Enter the password :
thegeekstuff

 Correct Password 

 Root privileges given to the user

This works as expected. The passwords match and root privileges are given.

But do you know that there is a possibility of buffer overflow in this program. The gets() function does not check the array bounds and can even write string of length greater than the size of the buffer to which the string is written. Now, can you even imagine what can an attacker do with this kind of a loophole?

Here is an example :

$ ./bfrovrflw 

 Enter the password :
hhhhhhhhhhhhhhhhhhhh

 Wrong Password 

 Root privileges given to the user

In the above example, even after entering a wrong password, the program worked as if you gave the correct password.

There is a logic behind the output above. What attacker did was, he/she supplied an input of length greater than what buffer can hold and at a particular length of input the buffer overflow so took place that it overwrote the memory of integer ‘pass’. So despite of a wrong password, the value of ‘pass’ became non zero and hence root privileges were granted to an attacker.

There are several other advanced techniques (like code injection and execution) through which buffer over flow attacks can be done but it is always important to first know about the basics of buffer, it’s overflow and why it is harmful.

To avoid buffer overflow attacks, the general advice that is given to programmers is to follow good programming practices. For example:

  • Make sure that the memory auditing is done properly in the program using utilities like valgrind memcheck
  • Use fgets() instead of gets().
  • Use strncmp() instead of strcmp(), strncpy() instead of strcpy() and so on.
Add your comment

If you enjoyed this article, you might also like..

  1. 50 Linux Sysadmin Tutorials
  2. 50 Most Frequently Used Linux Commands (With Examples)
  3. Top 25 Best Linux Performance Monitoring and Debugging Tools
  4. Mommy, I found it! – 15 Practical Linux Find Command Examples
  5. Linux 101 Hacks 2nd Edition eBook Linux 101 Hacks Book

Bash 101 Hacks Book Sed and Awk 101 Hacks Book Nagios Core 3 Book Vim 101 Hacks Book

Comments on this entry are closed.

  • xiaogang June 4, 2013, 7:56 am

    well work, thank you!

  • C++ June 4, 2013, 11:02 am

    How about in C++ ?
    Pls…….
    Many thanks!

  • Braden Talbot June 4, 2013, 12:05 pm

    I’ve always wondered what was so dangerous about buffer overflow besides funky program behavior. I never considered the ‘non-zero-ness’ of the return in cracking a password. Thanks for the article.

  • Bruno Santos June 4, 2013, 2:23 pm

    Love the tutorial ! It’s really interesting and clarifying.

    I’ve read the examples and try them myself, but one question pops into my mind and i wonder why (i’m not new to programming, but my C is very rusty).

    The example works because the memory location of the pass variable is just next to the location of the buffer, so it gets overwritten !

    My question: Is it always like this ? I’ve always been told the location is quite random..
    Is is true ?

    Thank you !

  • Erlo June 4, 2013, 3:55 pm

    Nice and to-the-point article.

    The example code shows two flaws:
    – Input shall *always* be checked for length and invalid characters before using it, especially if it is user input.
    – The conditional ‘if (pass)’ should be rewritten as ‘if (1 == pass)’ in order to only let a valid value of pass cause the test to become true.
    Defensive coding is important when it comes to accepting input, no matter if it is from a carbon unit or another machine.

    C++ makes this a little easier if the standard container library is used, as there are structures with bounds checking.

    Static analysis tool like Lint might point out some of these buffer overflow issues.

  • Jalal Hajigholamali June 4, 2013, 10:38 pm

    Hi,

    Nice article,

    Thanks a lot…

  • Majid Khan June 4, 2013, 11:38 pm

    Enjoyed the article, very well explained about the buffer overflow..

  • sysadmin June 5, 2013, 1:39 am

    Hi,
    very simply and very good explanation.
    Thank you!

  • Sh June 5, 2013, 2:44 am

    Very nice article. Thanks

  • Envenler June 5, 2013, 11:44 pm

    Hi,I got the program tested, and if I entered 20 chars , it told me segment error !

  • Pratiksinh June 6, 2013, 10:46 am

    This is a great explanation. Thnxx 🙂

  • under June 7, 2013, 11:42 am

    Now we ( beginner ) know buffer overflow because of this article.
    How about buffer underrun ?

  • Anilkumar June 7, 2013, 12:19 pm

    Thanks for the explanation with a good example.Can you please also explain • Cross Site scripting & • SQL Injection in the coming posts.

    Regards
    Anil

  • Musikolo June 22, 2013, 10:06 am

    Very good way to explain a quite complex security issue.

    Great job!

  • Mahyar Kari July 2, 2013, 11:47 am

    thanks.

  • Mr Greg October 9, 2013, 12:55 am

    Great explanation. Wish my course just put it plain and simple like the above. Now I understand why buffer checking is important.

  • anon October 10, 2013, 10:43 pm

    I compiled the example using gcc compiler but when I try to do a buffer overflow attack just get an error (*** stack smashing detected ***) and execution ends. The example didn’t work until disable the Stack-smashing protection as follows:
    gcc -fno-stack-protector example.c

  • Mayank December 15, 2014, 4:26 am

    This code is not vulnerable in devc++

  • Mike Jones February 11, 2015, 4:23 am

    Hi, just a quick one, I think there is an error here, no?

    if(strcmp(buff, “thegeekstuff”))
    {
    printf (“\n Wrong Password \n”);

    Doesn’t this imply that if you enter”thegeekstuff” as a password, it should stay wrong password, not password is correct?

  • peter March 2, 2015, 7:53 am

    Thankyou so much, i was wondering why i was getting errors in my code…

  • peter March 2, 2015, 7:55 am

    i would like more examples of using buffer overflow attacks

  • Pavan March 27, 2015, 12:05 am

    Nice explanation thanks.

  • Ashwini August 4, 2015, 12:40 am

    this s very nice d very simple explanation. this s for the people who does not know anything of the topic. thank u so much

  • Mike Jones has trouble August 22, 2015, 2:32 pm

    Mike Jones has trouble with basic C comprehension. Furthermore, Mike Jones seems unable to look up the man page for the strcmp() function, and prefers to ask questions before investigating on his own. This says something about Mike Jones.

  • MacPoison September 10, 2015, 11:45 pm

    Dear Thegeekstuff team. This code is in each point of it vulnerable –> That was the sence of it.
    But how can they avoid bufferoverflow attacks?
    You leave this question unanswered.
    I’ve modifyed your code, to show how the “right” code should look like.

    #include 
    #include 
    
    int main(void)
    {
        
        int pass = 0;
        
        printf("\n Enter the password : \n");
        FILE *fp;
       int buff[10];
        char *p;
        
        p = gets (buff);  /* Uh-oh. Don't panic. See below. */
        if (p == NULL) {
            printf("Password was NULL\n");
        } else {
            
            if(strcmp(buff, "thegeekstuff"))
            {
                printf ("\n Wrong Password \n");
            }
            else
            {
                printf ("\n Correct Password \n");
                pass = 1;
            }
            
            if(pass)
            {
                /* Now Give root or admin rights to user*/
                printf ("\n Root privileges given to the user \n");
            }
            
            
            
            return 0;
    
        }
       
        
       
    }
    

    PS: If you saw, that i’m using the gets() function and you know that this function is vulerable, good job!

    Use scanf() instead of gets()

  • Grwww September 13, 2015, 7:36 am

    Each C compiler and OS has different practices for how automatic (on the stack) variables are allocated space. On some platforms, you’ll never see the int on the stack after the buffer, and thus it’s not possible to create this specific type of exploit. But, you can still overwrite what follows ‘buff’ in memory and that is often stack contents, which is how virus exploits over network connections usually happen on buffer overruns.

    Spend some time printing out the address of the variables to see how they line up in memory. In this example, you can see that C has no explicit checks on what happens to memory with some of the library routines. Newer operating systems and related C runtimes include things like pre-return stack checks to see if the stack has been corrupted. Others may assert memory protection in certain places so that “random” writes to memory cause runtime faults which stop the program.

    In the end, programmers need to know about all of these stuff and make the right choices on how to mitigate exploitation of their code, as well as inadvertent buffer overruns by the users which compromises the stability of their software.

    Always test your software by sending it huge amounts of unexpected data at all the points it consumes data from outside sources. Make sure you are handling those conditions in a safe way which allows you to notify the user of a problem, instead of allow viruses in, or causing your users to lose data when your software crashes.

  • Manuel September 14, 2015, 8:10 am

    I tried this but didn,t work, but shows the following message ::
    Enter the password :
    hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
    Wrong Password
    *** stack smashing detected ***: ./bufflow terminated
    Aborted (core dumped)

  • Anonymous February 10, 2016, 12:28 am

    thank you!!!

  • LYDIE MWANZA April 7, 2016, 4:24 am

    How to improve this code to avoid data overflow

    #include
    #include
    int main (void) /* this is simplest buffer overflow C programming */
    {
    char name[4]; /*the size of characters for the name or name buffer size is maximum 4 characters */
    char etc_passwd[4];
    char password[4];
    printf(“Enter Your Name: “);
    gets(name);
    printf(“Enter Your Password: “);
    gets(password);
    printf(“Your name and password entered were %s and %s.”, name, password);
    printf(“The password for %s in /etc/shadow file is %s.”, name, etc_passwd);
    return 0;
    }

  • Azam April 21, 2016, 4:00 pm

    Thanks a lot for the nice article 🙂

  • prashant May 15, 2016, 1:27 pm

    good one !!!

  • bhumika gupra January 20, 2017, 6:37 pm

    Cleared the concept! Thanks alot 😀

  • Ron H February 4, 2017, 2:32 pm

    Thank you. You explained it in a way I can understand it.

  • Anonymous February 15, 2017, 11:59 pm

    nice article 🙂

  • Vishal April 5, 2017, 11:42 pm

    Perfectly explained!

  • steph April 19, 2017, 2:55 am

    Sorry but this is not a good example, it’s logic is flawed and cannot reproduce a buffer overflow in any ways.