I have been looking at several samples of Cobalt Strike beacons used in malware attacks. Although work is still ongoing, I already want to share my findings.
Cobalt Strike beacons communicating over HTTP encrypt their data with AES (unless a trial version is used). I found code to decrypt/encrypt such data in the PyBeacon and Geacon Github repositories.
This code works if you know the AES key: which is not a problem in the use cases of the code above, as it is developed to simulate a beacon. Beacons generate their own AES key, and thus these beacon simulations also generate their own AES key.
But what if you’re analyzing real beacons used in malware attacks? How do you obtain the AES key?
I found a way to extract the keys (AES and HMAC) from process memory of a running beacon.
I use the following procdump command to prepare process memory dumps:procdump -mp -w -s 1 -n 5 malware.exe
Then I start the beacon malware.exe in a malware analysis virtual machine while capturing traffic with Wireshark.
My new tool cs-extract-key.py looks in the dumped process memory for the unencrypted (RSA encryption) metadata that a beacon sends to the C2. This metadata contains the AES en HMAC keys.
This method does not always work: the metadata is overwritten after some time, so the process dump needs to be taken quickly after the beacon is started. And there are also cases were this metadata can not be found (I suspect this is version bound).
For those cases, my tool has another way of obtaining the keys. I extract the encrypted data of the first post of the beacon to the C2 (this is called a callback in the PyBeacon code):
And then I provide this to my tool, together with the process dump. My tool will then proceed with a dictionary attack: extract all possible AES and HMAC keys from the process dump, and try do authenticate and decrypt the callback. If this works, the keys have been found:
And once I have obtained the keys, I can pass them to my traffic decoding program that I have updated to include decryption (and that I have renamed to cs-parse-http-traffic.py):