SpiderLabs Blog

NetSupport Information Leakage Using Nmap Script

Written by David Kirkpatrick | Apr 23, 2014 11:44:00 AM

NetSupport allows corporations to remotely manage and connect to PC's and servers from a central location for the purposes of desktop support.

In my last post I discussed how I wrote a script using the NetSupport scripting language to find versions of NetSupport running on clients with default installations that didn't require authentication to remotely connect to them. Essentially you could use NetSupport to bypass
any Domain or local credentials to remotely connect to the PC and compromise it, but you needed access to NetSupport Manager software to run it.

Since then, I've written a basic Nmap script that performs a similar task by checking whether a NetSupport Manager implementation requires authentication. If authentication is not requireed, it returns useful NetSupport configuration settings from the hosts. This negates the requirement to use the NetSupport software to find hosts configured with this weakness.

With no information on the NetSupport packet format in my test network, I fired up Wireshark and captured all the relevant data sent from the NetSupport Manager when I performed an Inventory query from the Action menu on the manager to another host, as shown below:

As you can see, it provides quite a lot of information on the client NetSupport configuration. Wireshark allows you to follow the TCP stream of the NetSupport service on TCP port 5405 and view the response. It also has a handy feature to show this data as raw Hex by clicking on C Arrays, which essentially gives you the raw Hex code required to send to a socket. I captured this raw data, then replayed the request by sending it to TCP port 5405 on the client using an Nmap script to see what output I would get.

Each host I used to test returned a response which contained the word "License" (see the word "License" in the above response) in the packet response after a successful connection. So, I decided to use that as my true/false test in my Nmap script to see if the client required authentication or not. If "License" was returned then the information was freely retrieved without authentication. If it wasn't, that meant that most likely authentication was required to get the results of the query.

I was amused that I did end up getting the information I was after. Even better, the "Connect" popup that usually appears on the remote PC, when running the previous NetSupport Manager script, did not pop up (for want of a better word !) when using the Nmap script after a successful connection. The following shows a typical response from my Nmap script from a PC running NetSupport client with a default installation:

This meant I could run this script across the network and the clients would be unaware of my testing of their configuration.

While writing the script I needed to decide how much of the raw response to include in the Nmap output. Should it just include a basic message e.g. "No authentication required"? Should it return only the version information and a message? Should it send the ASCII output? From the testing I performed on other NetSupport versions, the responses seemed to change slightly. For example, in version 12.0, the response included this information in the _version=1200 parameter response. However for earlier versions there was no _version parameter returned.

In the end I decided to just return a chunk of the raw data and clean it up a bit removing \x00 and other hex data. So, what I ended up with is a custom Nmap script that does the following:

  • Sends a NetSupport Inventory query in raw packets
  • Checks if the response includes the word "License"
    • If so, it has successfully connected to the client without the need for authentication
    • If not, then most probably it requires authentication
  • Displays the response including user information such as hostname, user, version info, password of the "Configurator Password," etc.

The screenshot below shows that the encrypted Configurator Password of the client is also returned:

This flaw draws attention to software that is installed without the need for passwords to be configured. In this case installing the default NetSupport client settings on a PC, where no Client password is set, can allow information to be freely returned, which can assist an attacker. But more worryingly, an attacker could remotely connect to the host without the need for a password, bypassing Windows local or domain passwords.

We informed NetSupport of this information leakage vulnerability, and they have responded claiming to have fixed the issue in later revisions.

The simple remediation is to ensure that a Client Password is configured in ALL clients using the software to mitigate the risk. This can be done by clicking on the NetSupport Client Security settings and configuring a password as shown below:

Of course to properly secure the installation and configuration, it's best to follow NetSupports own guidelines.

In the customer network I was testing that was using NetSupport there were quite a few PCs not configured with a NetSupport password. This essentially was a quick win for me, allowing me to easily bypass any Domain or Windows credentials and use NetSupport to remotely connect to the hosts and compromise them.

The lesson here is that greater care should be taken when installing such powerful software that can bypass all your domain security so easily. Of course, software providers can help by securing their default installation configurations as well.

Anyway, here's my Nmap script you may find useful to help you find weakly configured NetSupport hosts:

 

 

local nmap = require "nmap"local shortport = require "shortport"description = [[Determines if NetSupport authentication is open or not and then gets Inventory query from host.]]author = "David Kirkpatrick"categories = {"auth"}portrule = shortport.port_or_service(5405, "netsupport")action = function(host, port)        local socket = nmap.new_socket()	local result        local status = true	local response        local strPayload = string.char (0x14, 0x00, 0x5a, 0x00, 0x44, 0x41, 0x56, 0x45,0x2d, 0x50, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x00, 0x51, 0x00, 0x81, 0x00, 0x44, 0x41, 0x56, 0x45, 0x2d, 0x50, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x3f, 0x4e, 0x41, 0x44,0x3e, 0x41, 0x48, 0x41, 0x40, 0x4e, 0x40, 0x48,0x43, 0x4f, 0x48, 0x45, 0x00, 0x38, 0x00, 0x03,0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd,0xb5, 0xa5, 0xff, 0x00, 0x00, 0x64, 0x61, 0x76,0x65, 0x00, 0x57, 0x4f, 0x52, 0x4b, 0x47, 0x52,0x4f, 0x55, 0x50, 0x00, 0x3c, 0x3e, 0x00, 0x44,0x41, 0x56, 0x45, 0x2d, 0x50, 0x43, 0x00, 0x31,0x32, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x30,0x30, 0x30, 0x00, 0x31, 0x30, 0x00, 0x00)                socket:connect(host.ip, port.number, port.protocol)        socket:send (strPayload)        status, result = socket:receive_bytes(1200)	local noauth = string.match(result, "License")        local cleanup1 = string.gsub(result, "\x00",",")        if (noauth) then		response = "!! No Authentication required !!\nHost Response = " ..cleanup1                return response         else                return "Not vulnerable - probably requires authentication."	end        	socket:close()end