The first RuxCon talk was on the first day at 9:00AM in the morning, after a drinking night. The room was also much more full at 9:10AM, and people couldn't get in :D
|Ty and Me|
Ty and I decided to release the new BeEF Bind research at RuxCon for various reasons:
- RuxCon is an old and underground conference, full of proper hackers and friends, not script-kiddies;
- many people from the project (Wade, Brendan, Christian, Ben, Scotty, basically everyone except Ryan, Heather, Saafan, Bart, and Quentin and me :-) are from Australia;
- I've never been in the land of the kangaroos.
The research is revitalizing Wade's research on IPEC (2007) in the following ways:
- We're using XmlHttpRequest instead of HTML forms to send cross-domain POST requests
- A new staging shellcode has been developed to be used specifically for this attack technique
- Everything has been merged into BeEF, with new exploitation reliability features
The original idea about IPEC is to exploit "tolerant" network protocols which do not close the client connection if non-valid protocol commands are sent. Lets say you have an IMAP server, and instead of sending LOGIN ciccio PASS pasticcio, which are valid commands, you send LOGIN ciccio CAZZ pasticcio. CAZZ is not a valid command for the IMAP protocol, but even if we fuzz the endpoint for thousand times sending the same CAZZ garbage, the connection is never closed unless we close it explicitly from the socket.
This behavior is different across protocol implementations, so you might find an IMAP implementation which does not behave in the following way. Our tests were focused mainly on IMAP, SIP, IRC and a few SMTP implementations. More details about this will be released in the near future.
You can clearly see that this behavior has an obvious flaw. We can exploit it encapsulating the data for this protocol with another one, lets say HTTP, because data which is not valid is just rejected but it is still parsed. This practically means the following HTTP request can be sent:
|Wireshark HTTP Request|
The HTTP request headers will be parsed as Bad Commands, while the body of the request will be correctly parsed because a001 LIST is a valid pre-authentication command. After that command we're actually sending shellcode, in this case the stager of the new BeEF Bind shellcode, together with an egg-hunter and current/next SEH pointers because the IMAP server (Eudora Mail 3 v220.127.116.11) is vulnerable to SEH based overflow. When the server will parse the LIST command, the shellcode will be loaded into process's memory binding a socket on port 4444. This is not yet a bind shell.
The next step is sending the stage to this port, as another POST request.
While the stage is running in memory, we have port 4444 listening again, waiting for POST requests like:
|Wireshark with stager|
Note the Access-Control-Allow-Origin, which enables cross-domain communication using CORS.
The only cross-domain requests where we can't read the response is when we send the stager and the stage of the shellcode. This would have been very helpful, because we could have fingerprinted the service properly.
From a low-level point of view, you can see how the request looks like in the IMAP process memory:
|Sending the POST Request|
|NOP NOP NOP|
You can clearly see that the HTTP request headers are in memory, as garbage/NOPs are sent in a normal exploit where we need to fill lets say 800 bytes of memory before reaching the pointers we can overwrite. This adds additional complexity to the exploitation. We cannot know in advance (and we cannot query the XmlHttpRequest object to know it) the exact size of the the HTTP request headers. An error of one byte means the exploit will fail. To calculate the size we send a POST request back to BeEF, on a different socket (to maintain the cross-domain behavior). In this way we can know exactly the size of the headers which will be sent to the target, and we just need to adjust the size considering the Host field which will be clearly different.
Some of you may have been wondering. Wait a sec, how come you can send cross-domain POST requests to port 143? True, there is no magic here.
A pre-requisite is to disable PortBanning for selected ports, and we do that by delivering a malicious Firefox extension. As you know, Firefox extensions have no limitations on which configuration objects to override. So, basically, everything accessible from about:config can be overwritten or modified.
So it's enough to send a malicious (or backdoored) Firefox extension which contains in prefs.js the following line:
to disable PortBanning for those selected ports.
Our research has been focused, and currently works perfectly, on latest Firefox. It works also in WebKit (Chrome/Safari) based browsers if you target not-banned ports. I still need to find a way to disable PortBanning on WebKit based browsers. Opera is still not tested, and Internet Explorer too. For IE there is an additional limitation: it looks like cross-domain POST requests cannot be sent.
The impact of this research is "Rooting your internals" (i.e. internal network services) from a browser which sits in your internal network, using only the browser as a pivot for internal network attacks. The communication with the shellcode is entirely in-browser via BeEF, there are no additional reverse sockets open. From a forensics point of view, this should be much more difficult to understand what's happening, or what happened. The attack is much more stealthy.
Slides from our RuxCon talk here:
I've also uploaded the screencast of the demo we shown at RuxCon on my Vimeo channel:
The demo covers a phishing scenario using the BeEF Social Engineering extension, and shows all the steps required to use the BeEF Bind shellcode: from the malicious Firefox extension delivery, to internal live systems identification and port scanning, finishing with exploitation using IPEC.
Expect more goodness on this topic in the near future.
If you want to help debugging/analyzing known/new exploits and see if they can be ported to this technique, let us know. Your help will be greatly appreciated.