OSCP Buffer Overflow Guide (Windows)

A walkthrough of the process to create a buffer overflow in windows in preperation for OSCP. This guide should be used with the walkthrough youtube video: https://www.youtube.com/watch?v=tUWCmpxWYdo

1. Play with the Program

First and foremost we should play with the application, see how it works. how many inputs it takes, is there a command we have to enter before we get to our overflow command, etc.

Make sure the program is running in immunity and connect to it with nc:

nc -nv <IP> <PORT>

2. Crash Replication

This step is finding a reliable way of crashing the application. This will usually be sending a string of A's, this can be done manually or writing a small python program.

circle-info

Sometimes the buffer can be very small (200-300 chars) and sometimes very large (10000+) so adjust your fuzzing accordingly

python -c 'print"A" * 1000'

If we want to automatically fuzz with increments of 100 we can use the following:

Fuzz.py (default script will send increments of 100)

#!/usr/bin/python 
import sys,socket 
import time 
address = '<target IP>' 
port = <PORT> 
buffer = ['A'] 
counter = 100 
while len(buffer) < 10: 
 buffer.append('A'*counter) 
 counter=counter+100 
try: 
 for string in buffer: 
  print '[+] Sending %s bytes...' % len(string) 
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
  connect=s.connect((address,port)) 
  s.send(string + '\r\n') 
  s.recv(1024) 
  print '[+] Done' 
except: 
  print '[!] Unable to connect to the application. You may have crashed it.' 
  sys.exit(0) 
finally: 
 s.close()

Once we know the number for a crash, we can now create our exploit and update the code with what we know.

Creating exploit.py

triangle-exclamation

Create this python code and fill in all the blanks. edit the code with the correct IP and port and change the exploit code part to send and receive what the application is expecting to send and receive up until our buffer. Running our code we should get a reliable crash of the application every time we run it. only then should we move on.

Once we have a reliable crash we can move on to finding the offset.

3. Finding the Offset

To find the offset we send a unique string of characters to the program and look at the value of the EIP register, We can then use this value to find the offset.

First we generate a unique string:

Kali:

Web:

Once we have created the unique string. We send this to the program. At the point of crash we can then copy the value from EIP and calculate the offset.

in kali:

4. Controlling EIP

Now we have the offset we can change our python code to double check that we are controlling EIP. So we send the offset number of 'A's, we then send 4 'B's (these should appear in EIP) and lastly we send the remainder of our PoC crash (3000) as C's, as this is where our payload will go later on.

We can also try increasing the number of C's to give us more room for our payload. We need a minimum of 350 characters for a Remote Access Trojan

5. Finding Bad Characters

To find the bad characters we need to send a string from \x00 all the way to \xFF. \x00 is a null byte, and is usually always a bad character.

Python Program to generate bad chars:

Output:

To adjust our python program we can add the string to the badchars variable and uncomment it. we can then change the fuzz variable to the following:

We can now send this string to the program in place of the shell code. Once the program has crashed we can follow "ESP in dump" and view the hexdump. Going through each value we should be able to determine if there are any bad characters due to it missing or changing subsequent values.

We then keep a note of these bad characters, remove them from the string and run it again until all bad characters have been discovered.

6. Redirecting Execution

Once we have discovered all the bad characters the next step is to tell the program to execute our payload. Replacing our B's with the address of ESP will not work as these address values change every time the program crashes or is reset.

So we need to find a "JMP ESP" command hard coded within the program or .dll to use. Using this instruction will redirect EIP to our payload located in ESP.

To find jmp esp commands run the following:

This command searches for JMP commands pointing to ESP. The reason we list the bad characters is because we do not want these characters appearing in the address of the jmp command as it will corrupt our python code.

circle-exclamation

7.Endianness

Once we have discovered an address we would like to use we need to convert it into bytes for our python code to read. we also need to determine the endiannessarrow-up-right of the program. In short if the system uses big endian, the stack gets filled from the top to the bottom and little endian is filled from the bottom towards the top.

So how does this affect us?

If we have an address of 0x625011AF

if we convert it to Little Endian it will look like: \xAF\x11\x50\x62

And if we convert it to Big Endian it will look like: \x62\x50\x11\xAF

triangle-exclamation

8. Creating Payload

Once we are sure that our code is working and redirecting execution to our payload. we can then go ahead and create our payload to grant us a reverse shell. kali:

  • msfvenom: metasploit payload generator

  • -p: type of payload

  • LHOST: Local IP address

  • LPORT: local port

  • -a: architecture of target system

  • --platform: Operating system of target

  • -b: bad chars

  • -e: encoder (used to bypass antivirus)

  • -f: format of output (py = python output)

9. NOPS

Once we have generated our payload we need to add in padding to provide space for our payload to decode itself. We can use NOParrow-up-right instructions for this which are represented in hex as \x90.

So our final buffer should look something like:

  • buffer: Variable name

  • prefix: instruction for program

  • " ": space

  • fuzz: lots of A's (offset amount)

  • retrn: return address (jmp esp)

  • padding: NOPS to allow payload to decode

  • buf: shellcode for reverse shell

10.TROUBLESHOOTING

  • Check IP address - You may be pointing at your dev machine instead of the target you are trying to exploit

  • Make sure we are using the right payload in msfvenom for the target

  • Make sure to use correct port, sometimes firewalls will block port 4444 for example so we may want to use a common port such as 443

  • Is you Edianness correct?

  • Check Encoder (using one might be an issue) - x86/shikata_ga_nai

  • Verify Shellcode space. We need at least 351 bytes available to us for shellcode space after our jump to esp.

Last updated