Didier Stevens

Friday 12 November 2021

Update: cs-decrypt-metadata.py Version 0.0.2

Filed under: Encryption,My Software,Update — Didier Stevens @ 0:00

This new version of my tool to decrypt Cobalt Strike metadata, now supports transformations.

By default, encrypted metadata in Cobalt Strike traffic is encoded with BASE64 and then transmitted via the Cookie header in HTTP(S) requests.

This metadata is encrypted with a public RSA key, and can be decrypted if the private key is known.

Here is an example of a malicious beacon with a specific metadata encoding.

Analyzing the beacon with my tool 1768.py yields the following information:

First: a public key (field 0x0007) is used, for which we know the private key: thus we will be able to decrypt the metadata.

Second: the encrypted metadata has a specific encoding (field 0x000c). This beacon was configured with a profile that specifies that the encrypted metadata must be encoded with BASE64 URL-safe (this is a variant of BASE64, that uses characters – and _ in stead of + and /). Then it is prefixed with string __cfduid= and transmitted via the Cookie header.

An error will result when this data is processed by tool cs-decrypt-metadata.py without providing the transformation instructions:

The following transformation instructions must be provided to properly decode and decrypt the metadata: 7:Metadata,13,2:__cfduid=,6:Cookie

This is done with option -t:

cs-decrypt-metadata_V0_0_2.zip (https)
MD5: 368EA059E91716DD071975B13A3F108D
SHA256: B906191D376F81E687392EC30EA57483BFC791E3D478E863FA0DB7B468662310

Thursday 4 November 2021

Update: 1768.py Version 0.0.9

Filed under: My Software,Update — Didier Stevens @ 0:00

This new version of 1768.py, my tool to decode Cobalt Strike beacon configs, brings proper decoding of malleable instructions.

And the license ID statistics have been updated, and 3 new private RSA keys have been added.

Fields 0x000b (Malleable_C2_Instructions), 0x000c (http_get_header) and 0x000d (http_post_header) contain instructions on how to transform data. Until now, my tool did not properly parse these instructions, because I had no need for them. It just extracted the strings found inside the binary data of these fields.

But this has changed, now that I’m improving my tools to parse and decrypt Cobalt Strike network traffic: I need these instructions to properly parse traffic.

Let’s start with a malicious beacon, that uses the default profile:

Field Malleable_C2_Instructions (0x000b) contains instructions on how to transform the data send by the team server to the beacon. For the default profile, like this sample, the instructions are just a print statement: this means that the received data can be decrypted as-is, that no transformation prior to decryption is necessary.

Field http_get_header (0x000c) contains instructions on how to generate the HTTP request that the beacon sends to the team server to obtain tasks it should execute. By default, this is done with a GET request. For the default profile, like this sample, the instructions explain how to transform the metadata. The encrypted metadata has to be BASE64 encoded, and then transmitted via the Cookie header.

Field http_post_header (0x000d) contains instructions on how to generate the HTTP request that the beacon sends to the team server to report the results (callbacks) of the tasks it has executed. By default, this is done with a POST request. For the default profile, like this sample, the instructions explain how to transform the session id and the encrypted callback data.

The session id has just to be transmitted via the id parameter in the POST request.

For the encrypted callback data (output), the instructions are just a print statement: this means that the data to be transmitted can be transmitted as-is, that no transformation prior to posting is necessary.

That was a malicious beacon with a default profile.

Now let’s take a look at another malicious beacon, with a custom profile:

For the received data (field 0x000b or the input, e.g., encrypted tasks received by the beacon), the following instructions need to be applied:

  1. Receiving the data (print)
  2. Removing 1522 bytes from the end of the received data
  3. Removing 84 bytes from the beginning of the remaining data
  4. Removing 3931 bytes from the beginning of the remaining data
  5. Decoding this remaining data with a BASE64 decoder for URLs
  6. XOR-ing the BASE64 decoded data with a 4-byte key that is found at the beginning of the remaining data

Remark that 1768.py reports these instructions twice: once in a human-readable format (see screenshot), and once in an encoded format between [] that my other tools can parse: [7:Input,4,1:1522,2:84,2:3931,13,15]

This data is transmitted by the beacon to the team server, via an HTTP request (GET in this sample). The headers to be included in this HTTP GET request are specified in field 0x000c:

And the metadata needs to be encoded and transmitted as follows (field 0x000c, Build Metadata):

  1. Encoding the encrypted metadata with a BASE64 encoder for URLs
  2. prepending value __cfduid= to this base64-encoded data
  3. Including the resulting data in the GET request via the Cookie header

For the transmitted data (field 0x000d or the output, e.g., encrypted callbacks sent by the beacon), the following instructions (Build Output) need to be applied:

  1. XOR-ing the encrypted data with a 4-byte key random key, that is prepended to the XORed data
  2. Encoding the resulting data with a BASE64 encoder
  3. Transmitting the data (print)

Field 0x000d also specifies the headers that need to be added to the POST request:

And field 0x000d also specifies how to transform and transmit the session id. The following instructions (Build SessionId) need to be applied:

  1. XOR-ing the session id with a 4-byte key random key, that is prepended to the XORed data
  2. Encoding the resulting data with a BASE64 encoder for URLs
  3. Including this encoded data to the POST request via parameter __cfduid

The encoded instructions (for my other tools) are: [7:Output,15,13,4]

Remark: although I show these instructions for HTTP communication, they are also applied for other protocols, like HTTPS and DNS.

1768_v0_0_9.zip (https)
MD5: 2AFD580D2BDA78F6FA8A240947661E1F
SHA256: 45841091C6AF270A508674B31389CCB1ED44346CD3A146FBE7AFC21940B00548

Wednesday 3 November 2021

New Tool: cs-extract-key.py

Filed under: Announcement,Encryption,My Software — Didier Stevens @ 0:00

cs-extract-key.py is a tool designed to extract cryptographic keys from Cobalt Strike beacon process memory dumps.

This tool was already available in my beta repository.

This tool can extract cryptographic keys from process memory dumps of a version 3.x beacon directly:

And from version 4.x together with encrypted data extracted from network capture:

More details can be found in the man page, and in and upcoming blog post.

cs-extract-key_V0_0_1.zip (https)
MD5: 4102A5A5BFD4D432DA4A721D43F568F5
SHA256: BBEDF6CBFFF51669187694F463C32A49F53420BEDF8B76508D06850643DE334F

Monday 1 November 2021

Overview of Content Published in October

Filed under: Announcement — Didier Stevens @ 0:00

Here is an overview of content I published in October:

Blog posts:

YouTube videos:

Videoblog posts:

SANS ISC Diary entries:

NVISO blog posts:

Friday 22 October 2021

New Tool: cs-decrypt-metadata.py

Filed under: Announcement,Encryption,My Software,Reverse Engineering — Didier Stevens @ 0:00

cs-decrypt-metadata.py is a new tool, developed to decrypt the metadata of a Cobalt Strike beacon.

An active beacon regularly checks in with its team server, transmitting medata (like the AES key, the username & machine name, …) that is encrypted with the team server’s private key.

This tool can decrypt this data, provided:

  1. you give it the file containing the private (and public) key, .cobaltstrike.beacon_keys (option -f)
  2. you give it the private key in hexadecimal format (option -p)
  3. the private key is one of the 6 keys in its repository (default behavior)

I will publish blog posts explaining how to use this tool.

Here is a quick example:

cs-decrypt-metadata_V0_0_1.zip (https)
MD5: 31F94659163A6E044A011B0D82623413
SHA256: 50ED1820DC63009B579D7D894D4DD3C5F181CFC000CA83B2134100EE92EEDD9F

Thursday 21 October 2021

“Public” Private Cobalt Strike Keys

Filed under: Encryption,Malware,My Software — Didier Stevens @ 18:05

I found 6 private keys used by malicious Cobalt Strike servers. There’s a significant number of malicious CS servers on the Internet that reuse these keys, thus allowing us to decrypt their C2 traffic. For the details, I recommend reading the following blog post I wrote “Cobalt Strike: Using Known Private Keys To Decrypt Traffic – Part 1“.

I integrated these keys in the database (1768.json) of my tool 1768.py (starting version 0.0.8).

Whenever you analyze a beacon with 1768.py that uses a public key with a known private key, the report will point this out:

And when you use option verbose, the private key will be included:

If you want to integrated these 6 keys in your own tools: be my guest. You can find these key pairs in 1768.json.

Monday 11 October 2021

Update: 1768.py Version 0.0.8

Filed under: My Software,Update — Didier Stevens @ 0:00

This new version brings an update to the statistics in file 1768.json.

1768_v0_0_8.zip (https)
MD5: C410C38FC2B5F0B2C3104D7FC1D35C58
SHA256: 9374650575E0F15331CE05ACFD2BFA4CD6EBEB1497207B9B6D4B1F7A0214457D

Sunday 3 October 2021

New Tool: onion-connect-service-detection.py

Filed under: My Software,Networking — Didier Stevens @ 0:00

To better understand how nmap does service detection, I implemented a tool in Python that tries to do (more or less) the same. nmap detects what service is listening on a port, by sending it probes (particular byte sequences) and matching it with expected replies. These probes and replies can be found in file nmap-service-probes.

It allows me to experiment with service detection.

By default onion-connect-service-detection.py connects to service ports over the Tor network.

Here is an example where I use the tool to detect services on the 10 most popular ports (top:10) of example.com. With a time-out of 5 seconds.

onion-connect-service-detection_V0_0_1.zip (https)
MD5: 8C6D94E1CEE4747E18807CB95FCB1EE9
SHA256: ADC8D937522F55CC47C91E5DC01B2B7D22372E5726542DAF84134279643F8297

Saturday 2 October 2021

Overview of Content Published in September

Filed under: Announcement — Didier Stevens @ 19:33
Here is an overview of content I published in September:
Blog posts: YouTube videos: Videoblog posts: SANS ISC Diary entries:

Wednesday 29 September 2021

Update: base64dump.py Version 0.0.17

Filed under: My Software,Update — Didier Stevens @ 0:00

This new version of base64dump brings 2 new features:

  • support for ASCII85 encoding: a85
  • selecting of the largest result: -s L
base64dump_V0_0_17.zip (https)
MD5: B535A0B9E73D068380078FC5006756E8
SHA256: DDC67BEBC5C3407213673C0228E84796E6816294A029997542BA7DD9AF659C4E
« Previous PageNext Page »

Blog at WordPress.com.