Buffer Overflow Vulnerability….
Buffer
Buffer is a region of memory used to temporarily hold data while it is being moved from one place to another. A buffer is used when moving data between processes within a computer. Majority of buffers are implemented in software. Buffers are generally used when there is a difference between the rate at which data is received and the rate at which it can be processed.
In this small program we defined a buffer in form of char of length 5 and its layout in stack in shown in right.
Buffer Overflow
A buffer overflow occurs when more data is written to a specific length of memory or defined buffer in such a way that adjacent memory addresses are overwritten.In Buffer overflow attack the attacker tries to overwrite this buffer so that they can inject their malicious code.
Stack
Stack is a linear data structure which follows a particular order in which the operations are performed. The order may be LIFO(Last In First Out) or FILO(First In Last Out).
Demo
#include<stdio.h>
#include<string.h>
int main()
{
char password[16];
printf(“\n what is secreat password \n”);
gets(password);
if (strcmp(password,“msingh”))
{
printf(“\n you fail”)
;}
else
{
granted();
}
return 0;
}
void granted()
{
printf(“\n access granted \n”);
return;
}
Let’s take an example of a basic authentication code that asks for a password and returns access granted if the password is correct.
Without really knowing how the code works, let’s enter a random password.
It says you fail since the password wasn’t correct. To test, we need to enter large random data.
You must be wondering why there is a Segmentation fault. Let’s see a more detailed version of the code.
As i have defined password buffer of length 16 and since addresses are also stored in hexadecimal. So we tried entering a long password to test this code for buffer overflow and as you can see our input above overflowed the buffer password and gave segmentation fault.
Note: C functions like strcpy()
, strcmp()
, strcat()
do not check the length of the variable and can overwrite later memory addresses, which is precisely what buffer overflow is.
Memory layout of a program
- Stack: A LIFO data structure extensively used by computers in memory management, etc.
- There is a bunch of registers present in the memory, but we will only concern ourselves with EIP, EBP, and ESP.
- EBP: It’s a stack pointer that points to the base of the stack.
- ESP: It’s a stack pointer that points to the top of the stack.
- EIP: It’s a stack pointer that points to the next instruction to be executed.
Layout of stack
- A stack grows in downward direction i.e it is filled from higher memory to lower memory.
- In a stack, all the variables are accessed relative to the EBP.
- In a program, every function has its own stack.
- Everything is referenced from the EBP register.
Why EBP is so important?
EBP is important because it provides an anchor point in memory and we could have a lot of things referenced to that value, when we call a function inside a program and we have some parameters to send to it, the positions in memory are always referenced by EBP as well as the local variables as you could see on the figure.
For example:
void pass(int a, int b, int c){
int x;
int y;
int z;
x=y=z=0;
x=z+y+a+b+c;
return z;
}
int main (int argc, int **argv)
{
pass(5,7,8);
}
Here, a, b, and c are the function parameters stored above the EBP.
- All the local variables of a function are stored below the EBP.
- The old ebp is the value of the EBP of the previous function. Since, after a function is executed, it has to return back to an older function, we need to store the values of both old EBP and EIP.
- ESP register stores the address of the bottom of the stack.
- x, y and z are local variables to the function and are stored below the EBP.
- Since a,b and c are parameters passed to the function, they are stored above the EBP. Also, because the stack is filled from higher to lower memory and parameters are read from right to left, c is written first in the memory, followed by b and a.
- x, y, and z are the local variables stored below the EBP.
- It is also required to store the old EBP and old EIP of the main in the stack to know where to return to after the function executes.
Buffer Overflow representation with data of 80 A’s
In above image a buffer with a length of 12 defined in a function. Now it is overflowed in such a way that it has some random data, followed by the shell code (malicious code) and then the return address which points to the shell code.
So, after the function gets executed, the instruction pointed to by the Return address gets executed and this is how our shell code gets executed.
Security Measures
- Use programming languages like Python, Java, or Ruby in which dynamic memory allocation takes place and the language itself manages the memory for you.
- In languages like C and C++, before writing data to a buffer, perform all the relevant checks and input validation.
- Before using any external libraries, check for security vulnerabilities in it.
- Use source code analysis tools for static analysis against vulnerabilities.
- Use a non-executable stack: This means that even if a machine code is injected into the stack, it cannot be executed as that particular region of memory is non-executable. It is done by setting up NX bit.
- Use ASLR (Address Space Layout Randomization) approach and setting it to 2, which make both stack and heap randomized and make guessing exact addresses difficult.
- Use Stack Control Protector or Stack Guard which also helps in protecting buffer overflows.
Note: Even after these measures are taken, it might be possible to exploit buffer overflow. Therefore, these are just layers of security that can help to prevent the exploitation of buffer overflow.