Having recently moved into the IR team – where I now have to actually do stuff as opposed to just talking about stuff in technical sales – I have found that the best way to get up to speed with detecting attacker behaviours is to run the tools they are likely to use in my lab so I can get familiar with how they work. Reading blogs like this and the others in Lee Kirkpatrick's excellent Profiling Attackers Series is great, but I find I learn much faster by doing things and interacting with systems myself.
In this blog series, Lee Kirkpatrick has already covered some examples of how to get the payload delivered and installed on the target, so we’re going to dive straight in to how our Hunting Methodology can be used to detect the activity. We are going to hunt for activity using data generated by both NetWitness Network and NetWitness Endpoint.
For the purpose of this exercise, we have used the default http settings for the Listener profile in Covenant, and only changed the default beacon setting from 5 seconds to 120 seconds to represent a more realistic use of the tool. The settings can be easily changed (such as the user-agent, directory and files used for the callback etc) but quite often the defaults are used by attackers too! We have also used the Power Shell method for creating our Launcher.
NetWitness Network Analysis
Covenant uses an HTTP connection for its communication (which can optionally be configured to run over SSL with user provided certs). By using our regular methodology of starting with Outbound HTTP traffic (direction = ‘outbound’ && service = 80), we can review the Analysis meta keys for any interesting indicators:
Reviewing the Service Analysis keys (analysis.service) we can see some interesting values:
By drilling into these 6 values we reduce our dataset from over 4,000 sessions to 69 sessions – this means that these 69 sessions all share the same “interesting” characteristics that suggest that they are not normal user initiated web browsing.
With 69 sessions we can use Event Analysis to view those sessions in more detail, which reveals the bulk of traffic belongs to the same Source & Destination IP address pair:
This appears to be our Covenant C2 communications. Opening the session reconstruction, we can see more details. Some things that we can observe that could be used to enhance detection of this traffic would be the strange looking User-Agent string:
The User-Agent string is strange as appears to be old. It resolves to Chrome version 41 on Windows 7 – the victim in this case is a Windows 10 system, and the version of Chrome installed on the host is version 79. If you attempt to connect to the Listener with a different User-Agent it returns a 500 Error:
Don't poke the Bear (or Panda, Kitten, Tiger etc) - if you find these indicators in your environment, don't try to establish a connection back to the attacker's system as you will give them a tip-off that you are investigating them.
Also, the HTTP Request Header “cookies” appears in all sessions:
The HTTP Request Header “cookie” also appears in all sessions after the initial callback … so sessions with both “cookies” and “cookie” request headers appear unique to this traffic:
The following query (which could be used as an App rule) identifies the Covenant traffic in our dataset:
client = 'mozilla/5.0 (windows nt 6.1) applewebkit/537.36 (khtml, like gecko) chrome/41.0.2228.0 safari/537.36' && http.request = 'cookies' && http.request = 'cookie'
When hunting with NetWitness Endpoint, I always start with my *Compromise keys – Behaviours of Compromise, Indicators of Compromise, and Enablers of Compromise, as well as reviewing the Category of endpoint events.
Here we can see 4 meta values related to running PowerShell – which we know is the method used for creating our Covenant Launcher.
Upon viewing these events in Event Analysis we can see the encoded PowerShell script being launched
Analysis shows that we have a very large encoded parameter being passed. It’s too large for us to decode and manage in the NetWitness GUI, so we can paste the command into CyberChef and decode it from there.
We can further decode the string to reveal the command:
The output here appears to be compressed, so we can add an Inflate operation to our recipe to reveal the contents:
Looks like we have some executable code. A quick search for recognisable strings yields a URL which matches our network traffic for the callback to the Covenant server, as well as a template for the html page that should match what is served by the Covenant Listener
Also the block of text can be Base64 decoded to reveal the Request Headers to be sent by the Grunt when communicating with the Listener:
This also matches what we observed in our network analysis for a Grunt check-in:
And the command being sent to the Grunt via the response from the Listener:
Decoding the &data= section of the above Post shows the encrypted data being returned to the Listener - known as the GruntEncryptedMessage: