Learn about buffer overflows and the cybersecurity measures you can take to avoid this programming vulnerability.
In programming, a buffer is an area in the computer’s memory that usually holds data temporarily. On many systems, these areas are stored one after another in the memory.
A buffer overflow is an anomaly where a program overruns the boundaries of such a buffer with fixed length while writing to it. When that happens, adjacent memory locations can get overwritten which can lead to undefined and potentially dangerous behavior.
The Consequences of Buffer Overflow
When a buffer with fixed length overflows, the data, stored in adjacent memory blocks, gets overwritten. The consequences of this range from a simple segmentation fault, which will cause the program to stop, to more severe problems, like a hijacked system where an attacker can gain full access to the computer.
Buffer Overflow Attack Example
The following example demonstrates what a vulnerable program looks like.
Overwriting Other Variables
The following example demonstrates what a vulnerable program looks like. In the application, two buffers, a and b, are created. Both have a fixed size of five characters. Because these buffers represent strings, the last character is a null-byte and the buffer’s effective size is, therefore, four bytes:
This example contains two buffers with four bytes each.
The program then prompts the user to enter a string. When the user hits the enter key, the entered string gets written to a and the contents of both buffers get printed to the console:
Entering a string into the program.
As you can see, when a user enters four characters (1, 2, 3, 4 in this case), the program behaves as it should. However, if more than five characters get entered, this is what happens:
Entering more than five characters shows the program's vulnerability.
Buffer a now seems to be six characters long while b seems to contain only one character. However, what they seem to contain is not what they actually contain. Both buffers are still four characters long, but the value of b — or at least the first two bytes — got overwritten:
Entering more than four characters causes buffer a to overflow and buffer b to overwrite.
As you can see, the string-terminator is missing in a. Instead, it got stored in b after the first character. More importantly, buffer b was overwritten because buffer a overflowed. Furthermore, the application now behaves unpredictably.
Overwriting Other Values
While the first example is already pretty dangerous, it gets even worse when other values of a program’s stack (for example, the return address) get overwritten. This will allow an attacker to hijack the program and call other functions of the program.
If an attacker can inject their executable code and make the return address point to it, they may even be able to hijack the entire system and gain administrator privileges.
How to Prevent Buffer Overflows
While programming languages like C and C++ don’t offer built-in protection for this vulnerability, many compilers and modern operating systems do. Usually, this built-in protection prevents an attacker from overwriting variable values and addresses on the stack.
Those mechanisms, however, won’t protect your code from crashing when a user enters a malformed input string. An effective and simple countermeasure is to always check input values. Furthermore, avoid using functions like strcpy. Instead, use their length-limited version (for example strncpy). The vulnerability described in the example above can be fixed by using fgets instead of scanf:
Using fgets instead of scanf helps prevent buffer overflow in our example.
Pay close attention when checking for boundaries and make sure you stop at the correct length. As shown above, strings need a terminator and you can, therefore, not utilize the entire buffer.
Buffer Overflows are Dangerous but Avoidable