This post is also available in: 日本語 (Japanese)
Cobalt Strike is commercial threat emulation software that mimics 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. Different elements of Cobalt Strike contribute to its versatility, including the processes that encrypt and decrypt metadata sent to the C2 server.
In a previous blog, “Cobalt Strike Analysis and Tutorial: CS Metadata Encoding and Decoding,” we learned that the encrypted metadata is encoded for an HTTP transaction.
When Cobalt Strike’s Beacon “phones home,” it encrypts metadata – information about the compromised system – with the RSA algorithm public key and sends it to the Cobalt Strike TeamServer. The TeamServer will use the private key to recover the Beacon plaintext metadata to differentiate the Beacon clients. Also, the AES symmetric key can be extracted from decrypted metadata. The client and server can use the AES key to encrypt and decrypt the further request and response data to finish the C2 traffic communication.
In this blog post, we will detail and demonstrate the data encryption and decryption algorithm, key generation and extraction, metadata encryption and decryption, and metadata schema definitions. One of the interesting components is how the encryption and decryption algorithm works during C2 traffic communication – and why this versatility makes Cobalt Strike an effective emulator that is difficult to defend against.
Data Encryption/Decryption Algorithm
Metadata Schema Definition
Public/Private Key Generation and Extraction
An Example of C2 Metadata Encryption/Decryption with RSA and AES
Conclusion
Indicators of Compromise
Additional Resources
The Cobalt Strike Beacon communicates with the TeamServer using a combination of symmetric (AES) and asymmetric (RSA) encryption key algorithms. The TeamServer will then create a new public/private key combination and store the key pair in a .cobaltstrike.beacon_keys file. The file is stored in the same directory where the Cobalt Strike setup is extracted. If the file already exists, it uses the same key pair.
The asymmetric key algorithm uses RSA/ECB/PKCS1Padding, while the symmetric key algorithm uses the AES/CBC/NoPadding format to encrypt/decrypt the data. The AES algorithm is initialized with a hard-coded initialization vector (IV). The static IV is abcdefghijklmnop.
Figure 1 highlights the C2 traffic between the Cobalt Strike Beacon and the TeamServer.
As the name suggests, metadata contains information about the target. The metadata follows a structured format with the 4-byte magic number (0xBEEF) at the start. Figure 2 shows the metadata structure.
The decrypted data is a blob of different information. The structure of the decrypted blob was updated in Cobalt Strike version 4.0, and the Beacon has added more information in the metadata. The size of the data field is 4 bytes long, and this suggests that the author may update the metadata structure in the future. Figure 3 shows the various types of information packed in the metadata. This structure is in accordance with the current implementation.
Below is the breakdown of the various data fields in the decrypted data in order.
When the Beacon checks in, it will send the metadata blob encrypted by the RSA public key to the TeamServer. The TeamServer uses the private key to decrypt and recover the plain text metadata and extract the AES key along with other metadata used for further communication. This can prevent a meddler-in-the-middle (MitM) attack and evade detection since the AES key is encrypted by asymmetric key, which is extremely difficult to decipher. Additionally, the C2 communication is encrypted by the symmetric key, making it difficult to find a fingerprint to mark it.
When the TeamServer starts with the profile loaded, it generates a public/private key pair and stores them in the .cobaltstrike.beacon_keys file in the TeamServer root directory if the file doesn’t exist.
We can use the key dump Java program shared in GitHub to extract the public/private key. See below for details on how this is done.
1. Public/private key pair stored in .cobaltstrike.beacon_keys as java.security.KeyPair object as Figure 4 shows.
2. Execute the command in Figure 5 to compile and run the Java program in the TeamServer root directory, and then the public/private key pair will be base64 encoded.
In the following example, we will discuss how both encryption and decryption work in the context of Cobalt Strike Beacon’s metadata and C2 HTTP traffic communication.
The analysis is of a sample taken from the wild, downloadable directly from VirusTotal (SHA256: 50ea11254f184450a7351d407fbb53c54686ce1e62e99c0a41ee7ee3e505d60c).
The C2 traffic analysis for this example is separated into three sections:
These sections contain encryption/decryption analysis that will describe the following process:
By parsing the configuration using the 1768.py script, it can be shown that the Beacon was generated by a version of Cobalt Strike’s software that has leaked RSA private keys.
Once the Beacon was downloaded and executed, the next step was to perform a C2 checkin on the TeamServer and to exfiltrate encrypted metadata information about the compromised machine inside of the cookie of the HTTP request.
In order to decrypt the metadata information, an execution of the cs-crypto-parser.py script (a slightly modified version of the cs-mitm.py script) should be performed and pass the value from the cookie – XjaoBxbLchqKBL/s/m8Pgz/wHRbx660/2Aa8Toa9T/AJ0Ns8mgjPBWdYIL9mEFM1DE/5GXGCSURf6RP+wxo5Zx0G/yENlMTuzPaCO11/XPNxRjj69Nf6++05qe7iMKfg8D4ZFGiEQAVo6UXqUteZlAqubJ+uNZBglsyioa+aSQw= – as a first argument.
The first task this script performs is a call to the RSADecrypt() function that receives two parameters: 1) The private key, and 2) The encrypted cookie value. Once this task is completed, it decodes and imports the RSA private key and instantiates a new PKCS1 object. Finally, the script calls the decrypt function and passes the encrypted data variable as argument to perform the actual decryption of the ciphertext.
The output will show a detailed breakdown of the metadata along with its hex values.
Readers can use the Metadata Schema Definition section of this blog for reference.
The payload is encrypted using AES256 encryption in CBC mode with an HMAC SHA256-keyed hashing algorithm. Since there is access to the RSA private key and the decrypted data, it includes the raw key. This key is 16 bytes long and is located at the eighth byte of the decrypted payload. In the case of this malware sample, the key (hex) is 1a 13 7e 76 f9 15 6a 67 f9 99 af d6 57 64 75 bd. In order to generate the AES and HMAC keys, the SHA256 hash is computed out of the raw key where the first half (16 bytes) is the actual AES key and the second half (16 bytes) is the HMAC key. Figure 11 below depicts such computation by the execution of the crypto-parser script.
Once a C2 channel is established and the checkin action is in place, the Beacon performs a check or any new tasks. In Figure 12, you will see that the task request received a response payload from the TeamServer.
The payload data of 48 bytes is now passed to the script to get decrypted. The last 16 bytes of the encrypted blob is the HMAC Signature that acts as an integrity measure for the request. FIgure 13 below shows the data parsing and decryption of the task payload.
The decryption process is handled by the Decrypt() function, which performs the following actions:
When a Beacon receives and executes a task provided by the C2 server, the results are collected and returned to the TeamServer.
By using the same Decrypt() function mentioned above, the encrypted payload is also provided. However, for a Cobalt Strike task response, the first four bytes are not considered for decryption, resulting in those bytes being excluded in the data passed to the function.
The task data response contained in this request corresponds to the ASCII string BOBSPC\\Administrator, which is the machine and user of the compromised computer.
Cobalt Strike is a potent post-exploitation adversary emulator. The metadata encryption/decryption detailed above are elaborate and are designed to evade security detections. A single security appliance is not well-suited to prevent a Cobalt Strike attack. Only a combination of security solutions – firewalls, sandboxes, endpoints and the appropriate software to integrate all these components – can help prevent an attack of this nature.
Palo Alto Networks customers receive protections from attacks similar to those by Cobalt Strike with the help of:
Cobalt Strike Training
Cobalt Strike Malleable C2 Profile
Cobalt Strike Decryption with Known Private Key
Cobalt Strike Analysis and Tutorial: How Malleable C2 Profiles Make Cobalt Strike Difficult to Detect
Cobalt Strike Analysis and Tutorial: CS Metadata Encoding and Decoding
Sign up to receive the latest news, cyber threat intelligence and research from us