Buffer Overflow (ret2func)

7 minute read

I

EXPLOITING STACK BUFFER OVERFLOWS OVER FUNCTIONS


BUFFER OVERFLOW

A buffer overflow occurs when the size of data exceeds the storage capacity of the memory buffer

As a result, the program will try to write the data to the buffer which overwrites nearer memory locations Instruction Pointer(IP), Base Pointer(BP)

C and C++ are two languages that are highly susceptible to buffer overflow attacks, as they don’t have built-in safeguards against overwriting or accessing data in their memory

Mac OSX, Windows, and Linux all use code written in C and C++.

WHAT ARE BUFFERS?

Buffers are memory storage regions that temporarily hold data while it is being transferred from one location to another

CAUSE & MITIGATTION

Buffer overflow is triggered by user input

In the case of buffer overflow vulnerabilities, the developer must check the input length before using any functions that might cause an overflow to happen

These attacks are caused by vulnerable functions in C

The following five common unsafe functions that can lead to a buffer overflow vulnerability:

printf, sprintf, strcat, strcpy, and gets.

Unfortunately, the base C language provides only one safe alternative: fgets (to be used instead of gets). Various platforms have their non-standard implementations. For example, the Microsoft version of C includes sprintf_s, strcpy_s, and strcat_s

You can also protect against buffer overflows by using an extension of a compiler that uses “canaries”

The canaries are special values that the compiler places on the stack between the location of the buffer and the location of control data

When a buffer overflow occurs, it is the canary that is corrupted first and this corruption can be immediately detected

MEMORY LAYOUT

The memory layout of a binary in stack can be reprsented as

I

The buffer space grows towards the Base Pointer (BP) and Instruction Pointer (IP) from lower memory to higher memory

I

Below Base Pointer (BP) there will be Instruction Pointer (IP)/Return Address

The stack components of the program are always stored above the Base Pointer (BP)

EXAMPLE

Lets consider this simple program

I

Compile this to binary

I

Here we have declared a ‘buffer’ space for char array variable of 32 bytes

So by theory this buffer space of this variable should hold only 32 bytes

Lets check it by passing inputs of random length

I

If we pass input with size less than 32 bytes,it runs perfectly

But if this size limit exceeds,it stores this input from the starting space of the ‘buffer’ and it ends in memory where the input data ends

Until that size, our input can overwrite the buffer space in the stack memory

This leads to serious flaw by which an attacker can change the track of the program

When we overwrite some important registers like Instruction Pointer (IP) and Base Pointer (BP),it points to an address which can be utilized for exploitation

It the address is not meaningful, it gives “ERRORS”(Segmentation Fault/Stack Smashing Detected/Core Dumped)

But with the help of the input values we can ovewrite these important register correctly to acheive our desired task/function


EXPLOITATION

Lets see how to use buffer overflow in stack to call another function from the memory

In this program we can see a function named “hidden” which is not being called in “main()”

So the actual program should receive input and print it as output

It should not display the contents inside the “hidden()”

I

To test stack based buffer overflows in Linux, you need to compile the source code with certain flags to enable “DISABLE STACK PROTECTION & STACK EXECUTION”

I

STEP 1 : CHECKING ASLR

Here we use a debugging line to print the address of “hidden()” function

Whenever this function needs to be called, our binary uses “call address_of_hidden()” in ASM to run “hidden()”

This program prints random address for “hidden()” whenever it is being called

I

This is because of ASLR present in the machine

ASLR (Address Space Layout Randomization)

Address space layout randomization (ASLR) is a memory-protection process for operating systems (OSes) that guards against buffer-overflow attacks by randomizing the location where system executables are loaded into memory

Lets disable ASLR to get the fixed address of “hidden()” to perform successful buffer overflow attack

I

Now the ASLR is disabled

Lets check for the address of “hidden()”

I

No matter how many times we run, it always gives us fixed address of “hidden()” when we try to run the program, because ASLR is disabled

STEP 2 : CRASHING THE PROGRAM

When all the protections are disabled, try to crash the program with inputs of random sizes

I

You can see that this program also gets crashed due to the size of the input passed which is larger than the buffer size

We can also view the crash with traps using “dmesg”

I

By seeing this we can come to a conclusion that this program is vulnerable to buffer overflow attack

STEP 3 : FINDING OFFSET

Lets pass the input data to crash the program and test it in GDB Debugger

I

So, when we pass the random junks of ‘A’ in input it causes an error

And during the crash the Base Pointer (BP) value is set as 0x4141414141414141

Here we can say that our junk input overwrote the Base Pointer (BP) register

We need to find the offset(location) of the Base Pointer (BP) so that we can craft our payload precisely

Lets create a random pattern of 100 bytes with “GDB-PEDA” and pass it through the program

I

Our pattern overflowed the buffer space and the Base Pointer (BP) causing an error

In this , we can see that our Base Pointer (BP) is filled by a random value from the pattern we passed as input

I

This value is a part of our pattern we passed

I

So this value can be used to find the offset of our Base Pointer (BP)

I

By calculating the offset it says that our Base Pointer (BP) memory starts after 64bytes of the “buffer” memory

STEP 4 : CONTROLLING INSTRUCTION POINTER

We know where our Base Pointer (BP) starts

Next to Base Pointer (BP) is the Instruction Pointer (IP)

Instruction Pointer (IP)

It is a register responsible for storing the address of next instruction which is needed to be executed in stack 

The main goal of all buffer overflow attacks is to overwrite the Instruction Pointer (IP) which can help the attacker to redirect the program to their purpose

We know that for x64 architecture,
Base Pointer (BP)        ---> 8 bytes
Instruction Pointer (IP) ---> 6 bytes
'A' in hex               ---> 0x41
'B' in hex               ---> 0x42

Lets pass an input crafted with the help of python to check,whether we can overwrite the IP or not

I

Here we have ‘A’s to fill upto BP

And 8 ‘B’s to fill BP

And 6 ‘B’s to fill IP

Lets pass this input and check it

I

Here we can see that BP and IP is overwritten successfully

I

STEP 5 : EXPLOITING WITH PAYLOAD

Now we have verified that we can overwrite IP successfully

To spawn the function “hidden()” we need to call it using IP

When IP is pointed with the address of “hidden()”,it executes the contents in the “hidden()” and allocates the registers according to the stack and continues the execution

I

Since we are using “LITTLE ENDIAN” our address should be represented in reverse order

Lets test the payload

I

Here we can see our “hidden()” function has been pwned successfully

Lets try this out of debugger

I

EXPLOIT IS DONE

STACK BUFFER OVERFLOW IS PERFORMED


Exploit Sample Is Given In GitHub Repo

AidenPearce369