Cybersecurity Tutorials

Cobalt Strike Analysis and Tutorial: CS Metadata Encoding and Decoding

Clock Icon 9 min read

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. Different elements of Cobalt Strike contribute to that versatility, including the encoding algorithm that obfuscates metadata sent to the C2 server.

In a previous blog, “Cobalt Strike Analysis and Tutorial: How Malleable C2 Profiles Make Cobalt Strike Difficult to Detect,” we learned that an attacker or red team can define metadata encoding indicators in Malleable C2 profiles for an HTTP transaction. When Cobalt Strike’s Beacon “phones home,” it sends metadata – information about the compromised system – to the Cobalt Strike TeamServer. The red team or attackers have to define how this metadata is encoded and sent with the HTTP request to finish the C2 traffic communication.

In this blog post, we will go through the encoding algorithm, describe definitions and differences of encoding types used in the Cobalt Strike framework, and cover some malicious attacks seen in the wild. In doing so, we demonstrate how the encoding and decoding algorithm works during the C2 traffic communication, and why this versatility makes Cobalt Strike an effective emulator for which it is difficult to design traditional firewall defenses.

Related Unit 42 Topics Cobalt Strike, C2, Tutorials

Metadata Encoding Algorithm

There are five encoding schemes supported by Cobalt Strike. The RSA-encrypted metadata is being encoded to easily transfer the ciphered binary data in network protocol.

Metadata encoding schemes supported by Cobalt Strike include Base64, Base64URL, Mask, NetBIOS and NetBIOSU
Figure 1. Encoding schemes in the Cobalt Strike profile.

Base64 Encoding and Decoding

Base64 Encoding and Decoding is a standard Request for Comments (RFC) algorithm implementation. The author has not made any changes to the Base64 Character set. Here is the list of characters used for encoding and decoding the data.

[ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' ]

Let's understand the use of the Base64 algorithm in Malleable profiles by studying an example.

1. Profile Metadata

Havex.profile uses Base64 encoding to transform metadata information about compromised systems before sending it. Figure 2 shows the metadata is encoded using the Base64 encoding algorithm and the result is placed in the Cookie header.

Metadata encoding options in Havex profile - as shown, the metadata is encoded using the Base64 encoding algortihm and the result is placed in the Cookie header.
Figure 2. Metadata encoding options in the Havex profile.

2. HTTP C2 traffic

Figure 3 shows the HTTP C2 traffic generated from the profiles. The highlighted part is the Base64-encoded metadata about the compromised machine.

HTTP C2 traffic generated from the Havex profile. The highlighted part is the Base64-encoded metadata about the compromised machine.
Figure 3. HTTP C2 traffic using the Havex profile.

 

3. Base64 Decoding

  • Any tool can decode the encrypted metadata. We have used the Python Base64 library to complete the task. Figure 4 shows a sample script to decode the data and print it in hex format.
  • Here is the decoded data from the script. This is RSA-encrypted metadata about the compromised system:
    751990bee317e74e4f2aa6f13078ef22dd884e065b738f8373f49dee401a069d5dfd1d3e39e94cc637e21364e1fd71ab3322fb9c7a987fc6aa27dfab981f077e7ddc2f20aba8e9d841250adc4edd4d15082445869278f2bbcf66e145aa74152a22b85c9b6c5f15d69f7d8b3708b33deea7198683d6468bd0424f537617f759b5
A sample Python script to decode the data and print it in hex format
Figure 4. Sample Python script to decode Base64 data.

Base64URL Encoding and Decoding

Base64URL is a modified version of the Base64 encoding algorithm. The modified version uses URL and filename-safe characters for encoding and decoding. Here is the character set:

[ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' ]

Compared to the Standard Base64 character set, the modified version has replaced + with ‘-’ and / with _’. The Pad character ‘=’ is skipped from the encoded data as it is normally percent-encoded in URI.

Let's understand the use of the Base64URL algorithm in Malleable profiles by studying an example.

1. Profile Metadata

Cnnvideo_getonly.profile uses Base64URL encoding to transform the metadata information. (Note that this profile is an example of mimicking legitimate CNN HTTP traffic and has no connection to the organization.) Figure 5 shows the metadata is encoded using the Base64URL encoding algorithm and appends the data to parameter g.

The sample shows the metadata is encoded using the Base64 encoding algorithm and appends the data to parameter g.
Figure 5. Metadata encoding in CNN video profile.

2. HTTP C2 traffic

Figure 6 shows the HTTP C2 traffic generated by the Beacon. The parameter value is the Base64URL-encoded metadata about the victim.

HTTP traffic generated by the Beacon. The parameter value is the Base64URL-encoded metadata about the victim.
Figure 6. HTTP C2 traffic generated using CNN video profile.

3. Base64URL decoding

A user has a couple of options to decode the data.

  • A user can replace the - with + and _ with /along with adding a pad character ‘=’. The replaced string becomes standard Base64-encoded data. Then any Base64 decoding tool can be used to get the encrypted metadata.
  • Use the scripting language to do the job. Figure 7 shows a sample Python script to decode the data. The urlsafe_b64decode instruction only replaces the characters and does not add padding. In the sample, we have added ‘=’ to make the output compatible with Base64 encoding. You can add more padding characters; Python only complains if it sees less padding.
  • The output of the script is RSA-encrypted metadata. “60495dff002eddaa0c409aaaae0fda592810993ae0ae319c87d62b65c54d92447daf2c1bc84930c5d90ed3a023227e254d3a2c28763be372bb7444ef5719d5948b99d33ede3775f51c216bba97bc5fd4777e819517e89a737284c784bdc30b1d6b3b7debe2448c1dc28b00e3ac611fd5a8fd070502f3f7f672786f6b5787af51”
A sample Python script to decode the data. The urlsafe_b64decode instruction only replaces the characters and does not add padding. In the sample, we have added '=' to make the output compatible with Base64 encoding.
Figure 7. Python script to decode the Base64URL.

NetBIOS Encoding and Decoding

NetBIOS encoding is used to encode NetBIOS service names. The Cobalt Strike tool uses the same algorithm to encode victim metadata when it is being transferred in C2 communication.

In the NetBIOS encoding algorithm, each byte is represented by two bytes of ASCII characters. Each 4-bit (nibble) of the input byte is treated as a separate byte by right adjusting/zero filling the binary number. This number is then added to the value of ASCII character a’. The resulting byte is stored as a separate byte. Here is the character set used for encoding: [‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’, ‘g’, ‘h’, ‘i’, ‘j’, ‘k’, ‘l’, ‘m’, ‘n’, ‘o’, ‘p’].

Figure 8 demonstrates the encoding process:

Demonstrates the NetBIOS encoding process, running from the original byte to the step that splits the nibbles and the final step that adds 'a' (Hex 0x61)
Figure 8. NetBIOS encoding process.

Let's understand the use of the NetBIOS algorithm in Malleable profiles by studying an example.

1. Profile Metadata

Ocsp.profile uses NetBIOS encoding to convert the victim’s metadata. Figure 9 shows the metadata is encoded using the NetBIOS encoding algorithm. The resulting data is appended to the URI.

The metadata is encoded using the NetBIOS algorithm. The resulting data is appended to the URI.
Figure 9. Metadata encoding in the OCSP profile.

 

2. HTTP C2 traffic

Figure 10 shows the HTTP traffic generated by the Beacon using the OCSP profile.

Figure 10. HTTP C2 traffic generated using the OCSP profile.
Figure 10. HTTP C2 traffic generated using the OCSP profile.

3. NetBIOS decoding

Figure 11 shows a Python implementation to decode the NetBIOS-encoded metadata.

The output of the script is RSA-encrypted metadata about the victim:
“5725245edcb589b305e33e02da1cda208ed083bed8a1ae0b3a87da0f9d6ebe31025ab67c58572acb9757288cc2e78bea414249fa8cb0783485a1b5a3c0863501fc1c89c6ac59b7129c51cacbfa197cc64eea31ec8ac204cbcdbefaecf19762f9efcc56280f3e9b183c37f98f371f5e1c08b645524646d7010af4408f4ebb8a2f”

A Python implementation to decode the NetBIOS-encoded metadata.
Figure 11. Python script to decode the NetBIOS encoding.

NetBIOSU Encoding and Decoding

The NetBIOSU algorithm is a slightly modified version of the NetBIOS algorithm discussed above. The slight change is the character set used for encoding the algorithm. In this algorithm, the character set is the uppercase version of the set used in the normal NetBIOS algorithm. Here is the set : [‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, ‘G’, ‘H’, ‘I’, ‘J’, ‘K’, ‘L’, ‘M’, ‘N’, ‘O’, ‘P’].

NetBIOSU uses the same encoding process as in the NetBIOS algorithm. Please refer to Figure 8 for more information.

Let's understand the use of the NetBIOSU algorithm in Malleable profiles by studying an example.

1. Profile Metadata

Asprox.profile uses NetBIOSU encoding to convert the victim’s metadata. Figure 12 shows the metadata is encoded using the NetBIOSU encoding algorithm. The resulting data is appended to the URI.

The metadata is encoded using the NetBIOSU encoding algorithm. The resulting data is appended to the URI.
Figure 12. Metadata encoding in the asprox profile.

2. HTTP C2 traffic

Figure 13 shows the HTTP traffic generated by the Beacon using the asprox profile, and the highlighted part is the metadata about the victim.

The HTTP traffic generation by the Beacon using the asprox profile. The highlighted part is the metadata about the victim.
Figure 13. HTTP C2 traffic generated using the asprox profile.

3. NetBIOSU decoding

Figure 14 shows a Python implementation to decode the NetBIOSU-encoded metadata.

The output of the script is RSA-encrypted metadata about the victim.
“722676e535f86ffc29ba1cafb9856d98d1f697a83b0afc5bb143e2cf2242152a351081fb837192da3e3b2d9021fab75ce32677b6299a24d15e28db883adb36c5fe448d5eb47014f6d2e72eff389f0176efced60380450c87e2015a8c5de6aa90dc8f105683ac5fd96dc33d4d63da62818facda595910cf9aee10f36fe54d4a6a”

A Python implementation to decode the NetBIOSU-encoded metadata.
Figure 14. Python script to decode the NetBIOSU encoding.

Mask Encoding and Decoding

The Mask encoding algorithm can be indicated and combined with other encoding algorithms in the Malleable C2 profile, which can be loaded by the TeamServer and used as C2 communication. The Beacon will generate the random four bytes as Mask xor key, then use the Mask key to xor the 128-byte metadata encrypted and send the Mask key and encoded data to the TeamServer for C2 communication, As an example, we walk through the randomized.profile to explain in more detail below.

1. Figure 15 is a partial profile with metadata encoded by Mask and Base64URL. The partial profile below defines the URI and metadata encoding algorithm as Mask and Base64URL, and the encoded metadata will be appended to the URI.

A partial profile with metadata encoded by Mask and Base64URL. The partila profile defines the URI and metadata encoding algorithm as Mask and Base64URL, and the encoded metadata will be appended to the URI.
Figure 15. Metadata encoding options in randomized profile.

2. HTTP C2 Traffic

Figure 16 is the C2 traffic based on the Figure 15 profile, so we can reverse the encoding data with the following steps.

  • From the traffic captured, we know that the entire URI is: /zChN7QMDhftv10Li9Cu-fm_T_3qDQawT-Z1GzNg1FWfAfSILT-u_rKLvXP-RE0ac-pxJTlGFCUIm4Aw9rGHPCIJVl0zNdCbM_G2VkYXJ5GGGtVh8S0LWMM4YLGZD9okLcFBc402j5zESK71HaR_owJb-AVBfFvAo8q0I2J74rmfGyIROyg
  • Remove the prefix /zC. The remaining value is encoded by Base64URL:
    hN7QMDhftv10Li9Cu-fm_T_3qDQawT-Z1GzNg1FWfAfSILT-u_rKLvXP-RE0ac-pxJTlGFCUIm4Aw9rGHPCIJVl0zNdCbM_G2VkYXJ5GGGtVh8S0LWMM4YLGZD9okLcFBc402j5zESK71HaR_owJb-AVBfFvAo8q0I2J74rmfGyIROyg
The C2 traffic based on the Figure 15 profile. It allows us to reverse the encoding data with the steps detailed in the text.
Figure 16. C2 traffic based on randomized profile.

3. Data encoding and decoding

  • Base64URL encoding and decoding
    The Base64URL-encoded data:
    hN7QMDhftv10Li9Cu-fm_T_3qDQawT-Z1GzNg1FWfAfSILT-u_rKLvXP-RE0ac-pxJTlGFCUIm4Aw9rGHPCIJVl0zNdCbM_G2VkYXJ5GGGtVh8S0LWMM4YLGZD9okLcFBc402j5zESK71HaR_owJb-AVBfFvAo8q0I2J74rmfGyIROyg
  • The Base64URL-decoded data:
    84ded030385fb6fd742e2f42bbe7e6fd3ff7a8341ac13f99d46ccd8351567c07d220b4febbfaca2ef5cff9113469cfa9c494e5185094226e00c3dac61cf088255974ccd7426ccfc6d959185c9e46186b5587c4b42d630ce182c6643f6890b70505ce34da3e731122bbd47691fe8c096fe01505f16f028f2ad08d89ef8ae67c6c8844eca0Using the Python Base64 library, as shown by the code in Figure 17, to decode the Base64URL-encoded data, the decoded hex data length is 132 and the first four bytes, 84ded030, are the Mask xor key. The remaining 128 bytes are the metadata encoded by the Mask xor algorithm.Base64URL decoded Python code:
Using the Python Base64 library to decode the Base64URL-encoded data.
Figure 17. Base64URL-decoded Python3 code.
  • Mask encoding and decodingThe Mask key is 84ded030The Mask-encoded data is:
    385fb6fd742e2f42bbe7e6fd3ff7a8341ac13f99d46ccd8351567c07d220b4febbfaca2ef5cff9113469cfa9c494e5185094226e00c3dac61cf088255974ccd7426ccfc6d959185c9e46186b5587c4b42d630ce182c6643f6890b70505ce34da3e731122bbd47691fe8c096fe01505f16f028f2ad08d89ef8ae67c6c8844eca0The Mask-decoded data is:
    bc8166cdf0f0ff723f3936cdbb2978049e1fefa950b21db3d588ac3756fe64ce3f241a1e71112921b0b71f99404a3528d44af25e841d0af6982e5815ddaa1ce7c6b21ff65d87c86c1a98c85bd1591484a9bddcd10618b40fec4e67358110e4eabaadc1123f0aa6a17a52d95f64cbd5c1ebdc5f1a545359df0e38ac5c0c9a3c90

    Using the Python code in Figure 18 to decode the Mask-encoded data, the decoded hex data length is 128 bytes. The 128 bytes are the encrypted metadata with an RSA algorithm that will be detailed in a forthcoming piece.

    Mask-decoded Python code:

The Python code shown here can be used to decode the Mask-encoded data.
Figure 18. Mask-decoded Python3 code.

Cases in the Wild

The following sections show two different cases of Cobalt Strike payloads found in the wild used by malware. One uses Base64 and the other uses Base64URL encoding. Palo Alto Networks identified them using static and dynamic analysis under the Unit42.CobaltStrike tag in the AutoFocus system.

Base64

SHA256: 6b6413a059a9f12d849c007055685d981ddb0ff308d6e3c2638d197e6d3e8802

An example of a case found in the wild of a Cobalt Strike used by malware that uses Base 64 metadata encoding.
Figure 19. Base64 encoding.

Base64URL Encoding

SHA256: f6e75c20ddcbe3bc09e1d803a8268a00bf5f7e66b7dbd221a36ed5ead079e093

An example of a case found in the wild of a Cobalt Strike used by malware that uses Base 64URL metadata encoding.
Figure 20. Base64URL encoding.

Conclusion

Cobalt Strike is a potent post-exploitation adversary emulator. The five encoding algorithms detailed above are elaborate and are 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 the Base64 metadata encoding in default profiles.
  2. WildFire, an NGFW security subscription, and Cortex XDR identify and block Cobalt Strike Beacon.
  3. AutoFocus users can track this activity using the CobaltStrike tag

Indicators of Compromise

CS Samples

  • 6b6413a059a9f12d849c007055685d981ddb0ff308d6e3c2638d197e6d3e8802
  • f6e75c20ddcbe3bc09e1d803a8268a00bf5f7e66b7dbd221a36ed5ead079e093

CS Beacon Samples

  • /n9Rd
    • SHA256 Hash:
      • fc95e7f4c8ec810646c16c8b6075b0b9e2cc686153cdad46e82d6cca099b19e7
  • /flas
    • SHA-256 Hash:
      • 11b8beaa53353f5f52607e994849c3086733dfa01cc57fea2dae42eb7a6ee972

CS TeamServer IP addresses

  • 80.255.3[.]109
  • 143.244.178[.]247

Additional Resources

Cobalt Strike Training
Cobalt Strike Malleable C2 Profile
Cobalt Strike Analysis and Tutorial: How Malleable C2 Profiles Make Cobalt Strike Difficult to Detect
Cobalt Strike Attack Detection & Defense Technology Overview

Enlarged Image