Blog: How Tos

How to reverse engineer a protocol

David Lodge 24 Sep 2013

On a recent test I had the following finding come up from Nessus:

NetSupport Manager Gateway HTTP Protocol Information Disclosure.

The description gives one test case to allow manual verification, but gives no really useful information of what information can be gathered or even what the NetSupport Manager Gateway actually is.

I could just report it as is, manually confirming its existence using the single test case built into Nessus, but where’s the fun in that? What I could do with it to build a path to turn this into a potential proper exploit.

So, we start with finding out what NetSupport Manager Gateway actually is; a piece of software that allows remote administration and access to hosts from a centralised manager. The Gateway aspect is a single interface to ease paths through firewalls. In other words, the key to me getting inside your network!

We need to explore the protocol and see what we can dig up. Searching the Internet and the provider’s knowledge base was of little use; we can see the product’s manuals, which tells us the need for a security key and that’s about it.

As it’s undocumented the easiest way to explore this is to download an evaluation version of the product, stick it on a virtual machine and use Wireshark to sniff the traffic and see what we can reverse engineer.

The first run is to use the installed client to connect to the server, which starts off well, but then becomes less useful:

POST http://xxx.xxx.xxx.xxx/fakeurl.htm HTTP/1.1
User-Agent: NetSupport Manager/1.3
Content-Type: application/x-www-form-urlencoded
Content-Length:    22
Host: xxx.xxx.xxx.xxx
Connection: Keep-Alive

CMD=POLL
INFO=1
ACK=1

HTTP/1.1 200 OK Server: NetSupport Gateway/1.3 (Windows NT) Content-Type: application/x-www-form-urlencoded Content-Length: 61 Connection: Keep-Alive CMD=ENCD ES=1 DATA=.g+$.{.. \….W…&.=@Q.{.w}..o..X..xf…

 

From the looks of it, this is setting up some encrypted channel, as every following packet use the ENCD CMD. This isn’t promising. If it is encrypted traffic then the key ought to play some part. As I don’t know the key of the target it is easier to set up my own gateway with a known key, then I can compare encoding values if the key is changed.

A quick configuration later and I have a gateway with a key set to ABCDEFGH. Trying to run this on one VM doesn’t appear to work (as it tries to route locally), so we use the proxy option to send it through a burp instance.

Interestingly enough, although this doesn’t work, what Wireshark shows me is a totally different, unencrypted handshake with what appears to be a hash embedded in it (stripping out the HTTP headers):

CMD=CTL_BROWSE
MATCH_NAME=
REQHOSTNAME=1
GSK=R4PnhLT6L7qeTWUC28ZPjwAA
CONTEXT=local
CTLTYPE=8
APPTYPE=0

Testing with adjusting the hash gives us differing responses depending on whether the hash is valid:

CMD=BROWSE_REPLY
CONTEXT=local
MORE=0

Or invalid:

CMD=BROWSE_REPLY
CONTEXT=local
FAILED_REASON=1

As we have a case for a valid key and an invalid key, we have the basic test steps for a brute force attack, basically loop through a dictionary or programmatically derived keys until we get a reply with MORE=0.

The only thing we need to do first is to work out how the hash is derived. As the hash is composed of alphanumeric characters it looks to be base64 encoded, passing this through a decoder gives us the binary numbers:

47 83 e7 84 b4 fa 2f ba 9e 4d 65 02 db c6 4f 8f 00 00

This is 16 bytes plus 2 null bytes at the end. 16 bytes is the right size for an md5 hash, and we can test this by working out the hash of our key:

[xxxx@xxxxxxxx xxxxxxx]$ perl -e 'use Digest::MD5; 
print Digest::MD5::md5_hex("ABCDEFGH") . "\n";'
4783e784b4fa2fba9e4d6502dbc64f8f

Those bytes look remarkably familiar! So the hash is just a modified base64 variant of the md5 hash of the key. The means we can write a simple brute forcer and potentially compromise the server.

Out of curiosity I wrote a simple perl based script and left it running for a few hours just to get an idea of speed, when I cancelled it (so I could shut down my laptop) it was on:

Attempt 7705000: AAAQWJYD, elapsed time(s): 14792

That works out to be 520 guesses a second, talking from one virtual machine to another, running on the same host which should have little network latency. This is unfeasible for a real attack: the key size can be from 8 to 15 characters and although it is case insensitive it allows numeric and special characters. Even assuming that only alphanumeric passwords are going to be used and the key is the minimum size of 8 characters that give us a possibility of:

368 = 2821109907456

…which would take about 172 years to perform an exhaustive key search, assuming that we can get full speed and that the service doesn’t crash under the load.

What can we take out from this? Although it is possible to attempt a brute force attack into the service and this would have a great pay off if it succeeded, it is unfeasible for me to perform the attack unless the key is a simple dictionary phrase. Note that I’m a security consultant with a finite amount of time to spend on attacking a host and usually within a specified timescale.

An attacker does not have these restrictions, and with an hour of reverse engineering and some tinkering they could be quite happily brute forcing your services, but you’d be able to see that can from your log files which you, of course, regularly check.

The mitigation steps are simple:

  • Restrict remote control software to specified source IP addresses.
  • Ensure that keys put in place on services have a large level of entropy and cover the full possible range that is allowed (AAAAAAAA is bad, A71&*%HJQWWBNA1 is good).
  • Check your web server logs for abnormal requests.
  • Don’t believe just because the software in use is not fully documented that somebody cannot work it out.