What is a Buffer Overflow attack?
Like other memory corruption bugs, Buffer Overflow attacks aim to bring a program into a profitable invalid state (a state that the program wasn’t initially designed to be in), they take advantage of the lack of bound checks in programs written in low level programming languages (such as C and C++), where the programmer is responsible for allocating memory buffers and making sure to not feed more data than these buffers can handle. These attacks often lead to remote command execution.
What are its types?
Stack-based Buffer Overflows
When a program statically allocates local variables (for example, an array of characters), a buffer will be reserved on the stack frame of that function to hold that array. When a function calls another function, the program needs to know where in the caller function to return after executing the callee function. So before making a function call, the caller needs to push the return address onto the stack before jumping to the callee function. And because that return address is located on the stack, feeding more data into a statically allocated buffer results in corrupting the stack, and overwriting the return address. With this basic technique, an attacker can take control of the program, and redirect its execution flow wherever he/she wants to.
Heap-based Buffer Overflows
Unlike stack-based buffer overflows, a buffer overflow on the heap leads to the corruption of heap chunks (a data structure handled by dynamic memory allocators, such as ptmalloc2). This often leads to unexpected results, and can also lead to remote command execution. These exploits are often achieved by overwriting a function pointer to take control of the program execution flow, which involves a deep understanding of the inner workings of the target heap memory manager (see the latest vulnerability in the `sudo` binary, tracked as CVE-2021–3156).
Buffer Overflows in other data segments
A buffer overflow can also take place in the .bss section (a memory region reserved for non-initialized global and static variables). However, the exploitability of this type of buffer overflows depends on the program logic, and the data being overwritten (for example, if there’s a global variable holding a function pointer and it can be overwritten through a buffer overflow, then an attacker may be able to control the execution flow of the program).
How to protect against Buffer Overflow attacks?
- Don’t use vulnerable functions such as gets (and scanf for instance, when using “%s” to read a string without specifying the field width) and strcpy. Instead, you can use fgets and strncpy which support an additional size argument.
- Compile your program with full protections (Stack canary, PIE, DEP and Full RelRO (if you don’t care about small performance overheads, otherwise, the default Partial RelRO would do)).
- Make sure ASLR is enabled on the system.
- Employ a secure coding mindset when writing code, instead of doing it at the very end of a project.
- If you’re new to low level programming and come from programming languages where arrays start from 1, keep in mind that arrays start from 0 in programming languages such as C and C++. This is valuable information to avoid off-by-one bugs.