Protections against buffer overflow exploits in Linux
Linux has several inbuilt protection mechanisms to deal with malicious buffer overflow attacks. Some of them are built into kernel while some of them are part of compiler tools such as gcc, g++.
- Address space Layout Randomization (Kernel)
- Executable Stack Protection (Compiler)
- Stack smashing protection (Compiler)
- Position Independent Executables (Compiler)
- Fortify Source (Compiler)
- Stack Protector (Compiler)
Address Space Randomization is a technique in which various parts of executable such as data, stack and code are randomly given start addresses whenever a program starts. This makes difficult for an attacker to guess let’s stay the base of stack in order for him to successfully launch the buffer overflow attack. ASLR can be disabled in linux with the following command
To reneable just echo it with a positive integer, for ex
Executable Stack Protection is another technique of preventing buffer overflow attacks. As a result of this protection, the stack portion of the memory is marked non executable. To check if the stack is executable or not, run the following command
The following line , shows that stack is Read Write but not executable
In order to make the stack executable, the program needs to be compiled with -z execstack option
In that case, the output of readelf program would be
Stack smashing protection refers to compiler generated protection techniques of smash stacking. Refer to wikipedia link to get more details about the techniques involved in this protection. This can be disabled in gcc as follows:
Windows Implementation The /GS switch is a compiler option that will add some code to function’s prologue and epilogue code in order to prevent successful abuse of typical stack based (string buffer) overflows.
When an application starts, a program-wide master cookie (4 bytes (dword), unsigned int) is calculated (pseudo-random number) and saved in the .data section of the loaded module. In the function prologue, this program-wide master cookie is copied to the stack, right before the saved EBP and EIP. (between the local variables and the return addresses)
[buffer][cookie][saved EBP][saved EIP] During the epilogue, this cookie is compared again with the program-wide master cookie. If it is different, it concludes that corruption has occurred, and the program is terminated.
In order to minimize the performance impact of the extra lines of code, the compiler will only add the stack cookie if the function contains string buffers or allocates memory on the stack using alloca. Furthermore, the protection is only active when the buffer contains 5 bytes or more.
In a typical buffer overflow, the stack is attacked with your own data in an attempt to overwrite the saved EIP. But before your data overwrites the saved EIP, the cookie is overwritten as well, rendering the exploit useless (but it may still lead to a DoS). The function epilogue would notice that the cookie has been changed, and the application dies.
|buffer||cookie||saved EBP||saved EIP| |AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA| ^ |
The second important protection mechanism of /GS is variable reordering. In order to prevent attackers from overwriting local variables or arguments used by the function, the compiler will rearrange the layout of the stack frame, and will put string buffers at a higher address than all other variables. So when a string buffer overflow occurs, it cannot overwrite any other local variables.
Position Independent Executables (PIE) In order to take advantage of Address Space Layout Randomization (ASLR), programs need to be built as Position Independent Executables (PIE) with -fPIE –pie flag. PIE has a 5-10% performance penalty on architectures with small numbers of general registers (e.g. x86).
Fortify Source enables several compile-time and run-time protections including protections against overflows. In order to use Fortify Source which provides run-time checks of buffer lengths and memory regions, programs need to be built with -D_FORTIFY_SOURCE=2 flag.
Stack Protector is enabled at compile-time with -fstack-protector flag. It enables run-time stack overflow verification protecting against stack overflows, and reducing the chances of arbitrary code execution via controlling return address destinations.