Friday, March 15, 2019

One-Way Shellcode for firewall evasion using Out Of Band data

In a recent post I was talking about a shellcode technique to bypass firewalls based on the socket's lifetime which could be useful for very specific exploits. Continuing with this type of shellcodes (reuse socket/connection) I would like to share another technique that I have used with certain remote exploits for Windows; especially in scenarios in which I know in advance that the outgoing traffic is blocked by a firewall and where a reverse shell is not possible.

I have to say that the idea is not new, at least for Linux systems. In fact, it was as a result of finding this old thread some years ago, in which the author bkbll (one of the collaborators of HTRAN by the way) uses a cute trick to reuse connections, the reason for making my own implementation for Windows. Remember, as I mentioned in my last post, that this kind of shellcodes are very particular and only valid for certain types of exploits,  something that requires some effort at times. Possibly the difficulty and the time required to adapt them to each target (whenever posible) is the main reason why attackers and pentesters tend to use "universal" payloads instead. 

OOB Data

Despite being little known, TCP allows you to send "out of band" data in the same channel as a way to indicate that some information in the TCP stream should be processed as soon as possible by the recipient peer. This is typically used for some services to send notice of an exceptional condition; for instance, the cancellation of a data transfer. 

A simple way to send OOB data is through the MSG_OOB flag from the send function. When this is done, the TCP-stack build a packet with the URG flag and fill the Urgent Pointer with the offset where the OOB data starts.

To be aware of this data, the recipient must call recv with the MSG_OOB flag, otherwise will just read the "normal" data from that stream (as long as the socket is not set with the SO_OOBINLINE option). To understand more deeply how this mechanism works, refer to this link.

The important thing for us is that, under normal conditions, an application that is not configured to manage OOB data will keep working as usual with the TCP stream even when we send OOB data. Only when the corresponding API is called this kind of data could be fetched. So, how can we take advantage of this? Easy. When it comes to crafting the exploit we only have to make sure to send OOB data (just one byte is needed) in some packet/packets just before the shellcode starts to run. To find the handle the stager would only need to bruteforce the list of posible sockets looking for the one with OOB pending to be read. An C implementation of this could looks like:

As usual, to build the stager with this logic I've used a reverse TCP shellcode from Metasploit as a template. The block in charge of making the reverse connection has been replaced with this code:

The asm code in the red box will be responsible for going through all socket descriptors until the one with the OOB byte is found. Note that, as with the shellcode based on socket's lifetime, this stager will also be NAT inmmune.

P0C: FTP Exploit

Let's see a proof of concept of how to convert a remote exploit for Windows using this technique. I have chosen the following exploit which leverage a vulnerability in the Konica Minolta FTP server. If we run said exploit using the existing payload (windows/shell_reverse_tcp) we would get two connections: the one generated to trigger the vulnerability; and the one created by the stager to connect back to our port 4444.

A firewall that protects any outgoing connection would block the reverse shell, foiling the attack. Let's see how we can build our "one-way shellcode".

First, let's change a little bit the data sent to the service to see how it behaves. We will simply add a new byte (an "A") at the end of the string "USER Anonymous" and then send it as OOB (through the MSG_OOB flag).

To get a general idea about how the FTP service manages the communications I will use Frida.  I love this tool and in cases like this can save you a lot of debugging time. I will execute frida-trace with the following script to get all the parameters and values returned by the recv API (I have previously used frida-trace too to identify which network API are used to send/receive data: send, sendto, recv, recvfrom, WSASend, WSARecv, etc.)

After launching the exploit we observe the following result. The most relevant data is marked in red. Notice that the recv function getting the string "User anonymous" returns 10 bytes (not 11); that is, it does not consider the extra byte sent "out of band". From this information we can infer that the socket handle has not been set with SO_OOBINLINE (in which case all of the OOB data would be read along with the normal data stream).

So we only need to know the size of the buffer used to collect the vulnerable command (CWD) and adjust the offsets of our exploit.  When the stager finds the socket handle, the code shown below will be executed. Note that instead of sending the payload size, I invoke VirtualAlloc directly to reserve a sufficiently large buffer (4 MB). The reason to stop receiving data when eax is FFFFFFF is because in this case the socket is non-blocking and when it has no more data to fetch from the buffer it will return WSAEWOULDBLOCK. This is not very stable and more logic can be added (like GetLastError API call) but as a proof of concept it is ok.

Here the code to assemble the shellcode and obfuscate it with msfvenom.

As a payload I have used a simple binary compiled with Visual Studio that just shows a MsgBox. To convert the .exe to the "mapped" version (so that it can be loaded in a reflective way) I have used Amber.

The final exploit is shown below.

One thing to highlight here. For this particular exploit I have sent the OOB byte embeded not along with the evil buffer but before (and just one time). The correct way to do it is by sending that OOB byte as close as possible with the data that triggers the vulnerability. This paragraph would clarify the reasons why I say this:

"If the socket option SO_OOBINLINE is not set, and the sending program sent OOB data with a size greater than one byte, all the bytes but the last are considered normal data. (Normal data means that the receiving program can receive data without specifying the MSG_OOB flag.) The last byte of the OOB data that was sent is not stored in the normal data stream. This byte can only be retrieved by issuing a recv(), recvmsg(), or recvfrom() API with the MSG_OOB flag set. If a receive operation is issued with the MSG_OOB flag not set, and normal data is received, the OOB byte is deleted. Also, if multiple occurrences of OOB data are sent, the OOB data from the preceding occurrence is lost, and the position of the OOB data of the final OOB data occurrence is remembered."

After exploiting the service this is the new result from Wireshark; just one session :)

Note that this exploit is very easy to craft. However, as I mentioned earlier it can be quite painful or simply impossible to carry it out with some exploits. Sometimes the exploited process itself does not even have the socket handle or if it does have, a watchdog or other thread can do things with it and disrupt your payload.

I leave the shellcode and the p0c in my Github.

No comments:

Post a Comment