This post carries on from our previous post on detecting Hacking Team's 'Galileo Remote Control System' using a memory image of a compromised host. Today we'll be creating a set of network signatures for the popular open source Intrusion Detection System (IDS) Snort, and using these to determine if there are any Galileo RCS agents in our network.

Snort (https://www.snort.org/) is a free open-source IDS, designed to be deployed in networks of all shapes and sizes, from small home networks all the way up to large enterprises. An Intrusion Detection System (IDS) analyses network traffic to identify suspicious or malicious traffic. This allows security operations staff to investigate suspected malware infections, as well as employee misbehaviour, and often provides the trigger that starts a 'hunt' for malware within a network. Snort works by listening to all of the network traffic on its 'monitor' port, and checking to see if it triggers any of the rules that it has in its database.

These rules consist of a set of conditions; if the packet matches these conditions then an alert is raised. An example rule is shown below:

alert icmp 192.168.1.4 any -> 192.168.1.1 any (msg: "HEARTBEAT";)

This rule listens for ICMP (Ping) traffic coming from host 192.168.1.4 and going to host 192.168.1.1 (on any port). If it detects this traffic then it triggers an alert with the message "HEARTBEAT".

If we want to identify the presence of Galileo RCS agents then, we need to write a rule that uniquely matches the traffic produced by that agent. If we make our rule too broad, then it will trigger 'false positives' and flag up legitimate traffic as malicious. Conversely, if we make our rule too specific then it can be evaded by sneaky malware authors. Striking this balance is hard, and often requires multiple revisions of a rule.

In order to start testing, I previously captured a sample of network traffic from both a 'scout' and an 'elite' implant using Wireshark (a packet capture tool - https://www.wireshark.org/). This allows me to look at the bytes sent to find unique aspects to write a rule. As we're also going to be going through lots of revisions of the rule, I can then re-play this capture into a lab network using the 'tcpreplay' tool to verify that my rule works.

For testing purposes, I've set up a virtual network containing a Kali Linux 'replay' machine, and a Security Onion IDS platform with Snort installed. Security Onion (http://blog.securityonion.net/p/securityonion.html) is a very full-featured Linux distribution containing a number of intrusion detection and forensics tools, as well as some useful graphical front-ends to them.

Snorby - Graphical front end to SNORT installed on Security Onion

If you've read my previous work building a custom controller for the 'scout' agent (Here). You'll know that this agent communicates through HTTP POST requests to the Command and Control (C2) server. One of these is shown below:

POST /index.php HTTP/1.1 Accept: */* Cookie: ID=f2561df6-1231-4927-88a7-809b557f54fe User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0) Host: 178.62.50.243 Connection: Keep-Alive Content-Length: 112 h.2..]....|......x.H.c......9.Z...p...rF8...CHY z...*S..S.1.....;.v6...1."&SOI.\.%N).......8kFec.[.|.|..E.t.9S..

A few things immediately jump out here: Firstly, the fact that a client is performing a POST request to the /index.php page is not particularly suspicious, but the fact that the data being sent is binary data (and not plain ascii text) is.

Interestingly, the initial authentication request is sent as Base-64 encoded binary, but this is dropped after the agent is authenticated. This is probably an over-sight on the part of Hacking Team, as it makes their network traffic immediately more noticeable. We can add this to the list of mistakes made by Hacking Team writing their agents.

If we replay the packet capture with no custom rules, Snort detects the agent as a 'Generic Trojan'.

Scout agent detected by Emerging Threats rule

This rule was written by a company called 'Emerging Threats' who write rules to catch large varieties of malware. The exact rule that triggered is below (and is a bit more complicated than our example):

alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"ET TROJAN Generic - POST To .php w/Extended ASCII Characters"; flow:established,to_server; content:"POST"; http_method; content:".php"; http_uri; content:!"Referer|3a|"; http_header; content:!"Content-Type|3a|"; http_header; content:" MSIE "; http_header; pcre:"/^.{0,3}[\x80-\xff]{1,3}[\x00-\x7f]{1,3}[\x80-\xff]{1,3}[\x80-\xff]{1,3}/P"; classtype:trojan-activity; sid:2016858; rev:7;)

As we can see here, this triggers on both the POST to index.php, as well as the presence of binary data ('pcre' runs a regular expression against the data).

In addition to the binary POST, we also have a fairly unique Cookie string. We can therefore write a regex (regular expression) to identify this cookie, and therefore tie the 'Generic Trojan' down to a specific malware family. Writing regexes is beyond the scope of this post, but if you want to learn more, this article covers detecting credit card data using regexes and Snort.

Our unique cookie format looks as follows:

ID=f2561df6-1231-4927-88a7-809b557f54fe

We can therefore write the following regex to detect this id:

pcre:"/ID=\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/C";

This first matches the "ID=" string, before matching 8 alphanumeric ('\w') characters, then three sequences of 4 followed by a sequence of 12 (all separated by dashes). The 'C' at the end tells Snort to try and match this regex in the cookie data.

Our completed rule then looks as follows:

alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"Hacking Team 'Scout' Windows Implant Exfiltration"; flow:established,to_server; content:"POST"; http_method; content:"index.php"; http_uri; pcre:"/ID=\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/C"; pcre:"/^.{0,3}[\x80-\xff]{1,3}[\x00-\x7f]{1,3}[\x80-\xff]{1,3}[\x80-\xff]{1,3}/P"; classtype:trojan-activity; reference:url,www.4armed.com/blog/network-defense-catching-galileo-rcs-using-snort; sid:1337002; rev:6;)

And when we play our capture back, Snort triggers an alert:

Scout implant detected by our rule

Of course the 'scout' level agent has no special hiding abilities on the host either, and is designed as a 'throwaway' implant to determine if the target is interesting. Once the target is 'interesting', the more advanced 'elite' agent is deployed. As mentioned previously, this spyware has a number of advanced hiding techniques. So what does its network traffic look like?

POST /index.jsp HTTP/1.1 Accept: */* Cookie: ID=1f3554f9-0902-4163-a3a0-986551541a8c User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Host: 178.62.50.243 Connection: Keep-Alive Content-Length: 122 r...h..e+oon.k^...r...?Z.....L.'...2`.(?N.f....".s.......^....+.b...@.5....,.c..?0......{....DX.0.>....q*-..P.....n.y`(...

You would be forgiven for thinking that i'd just accidentally pasted the wrong packet capture in, but the 'elite' implant doesn't actually bother to hide its C2 traffic at all. The one change is that the POST request is to 'index.jsp' rather than 'index.php'...

However, this demonstrates an interesting point that I mentioned earlier about being over-specific with rules. The Emerging Threats rule that detected the 'scout' agent does not trigger for the 'elite'. Why? Because it only triggers on POST requests to '.php' pages

content:"POST"; http_method; content:".php";

So the 'elite' implant is magically invisible to Snort. We'll fix that now though by creating a new rule. This rule does exactly the same as the previous rule, except it uses the '.jsp' as an indicator to determine the level of the implant installed.

alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"Hacking Team 'Elite' Windows Implant Exfiltration"; flow:established,to_server; content:"POST"; http_method; content:"index.jsp"; http_uri; pcre:"/ID=\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/C"; pcre:"/^.{0,3}[\x80-\xff]{1,3}[\x00-\x7f]{1,3}[\x80-\xff]{1,3}[\x80-\xff]{1,3}/P"; classtype:trojan-activity; reference:url,www.4armed.com/blog/network-defense-catching-galileo-rcs-using-snort; sid:1337001; rev:5;)

And once installed, we can now reliably detect the 'elite' agent using Snort.

Elite implant detected by Snort

In addition to this, neither implant compresses any of the data that they exfiltrate, leading to a large amount of network traffic. As each of these exfiltration requests triggers our alert it becomes very obvious when a machine on a network is infected with the Galileo RCS.

Large spike in alerts from infected machine

As a closing note, some people will be thinking 'why not use the user-agent as an indicator?'. The User-Agent string in each request is identical to a level of the Galileo RCS (i.e. the scout and elite agents are different from each other, but the same across all scouts). Therefore we could write a rule that uses the User-Agent to identify the system. However, changing the user-agent to defeat this rule is trivial for someone looking to re-use the Galileo RCS as the string is contained in the clear the binary (and not dynamically generated). This contrasts with the cookie string, which is dynamically generated by the server and whose pattern is much more complex to change.

User agent defined in the scout implant

To conclude, we've identified a number of unique patterns in the network traffic of both the 'scout' and 'elite' implants on Windows. These have allowed us to write a pair of rules for the Snort IDS, allowing anyone to detect the Galileo RCS on their networks. If you are concerned about the impact of the Galileo RCS (or other spyware) on your home or business, please get in touch with us to discuss your requirements and find out how we can assist.