{
	"id": "ee6ee692-c68b-4dd5-935b-64a8a5166185",
	"created_at": "2026-04-06T00:09:40.768347Z",
	"updated_at": "2026-04-10T03:24:24.677635Z",
	"deleted_at": null,
	"sha1_hash": "a858f65a853afb4d2c6c876365b0de884f3faa5c",
	"title": "Cobalt Strike Analysis and Tutorial: CS Metadata Encryption and Decryption",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1377054,
	"plain_text": "Cobalt Strike Analysis and Tutorial: CS Metadata Encryption and\r\nDecryption\r\nBy Chris Navarrete, Durgesh Sangvikar, Yu Fu, Yanhui Jia, Siddhart Shibiraj\r\nPublished: 2022-07-13 · Archived: 2026-04-05 17:47:41 UTC\r\nExecutive Summary\r\nCobalt Strike is commercial threat emulation software that mimics a quiet, long-term embedded actor in a network. This\r\nactor, known as Beacon, communicates with an external team server to emulate command-and-control (C2) traffic. Due to\r\nits versatility, Cobalt Strike is commonly used as a legitimate tool by red teams – but is also widely used by threat actors for\r\nreal-world attacks. Different elements of Cobalt Strike contribute to its versatility, including the processes that encrypt and\r\ndecrypt metadata sent to the C2 server.\r\nIn a previous blog, “Cobalt Strike Analysis and Tutorial: CS Metadata Encoding and Decoding,” we learned that the\r\nencrypted metadata is encoded for an HTTP transaction.\r\nWhen Cobalt Strike’s Beacon “phones home,” it encrypts metadata – information about the compromised system – with the\r\nRSA algorithm public key and sends it to the Cobalt Strike TeamServer. The TeamServer will use the private key to recover\r\nthe Beacon plaintext metadata to differentiate the Beacon clients. Also, the AES symmetric key can be extracted from\r\ndecrypted metadata. The client and server can use the AES key to encrypt and decrypt the further request and response data\r\nto finish the C2 traffic communication.\r\nIn this blog post, we will detail and demonstrate the data encryption and decryption algorithm, key generation and\r\nextraction, metadata encryption and decryption, and metadata schema definitions. One of the interesting components is how\r\nthe encryption and decryption algorithm works during C2 traffic communication – and why this versatility makes Cobalt\r\nStrike an effective emulator that is difficult to defend against.\r\nData Encryption/Decryption Algorithm\r\nThe Cobalt Strike Beacon communicates with the TeamServer using a combination of symmetric (AES) and asymmetric\r\n(RSA) encryption key algorithms. The TeamServer will then create a new public/private key combination and store the key\r\npair in a .cobaltstrike.beacon_keys file. The file is stored in the same directory where the Cobalt Strike setup is extracted. If\r\nthe file already exists, it uses the same key pair.\r\nThe asymmetric key algorithm uses RSA/ECB/PKCS1Padding, while the symmetric key algorithm uses the\r\nAES/CBC/NoPadding format to encrypt/decrypt the data. The AES algorithm is initialized with a hard-coded initialization\r\nvector (IV). The static IV is abcdefghijklmnop.\r\nFigure 1 highlights the C2 traffic between the Cobalt Strike Beacon and the TeamServer.\r\nFigure 1. C2 Communication between the Beacon process and the TeamServer.\r\nMetadata Schema Definition\r\nAs the name suggests, metadata contains information about the target. The metadata follows a structured format with the 4-\r\nbyte magic number (0xBEEF) at the start. Figure 2 shows the metadata structure.\r\nhttps://unit42.paloaltonetworks.com/cobalt-strike-metadata-encryption-decryption/\r\nPage 1 of 8\n\nFigure 2. Beacon metadata structure.\r\nThe decrypted data is a blob of different information. The structure of the decrypted blob was updated in Cobalt Strike\r\nversion 4.0, and the Beacon has added more information in the metadata. The size of the data field is 4 bytes long, and this\r\nsuggests that the author may update the metadata structure in the future. Figure 3 shows the various types of information\r\npacked in the metadata. This structure is in accordance with the current implementation.\r\nFigure 3. Metadata schema.\r\nBelow is the breakdown of the various data fields in the decrypted data in order.\r\nThe first 16 bytes are the random bytes generated by the Beacon and are unique to each process run. The Beacon and\r\nTeamServer use these bytes to create the AES key and HMAC key. The process calculates the SHA256 hash of the\r\nbytes. The first 16 bytes of the SHA256 are assigned as the AES key for symmetric encryption, and the remaining 16\r\nbytes are the HMAC keys for the message authentication code.\r\nThe next two little endian bytes are decoded as ANSI Charset. For the complete list of charsets, refer to\r\ndocumentation on Code Page Identifiers.\r\nTwo little endian bytes are assigned to OEM Charsets.\r\nFour big-endian bytes are the Beacon ID, with each Beacon getting a unique ID.\r\nFour big-endian bytes are the Process ID of the Beacon on the victim’s machine.\r\nTwo bytes are decoded as the port.\r\nOne byte decodes as the flag. In the current implementation of Cobalt Strike, the flag value is used to set the\r\narchitecture (32/64 bit) of the Beacon.\r\nTwo bytes are the Beacon version number. These bytes are converted into a string with a “.” inserted between them.\r\nEx: A.B\r\nTwo bytes are decoded as the build version of the Beacon.\r\nThe next 4-byte big endian value is used to prefix the pointers to functions if the architecture of the beacon is 64 bit.\r\nThese 4 bytes are discarded if the architecture is 32 bit.\r\nThe following two 4-byte values are the pointers to GetModuleHandleA and GetProcAddress. The value of these will\r\nhelp the shellcode to resolve further functions without being imported explicitly. If the Beacon is 64 bit, the earlier\r\nvalues are prefixed and the entire value is stored in a variable.\r\nNext four bytes are the IP address of the target. The bytes are then converted to an IPv4-readable address.\r\nLast set of bytes are UTF-8, and the values are delimited by \\t. As of the current version, the data is structured as\r\nComputerName\\tUserName\\tBeaconProcessName\r\nPublic/Private Key Generation and Extraction\r\nWhen the Beacon checks in, it will send the metadata blob encrypted by the RSA public key to the TeamServer. The\r\nTeamServer uses the private key to decrypt and recover the plain text metadata and extract the AES key along with other\r\nmetadata used for further communication. This can prevent a meddler-in-the-middle (MitM) attack and evade detection\r\nsince the AES key is encrypted by asymmetric key, which is extremely difficult to decipher. Additionally, the C2\r\ncommunication is encrypted by the symmetric key, making it difficult to find a fingerprint to mark it.\r\nWhen the TeamServer starts with the profile loaded, it generates a public/private key pair and stores them in the\r\n.cobaltstrike.beacon_keys file in the TeamServer root directory if the file doesn’t exist.\r\nWe can use the key dump Java program shared in GitHub to extract the public/private key. See below for details on how this\r\nis done.\r\n1. Public/private key pair stored in .cobaltstrike.beacon_keys as java.security.KeyPair object as Figure 4 shows.\r\nhttps://unit42.paloaltonetworks.com/cobalt-strike-metadata-encryption-decryption/\r\nPage 2 of 8\n\nFigure 4. Public/private key pair Java object.\r\n2. Execute the command in Figure 5 to compile and run the Java program in the TeamServer root directory, and then the\r\npublic/private key pair will be base64 encoded.\r\nFigure 5. Public/private key.\r\nAn Example of C2 Metadata Encryption/Decryption with RSA and AES\r\nIn the following example, we will discuss how both encryption and decryption work in the context of Cobalt Strike Beacon’s\r\nmetadata and C2 HTTP traffic communication.\r\nThe analysis is of a sample taken from the wild, downloadable directly from VirusTotal (SHA256:\r\n50ea11254f184450a7351d407fbb53c54686ce1e62e99c0a41ee7ee3e505d60c).\r\nThe C2 traffic analysis for this example is separated into three sections:\r\n1. Cobalt Strike Beacon Download\r\n2. C2 Beacon Heartbeat\r\n3. C2 Tasks Request and Response (Callback)\r\nThese sections contain encryption/decryption analysis that will describe the following process:\r\n1. Decrypt metadata using RSA public/private leaked keys to get the AES and HMAC keys.\r\n2. Use an AES key to decrypt the task data encrypted in the HTTP GET response.\r\n3. Use an AES key to decrypt the task execution result in the HTTP POST request body.\r\nCobalt Strike Beacon Download\r\nFigure 6. Beacon download\r\nBy parsing the configuration using the 1768.py script, it can be shown that the Beacon was generated by a version of Cobalt\r\nStrike’s software that has leaked RSA private keys.\r\nhttps://unit42.paloaltonetworks.com/cobalt-strike-metadata-encryption-decryption/\r\nPage 3 of 8\n\nFigure 7. Beacon parsing/private key search.\r\nC2 Beacon Heartbeat\r\nOnce the Beacon was downloaded and executed, the next step was to perform a C2 checkin on the TeamServer and to\r\nexfiltrate encrypted metadata information about the compromised machine inside of the cookie of the HTTP request.\r\nFigure 8. C2 Heartbeat.\r\nIn order to decrypt the metadata information, an execution of the cs-crypto-parser.py script (a slightly modified version of\r\nthe cs-mitm.py script) should be performed and pass the value from the cookie –\r\nXjaoBxbLchqKBL/s/m8Pgz/wHRbx660/2Aa8Toa9T/AJ0Ns8mgjPBWdYIL9mEFM1DE/5GXGCSURf6RP+wxo5Zx0G/yENlMTuzPaCO11/XPNxRjj69\r\n– as a first argument.\r\nRSA Decryption\r\nThe first task this script performs is a call to the RSADecrypt() function that receives two parameters: 1) The private key,\r\nand 2) The encrypted cookie value. Once this task is completed, it decodes and imports the RSA private key and instantiates\r\na new PKCS1 object. Finally, the script calls the decrypt function and passes the encrypted data variable as argument to\r\nperform the actual decryption of the ciphertext.\r\nFigure 9. RSADecrypt function.\r\nThe output will show a detailed breakdown of the metadata along with its hex values.\r\nhttps://unit42.paloaltonetworks.com/cobalt-strike-metadata-encryption-decryption/\r\nPage 4 of 8\n\nFigure 10. C2 decrypted metadata.\r\nReaders can use the Metadata Schema Definition section of this blog for reference.\r\nC2 Task Request and Response (Callback)\r\nAES and HMAC Keys\r\nThe payload is encrypted using AES256 encryption in CBC mode with an HMAC SHA256-keyed hashing algorithm. Since\r\nthere is access to the RSA private key and the decrypted data, it includes the raw key. This key is 16 bytes long and is\r\nlocated 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\r\n67 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\r\nwhere the first half (16 bytes) is the actual AES key and the second half (16 bytes) is the HMAC key. Figure 11 below\r\ndepicts such computation by the execution of the crypto-parser script.\r\nFigure 11. Encryption/decryption hash and keys.\r\nC2 Task Request\r\nOnce a C2 channel is established and the checkin action is in place, the Beacon performs a check or any new tasks. In Figure\r\n12, you will see that the task request received a response payload from the TeamServer.\r\nhttps://unit42.paloaltonetworks.com/cobalt-strike-metadata-encryption-decryption/\r\nPage 5 of 8\n\nFigure 12. C2 task request (retrieval).\r\nThe payload data of 48 bytes is now passed to the script to get decrypted. The last 16 bytes of the encrypted blob is the\r\nHMAC Signature that acts as an integrity measure for the request. FIgure 13 below shows the data parsing and decryption of\r\nthe task payload.\r\nFigure 13. Cobalt Strike task request payload decryption.\r\nThe decryption process is handled by the Decrypt() function, which performs the following actions:\r\n1. Receive the encrypted data as parameter.\r\n2. Extract the HMAC signature out of the encrypted payload.\r\n3. Calculate and validate the HMAC signature by using the HMAC key on the encrypted payload.\r\n4. Load the AES key and set the mode (CBC), and its initialization vector (IV).\r\n5. Decrypt the encrypted payload.\r\nFigure 14. AES / HMAC decryption function.\r\nC2 Task Response\r\nWhen a Beacon receives and executes a task provided by the C2 server, the results are collected and returned to the\r\nTeamServer.\r\nhttps://unit42.paloaltonetworks.com/cobalt-strike-metadata-encryption-decryption/\r\nPage 6 of 8\n\nFigure 15. Cobalt Strike task response (data exfiltration).\r\nBy using the same Decrypt() function mentioned above, the encrypted payload is also provided. However, for a Cobalt\r\nStrike task response, the first four bytes are not considered for decryption, resulting in those bytes being excluded in the data\r\npassed to the function.\r\nFigure 16. Cobalt Strike task response decryption.\r\nThe task data response contained in this request corresponds to the ASCII string BOBSPC\\\\Administrator, which is the\r\nmachine and user of the compromised computer.\r\nConclusion\r\nCobalt Strike is a potent post-exploitation adversary emulator. The metadata encryption/decryption detailed above are\r\nelaborate and are designed to evade security detections. A single security appliance is not well-suited to prevent a Cobalt\r\nStrike attack. Only a combination of security solutions – firewalls, sandboxes, endpoints and the appropriate software to\r\nintegrate all these components – can help prevent an attack of this nature.\r\nPalo Alto Networks customers receive protections from attacks similar to those by Cobalt Strike with the help of:\r\n1. Next-Generation Firewalls (NGFW) with Threat Prevention signatures 86445 and 86446 identify HTTP C2 requests\r\nwith the base64 metadata encoding in default profiles. Advanced Threat Prevention has new capabilities to detect\r\nthese attacks without the need for signatures.\r\n2. WildFire, an NGFW security subscription, and Cortex XDR identify and block Cobalt Strike Beacon.\r\n3. AutoFocus users can track this activity using the CobaltStrike tag\r\nIndicators of Compromise\r\nCS Samples\r\n50ea11254f184450a7351d407fbb53c54686ce1e62e99c0a41ee7ee3e505d60c\r\nCS Beacon Samples\r\n/lNj8\r\nSHA256 Hash:\r\nhttps://unit42.paloaltonetworks.com/cobalt-strike-metadata-encryption-decryption/\r\nPage 7 of 8\n\ne712d670382ad6f837feeb5a66adb2d0f133481b5db854de0dd4636d7e906a8e\r\nCS TeamServer IP addresses\r\n92.255.85[.]93\r\nAdditional Resources\r\nCobalt Strike Training\r\nCobalt Strike Malleable C2 Profile\r\nCobalt Strike Decryption with Known Private Key\r\nCobalt Strike Analysis and Tutorial: How Malleable C2 Profiles Make Cobalt Strike Difficult to Detect\r\nCobalt Strike Analysis and Tutorial: CS Metadata Encoding and Decoding\r\nCobalt Strike Attack Detection \u0026 Defense Technology Overview\r\nSource: https://unit42.paloaltonetworks.com/cobalt-strike-metadata-encryption-decryption/\r\nhttps://unit42.paloaltonetworks.com/cobalt-strike-metadata-encryption-decryption/\r\nPage 8 of 8",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia",
		"ETDA"
	],
	"references": [
		"https://unit42.paloaltonetworks.com/cobalt-strike-metadata-encryption-decryption/"
	],
	"report_names": [
		"cobalt-strike-metadata-encryption-decryption"
	],
	"threat_actors": [
		{
			"id": "610a7295-3139-4f34-8cec-b3da40add480",
			"created_at": "2023-01-06T13:46:38.608142Z",
			"updated_at": "2026-04-10T02:00:03.03764Z",
			"deleted_at": null,
			"main_name": "Cobalt",
			"aliases": [
				"Cobalt Group",
				"Cobalt Gang",
				"GOLD KINGSWOOD",
				"COBALT SPIDER",
				"G0080",
				"Mule Libra"
			],
			"source_name": "MISPGALAXY:Cobalt",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		}
	],
	"ts_created_at": 1775434180,
	"ts_updated_at": 1775791464,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/a858f65a853afb4d2c6c876365b0de884f3faa5c.pdf",
		"text": "https://archive.orkl.eu/a858f65a853afb4d2c6c876365b0de884f3faa5c.txt",
		"img": "https://archive.orkl.eu/a858f65a853afb4d2c6c876365b0de884f3faa5c.jpg"
	}
}