Chapter 3 - Shellcode
Linux Buffer Overflow With Listening Shell
Purpose
To develop a very simple overflow exploit in Linux. This will give us practice with the following techniques:
Debugging with gdb
Understanding the registers $esp, $ebp, and $eip
Understanding the structure of the stack
Using Golang to create simple text patterns
Editing a binary file with hexedit
Using a NOP sled
Generating a payload with msfvenom
Disabling ASLR
We will disable ASLR to make this project easier.
In a terminal, execute these commands:
The Program
In this program, 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
The fuzzer works, producing a string of "A" characters as shown above.
Fuzzing the Program
Now we can fuzz the program and cause a "Segmentation fault" as shown below.
Using gdb
If we run 1020 characters in the program, when it crashes, the eip value is 0x41414141
, as shown above. This means that 1010 characters although causing the segmentation fault don't overflow eip, so we need to use 1020 characters.
Locating EIP
So we know that 1000 characters don't overflow the program, and that 1010 cause the segmentation fault but only 1020 reach the eip register. Although we are quite sure of that, we should put a nonrepeating pattern of bytes in the last 20 bytes of the exploit, after the 1000 characters to see which characters end up in the eip.
Running the program on gdb with our new fuzzer shows us that the program crash ends with an eip of 0x45454545
that is the ASCII code for "EEEE", as shown below.
Getting Shellcode
The shellcode is the payload of the exploit. It can do anything we 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 (OA) 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.
We can see the exploits available for the Linux platform, which bind a shell to a listening TCP port with this command:
The exploit we want is highlighted above: linux/x86/shell_bind_tcp
We can see the payload options with this command:
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 above. This port has a default value of 4444, but we will choose a custom port.
We can generate exploit code for our Golang exploit using the C language format (msfvenom doesnt support golang yet):
The resulting payload isn't useful for us, because it contains a null byte ("\x00"), as shown above.
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 makes the shellcode more eliable.
We can now execute this command:
The payload is longer (approximately 230 bytes (the exact length varies).
Constructing the Exploit
The program runs, printing out a long string of characters ending in "1234", as shown below.
Finding the NOP Sled in RAM
Now we need to open the program we are going to exploit in gdb
and set a breakpoint at the instruction after the strcpy
call.
After setting the breakpoint we can run the attack.
Now we need to see the registers and notice the address at the bottom of the stack fram (EBP).
By looking at the stack frame, we now need to find an address in the middle of the NOP sled (the 90 bytes), avoiding addresses containing "00", "10", or "20" bytes, which will be treated as delimiters and terminate the string prematurely.
In these case, I selected 0xffffcb90
as shown above.
Completing the Exploit Code
Now to complete the exploit code, we need to insert our chose address into the program in the eip
variable, in little-endian byte order. This time I will show the exploit in both python3 and Golang (the address in the examples might be different, because I tried different addresses during my trial and error proccess with both languages to come out with an exploit, since all the examples are in python2).
Python3
Golang
Testing the exploit in the Debugger
Testing the exploit outside of the Debugger
Last updated
Was this helpful?