Security practitioners may know about common command-and-control (C2) frameworks, such as Cobalt Strike and Sliver, but fewer have likely heard of the so-called Chinese sibling framework “Manjusaka” (described by Talos in an excellent writeup). Like other C2 frameworks, we studied the Manjusaka implant/server network communications in our lab environment, and here we document some of the detection methods available. We have also open-sourced the content we describe.
Deploying several detection strategies means that if and when an adversary changes one or more attributes of the C2 communication protocol, defenders have multiple opportunities to still detect its use. This is where the art of detection engineering comes into play. As network defenders we broadly look for:
These three key aspects often lie in tension, and depend not only on alert logic, but also the nature and volume of the traffic being inspected. In this context, the adage “there is no silver bullet” is apt, and so the strategies we employ to detect Manjusaka span several approaches, some of which are described in this blog:
The Manjusaka C2 framework sends a heartbeat every second to the C2 server. This can be thought of as a “ping” - a request from the implant to the C2 server for instructions to carry out. Let’s look at the Wireshark display of one such heartbeat stream. Below we show implant communication in red, and the response from the C2 server in blue. As there are several interesting and unique elements we can focus on, see if you can identify a few before reading on, and then we’ll continue by outlining a few detection strategies.
Given that this GET occurs every second (with no jitter), we could simply look for a GET to /global/favicon.png
occur every second. Here is what this looks like in a SIEM on a timeline:
Timing elements (“beacons”) provide a valid detection strategy, however they are an aspect that is easy for an attacker to vary, so we look for alternative detection strategies.As illustrated in the following Wireshark screenshot, the heartbeat consists of a GET request with binary content being sent to the server.
It is fairly rare that content is sent to the server as part of a GET request*. However, such activity is certainly not necessarily nefarious (e.g., ElasticSearch does this by design), so we need additional attributes to craft our detection logic.
Note that the Content-Length
from the client is always “2” for the heartbeat and from the server is always “5”. Zeek provides both of these by default in http.log fields request_body_len
and response_body_len
, respectively. So we can simply look for a combination of a request_body_len
of 2 and a response_body_len
of 5 together with the GET method, and also a user agent matching a browser, which further reduces the chances of false positives.
Humio search
#path="*http*" method=GET user_agent="Mozilla/*" request_body_len=2 status_code=200 response_body_len=5
Splunk search
sourcetype="*http*" method=GET user_agent="Mozilla/*" request_body_len=2 status_code=200 response_body_len=5
As a variation, we can also look for when a GET request sends any content to a png
, as this is very rare in practice.
Humio search
#path="*http*" method=GET request_body_len>0 uri="/global/favicon.png"
Splunk search
sourcetype="*http*" method=GET request_body_len>0 uri="/global/favicon.png"
Surprisingly, this malware employs some quite unique user agents, so we can simply look for them in Zeek’s standard http.log. User agents can be easy for attackers to change - however when detections are this easy, it can be worth taking advantage of them anyway, as they offer some low-hanging fruit and remain effective until that evolution occurs.
Humio search
#path="*http*" method=GET
( user_agent="Mozilla/5.0 (Windows NT 8.0; WOW64; rv:58.0) Gecko/20120102 Firefox/58.0" OR user_agent="Mozilla/5.0 (Windows NT 8.0; WOW64; rv:40.0) Gecko")
Splunk search
sourcetype="*http*" method=GET
( user_agent="Mozilla/5.0 (Windows NT 8.0; WOW64; rv:58.0) Gecko/20120102 Firefox/58.0" OR user_agent="Mozilla/5.0 (Windows NT 8.0; WOW64; rv:40.0) Gecko")
A Manjusaka heartbeat consists of a GET request for a .png file, followed by a response from the server with a Content-Type of image/png
. However there are two aspects of the content served that make this “impossible”.
1A 1A 6E 04 29
, which is quite different from the expected byte sequence of a PNG file ( 89 50 4E 47 0D 0A 1A 0A
). If the correct file signature for a PNG did appear, Zeek would populate the resp_mime_types
field in http.log with image/png
to indicate it saw a PNG file. However if an unknown byte sequence appears instead - as in our case - Zeek won’t populate the resp_mime_types
field. Here’s a SIEM search based on this logic:#path="*http*" request_body_len>0 response_body_len>0 uri=*.png NOT resp_mime_types
Splunk search
sourcetype="*http*" request_body_len>0 response_body_len>0 uri=*.png NOT resp_mime_type
Even if a PNG has zero actual content (zero-by-zero image), its overall size can’t be less than eight bytes, corresponding to the number of file signature bytes required for PNGs. Since the content size of the server response is only “5’, it cannot possibly be a PNG file! In this case, a SIEM search might look like this:
Humio search
#path="*http*" request_body_len>0 response_body_len>0 uri=*.png response_body_len<8
Splunk search
sourcetype="*http*" request_body_len>0 response_body_len>0 uri=*.png response_body_len<8
Using Suricata we can employ the same tactics outlined above except we can now also inspect the actual content of the “2” and “5” byte responses. This additional visibility allows us to detect exfiltration, where the client sends more the heartbeat size of “2” to the C2 server (method 3 below). Our open-sourced Suricata rules work in spirit as follows.
In this blog we demonstrate an example of how employing a variety of detection strategies can improve a defender’s visibility of access to current C2 infrastructures. We also show how using a mixture of highly particular detection attributes (e.g., unique user agents) alongside more generic detections (e.g., detecting “impossible” PNGs) can provide robustness to attackers changing a single aspect to thwart one detection strategy. We can maintain visibility by leveraging a breadth of detection strategies.
By Corelight Labs Team
*RFC7231 section 4.3.1: "A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request."