Cobalt Strike Analysis and Tutorial: How Malleable C2 Profiles Make Cobalt Strike Difficult to Detect

A conceptual image representing malware, including the adversarial use of Cobalt Strike and its Malleable C2 profile discussed here.

This post is also available in: 日本語 (Japanese)

Executive Summary

Cobalt Strike is commercial threat emulation software that emulates a quiet, long-term embedded actor in a network. This actor, known as Beacon, communicates with an external team server to emulate command and control (C2) traffic. Due to its versatility, Cobalt Strike is commonly used as a legitimate tool by red teams – but is also widely used by threat actors for real-world attacks.

Cobalt Strike users control Beacon’s HTTP indicators through a profile, and can select either the default profile or a customizable Malleable C2 profile.

In this blog post, we will go through the concepts and definitions associated with these profiles, and explore differences between default and customized Malleable C2 profiles used in the Cobalt Strike framework as well as in some true attacks in the wild. In doing so, we demonstrate how the Malleable C2 profile lends versatility to Cobalt Strike, and why this versatility makes Cobalt Strike an effective emulator for which it is difficult to design traditional firewall defenses.

Palo Alto Networks customers receive protections against malicious uses of Cobalt Strike through Cortex XDR and the WildFire and Threat Prevention subscriptions for the Next-Generation Firewall.

Related Unit 42 Topics Cobalt Strike, C2, Tutorials

Table of Contents

Profile Options for Cobalt Strike
Global Options
Local Options
Cobalt Strike Default Profile
Customized Cobalt Strike Profiles
Cases in the Wild
Default Profile Sample
Customized Profile Sample
Cobalt Strike Beacon Configuration
Conclusion
Indicators of Compromise
Additional Resources

Profile Options for Cobalt Strike

The Cobalt Strike tool’s primary configuration is specified using a profile file. The tool uses the values present in the profile to generate the Beacon payload, and users create the profile and set its values with a Malleable Command and Control (C2) profile language.

The profile specifies how the beacon will transform and store data in a transaction.

Within a profile, options are divided into global options and local options. Global options update the global Beacon settings, while local options are transaction-specific. Local option changes within one transaction do not affect the output from other transactions.

The profile is divided into multiple sections to specify the values for different parts of the C2 communications. An example of a generic structure of the profile is as follows:

Different parts of the profile are explained below.

Global Options

Global options are global to C2 communications. Options such as sleeptime and jitter define the frequency of Beacon’s check-in with the team server. Here is a list of a few global options with example values:

If you are interested in a more comprehensive list of all the global options, refer to this Cobalt Strike user guide.

Local Options

On the other hand, the scope for local options is per transaction only. The options for one transaction do not affect the other.

Examples of Local options:

In addition to these options, a profile can specify different protocol-transactions to carry out different actions. Below are example transactions, as well as brief explanations of their usage:

  • http-stager: The Beacon is a staged payload. The stager downloads the file and injects it into memory. The values listed in this transaction are customizing the HTTP communication for downloading the beacon.
  • dns-beacon: After Cobalt Strike v4.3, DNS options became part of the dns-beacon transaction. This transaction modifies the DNS C2 communication. If you are interested in a more comprehensive list of all the dns-beacon options, refer to this Cobalt Strike user guide.
  • http-get: The http-get transaction customizes the HTTP communication between the Beacon and the team server. The Beacon starts by sending the HTTP request with metadata about the compromised system. If the team server has tasks to execute, the server sends an HTTP response.
  • http-post: Once the Beacon executes the tasks sent by the server, the output of the task is transferred in the http-post transaction. The values listed in this transaction affect the HTTP communication when the task output is sent over to the server.
  • https-certificate: If the Beacon is tasked to communicate over HTTPS, The team server generates a self-signed certificate. The team server uses http-get and http-post transaction values to create actual HTTP requests and responses. This profile transaction can help to specify the different parameters for SSL certificates. If you are interested in a more comprehensive list of all the http-certificates options, refer to this Cobalt Strike user guide.
The Cobalt Strike default profile will be loaded if no other customized profiles are specified.
Figure 1. Cobalt Strike default profile.

Cobalt Strike Default Profile

The default profile will be loaded if no other customized profiles are specified. Figure 1, above, is the specification of the default profile, and Figure 2, below, is an example of traffic capture from the default profile using the web drive-by-download option in a Cobalt Strike team server.

This example of traffic capture from the default profile uses the web drive-by-download option in a Cobalt Strike team server.
Figure 2. An example traffic capture from the default profile.

From Figure 2, you can see that there are several HTTP transactions of GET and POST requests and responses.

  • For GET requests, most of the request URIs are very short and have predefined patterns. The URIs are randomly chosen from the list of URIs specified under set uri in the default profile in Figure 1 (see Table 1 below for the complete list). Malicious attackers can easily modify the URI to arbitrary strings if they use a customized profile with set uri options inside the http-get section. This also explains why a pattern-based signature might catch the Cobalt Strike traffic using default profiles very well, but fail to capture any variations with customized profiles.
  • For POST requests, there is a predefined pattern – /submit.php?id= – in the URI. The ID value is randomly generated. Similar to the possibilities for HTTP GET requests, malicious attackers can easily modify the URIs to arbitrary strings if they use customized profiles with set uri options inside the http-post section.
Index URIs Index URIs Index URIs
1 /ca 8 /fwlink 15 /push
2 /dpixel 9 /cm 16 /ptj
3 /__utm.gif 10 /cx 17 /j.ad
4 /pixel.gif 11 /pixel 18 /ga.js
5 /g.pixel 12 /match 19 /en_US/all.js
6 /dot.gif 13 /visit.js 20 /activity
7 /updates.rss 14 /load 21 /IE9CompatViewList.xml

Table 1. Possible URIs specified in the Cobalt Strike default profile.

Customized Cobalt Strike Profiles

Public Malleable C2 profiles are available and can be downloaded in public repositories, such as from the official profiles examples on GitHub. These profiles can be loaded by the team server and used as a Beacon download for C2 communications.

As an example, we walk through the etumbot profile to explain in more detail below.

1. Global Options.

  • Sleeptime: The sleep time for the beacon callback is 5,000 milliseconds (5s).
  • Jitter: The jitter to set % is 0. In this example, the Beacon will call back every 5s because of the jitter value 0.
  • Maxdns: The maximum length of hostname is 255 when uploading data over DNS.
  • UserAgent: Set the HTTP C2 request useragent as "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/5.0)"
Public Malleable C2 profiles are available - see this example, showing global options in an Etumbot profile.
Figure 3. Global options in Etumbot profile.

2. Beacon check-In to get task from teamserver with HTTP GET request.

Below the global options, we find the following option configurations about HTTP request and response. Figures 4 and 5, below, show this configuration, which include URI, header and metadata information for both the client and the server.

Red boxes highlight the HTTP Request URI, HTTP Request Header, Metadata Encoding Algorithm, Metadata Attached in URI, HTTP Response Header, Task Data Encrypted and Encoded as Response Body in a sample Malleable C2 profile.
Figure 4. HTTP GET request options in Etumbot profile.
Red boxes highlight the HTTP URI path, metadata encoded by Netbios, HTTP UA, and HTTP response header in a sample Malleable C2 profile.
Figure 5. HTTP GET request in live traffic.

3. Beacon task execution result submission to teamserver with HTTP POST request.

We can find the following option configuration about HTTP response from Figure 6 below, as well as what the POST C2 traffic looks like in Figure 7.

Red boxes highlight the HTTP request URI, HTTP request header, HTTP request sessionID attached in URI, HTTP request payload for command execution result, HTTP response header, and HTTP response body in a sample malleable C2 profile.
Figure 6. HTTP POST request options in Etumbot profile.
Red boxes highlight the HTTP URI path, session ID encoded by Netbios, HTTP URI path postfix, HTTP request header, HTTP request UA, task execution result encoded by Base64 and HTTP response header in a sample malleable C2 profile.
Figure 7. HTTP POST request options in live traffic.

Cases in the Wild

The following sections show two different cases of Cobalt Strike payloads used in the wild: one using the default option (no profiles) and the other with a custom profile. Both samples have no trigger on VirusTotal at the time of this writing, but Palo Alto Networks identified them using static and dynamic analysis.

Default Profile Sample

SHA256 Hash: 6a6e5d2faeded086c3a97e14994d663e2ff768cb3ad1f5a1aa2a2b5fd344dde2

Cobalt Strike HTTP GET Beacon download request with default profile
Figure 8. Cobalt Strike HTTP GET Beacon download request.
Cobalt Strike HTTP GET heartbeat request with default profile
Figure 9. Cobalt Strike HTTP GET heartbeat request.
Cobalt Strike HTTP POST call-back request with default profile
Figure 10. Cobalt Strike HTTP POST call-back request.

As seen in Figures 9 and 10, the GET and POST requests follow from the configuration options specified in the default profile. The GET request URI is /load (Figure 9), which is one of the default options for GET requests, and the POST request URI is /submit.php (Figure 10), which is the default option for POST requests. If all Cobalt Strike traffic used these default URIs, it would be much easier to write signatures to identify Cobalt Strike traffic; however, these signatures would not be able to identify traffic originating from customized profiles, as shown in the next example.

Customized Profile Sample

SHA256 Hash: fcdc426289dab0e5a73cd6fbac928ad48a8ff9b67e1d37df2794af6e7fa559e9

Cobalt Strike HTTP GET Beacon download request with a customized malleable C2 profile
Figure 11. Cobalt Strike HTTP GET Beacon download request.
Cobalt Strike HTTP GET heartbeat request with a customized malleable C2 profile
Figure 12. Cobalt Strike HTTP GET heartbeat request.
Cobalt Strike HTTP POST call-back request with a customized malleable C2 profile.
Figure 13. Cobalt Strike HTTP POST call-back request.

As we can see in Figures 12 and 13, the GET and POST request URIs have changed from the default profile. Both of these URIs are prepended with /MicrosoftUpdate in order to seem like a legitimate HTTP request to Microsoft servers for regular Windows updates – but are actually request and response traffic from C2 servers. This is how Cobalt Strike traffic from customized profiles can be so flexible and difficult to detect.

Cobalt Strike Beacon Configuration

In addition to the differences in GET and POST request parameters mentioned previously, Cobalt Strike Beacon configuration differs between default and custom profiles, and it contains useful metadata according to the settings in a Malleable C2 profile, which includes encoding types, blog submission mechanisms, instructions used to perform data transformations and other properties. By leveraging Didier Stevens’s 1768.py script, a researcher can decode and extract Cobalt Strike Beacon configurations. Didier is a security researcher known for his development of several analysis tools and other security-related topics.

A screenshot showing extracted configuration metadata for a custom profile Beacon.
Figure 14. Custom profile Beacon configuration Metadata.

Figure 14 shows extracted configuration metadata for a custom profile Beacon. The most visible differences between a default profile and a custom profile Beacon configuration are the number of instructions and data transformations, as well as the HTTP parameters used.

The table below shows the full list of differences between configuration metadata of the default and custom profile samples found in the wild that were previously discussed.

Default Profile (Beacon /Iya9) Custom Profile (Beacon /api/1)
0x000a post-uri
0x0003 0x0040 '/submit.php'
0x000b Malleable_C2_Instructions
0x0003 0x0100
  Transform Input: [7:Input,4]
   Print
0x000c http_get_header
0x0003
0x0200
  Build Metadata: [7:Metadata,3,6:Cookie]
   BASE64
   Header Cookie
0x000d http_post_header
0x0003
0x0200
  Const_header Content-Type: application/octet-stream
  Build SessionId: [7:SessionId,5:id]
   Parameter id
  Build Output: [7:Output,4]
   Print
0x000a post-uri
0x0003 0x0040 '
/MicrosoftUpdate/GetUpdate/KB'
0x000b Malleable_C2_Instructions
0x0003 0x0100
  Transform Input: [7:Input,4]
   Print
0x000c http_get_header
0x0003
0x0100
  Const_header User-Agent: Mozilla/4.0 (Compatible; MSIE 6.0;Windows NT 5.1)
  Const_header Accept: */*, ..., ......, .
  Build Metadata: [7:Metadata,11,5:tmp]
   NETBIOS uppercase
   Parameter tmp
0x000d http_post_header
0x0003
0x0100
  Const_header Content-Type: application/octet-stream
  Const_header User-Agent: Mozilla/4.0 (Compatible; MSIE 6.0;Windows NT 5.1)
  Build SessionId: [7:SessionId,1:/default.asp,12]
   Append /default.asp
   Uri_append
  Build Output: [7:Output,4]
   Print

Table 2. Default profile vs custom Profile configuration meta-data.

Conclusion

Cobalt Strike is a potent post-exploitation adversary emulator. The Malleable C2 profile detailed above is elaborate and is designed to evade security detections. A single security appliance is not equipped to prevent a Cobalt Strike attack. Only a combination of security solutions – firewalls, sandboxes, endpoints and software to integrate all these components can help prevent this kind of attack.

Palo Alto Networks customers are protected from this kind of attack by the following:

  1. Next-Generation Firewalls (NGFWs) with Threat Prevention signatures 86445 and 86446 identify HTTP C2 requests with default profiles.
  2. WildFire, an NGFW security subscription identifies and blocks Cobalt Strike Beacon.
  3. AutoFocus users can track this activity using the CobaltStrike tags

Indicators of Compromise

CS Samples

  • 6a6e5d2faeded086c3a97e14994d663e2ff768cb3ad1f5a1aa2a2b5fd344dde2
  • fcdc426289dab0e5a73cd6fbac928ad48a8ff9b67e1d37df2794af6e7fa559e9

CS Beacon Samples

  • /Iya9
    • 08e901d4ed0b43b46e632158f5ec5e900f16015e18995a875f62903a3c1eb1f9
  • /api/1
    • d8b385d680bcdf7646f35df612712f7a3991f50a21cac8379630d05b3d2337ae

CS Team Server Domain

  • www.symantecav[.]xyz

CS Team Server IP addresses

  • 66.42.72[.]250
  • 146.0.77[.]110

Additional Resources