Post

Decrypting Cobalt Strike traffic - Kalmar CTF 2023 lleHSyniT! (Forensics) writeup

Introduction

This writeup presents the intended solution for lleHSniT!, one of the forensics challenges of Kalmar CTF 2023.

Challenge Description

One of our users here at StupidCorp ran a malicious binary they were sent over an email. We made a process dump, and dumped the network logs. We think it is TinySHell, can you please help figuring out what happened?

Writeup

To solve this challenge we received 2 files:

  • capture.pcap, a pcap network traffic capture;
  • proc.dmp, a process dump file.

Let’s start by analyzing the pcap file in wireshark. After checking the Protocol Hierarchy (Statistics -> Protocol Hierarchy), we can see the several protocols present in the capture. Protocol hierarchy statistics Protocol hierarchy statistics It contains some HTTP packets that might worth taking a closer look. Filtering HTTP packets in wireshark we can see one GET request made to /TnHS, some GET requests made to /g.pixel and some POST requests made to /submit.php?id=<ID>. wireshark traffic after http filter Wireshark traffic after http filter HTTP stream HTTP stream The data in the body of the requests appears to be encrypted. Following the TCP/HTTP stream of one of the HTTP requests, the HOST header set to Definitely not evil gives us an hint that requests are being sent over to a malicious ‘evil’ server. It seems that some kind of C2 traffic is going on. With the tshark command:

1
tshark -r capture.pcap -Y 'http' -Tfields -e frame.time -e http.host

it is noticeable the periodicity of the timestamps in the HTTP captured packets as we can see in the tshark output snippet below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
Feb 23, 2023 07:15:34.007527000 WET     Definitely not evil
Feb 23, 2023 07:15:34.019012000 WET
Feb 23, 2023 07:15:44.022331000 WET     Definitely not evil
Feb 23, 2023 07:15:44.023703000 WET
Feb 23, 2023 07:15:54.037950000 WET     Definitely not evil
Feb 23, 2023 07:15:54.050182000 WET
Feb 23, 2023 07:15:54.052943000 WET     Definitely not evil
Feb 23, 2023 07:15:54.053822000 WET
Feb 23, 2023 07:16:04.057436000 WET     Definitely not evil
Feb 23, 2023 07:16:04.058878000 WET
Feb 23, 2023 07:16:14.064167000 WET     Definitely not evil
Feb 23, 2023 07:16:14.076477000 WET
Feb 23, 2023 07:16:24.084827000 WET     Definitely not evil
Feb 23, 2023 07:16:24.097833000 WET
Feb 23, 2023 07:16:24.100541000 WET     Definitely not evil
Feb 23, 2023 07:16:24.101479000 WET
Feb 23, 2023 07:16:34.106975000 WET     Definitely not evil
Feb 23, 2023 07:16:34.405389000 WET
Feb 23, 2023 07:16:44.421228000 WET     Definitely not evil
Feb 23, 2023 07:16:44.422614000 WET
...

By now we have some indicators that some kind of specialized tool is probably being used to compromise the system and the network. A common one actively (ab)used by a wide range of threat actors from ransomware operators to espionage-focused Advanced Persistent Threats is Cobalt Strike (CS). Cobalt Strike’s default malware payload are called beacons and are used to create a connection to the team server. Active callback sessions from a target are also called beacons.

The communication between a Cobalt Strike beacon (client) and a Cobalt Strike team server (C2) is encrypted with AES. The AES key is generated by the client beacon and sent to the C2 server using an encrypted metadata blob (by default a cookie). This metadata is encrypted with RSA encryption algorithm where the beacon has the public key of the C2 server and the private key is stored in the C2 server itself.

cobalt strike traffic Cobalt Strike traffic

So now that we know Cobalt Strike beacons communicate over HTTP and encrypt their data with AES, we need to find a way to extract the keys (AES and HMAC) from the memory dump file proc.dmp of the cobalt strike beacon. If we can successfully get these cryptographic keys we can decrypt the data. Fortunely, there are tools to make this process easier as we will see in the further analysis.

Usually in CS traffic it is possible to identify the default malware payload beacon called the stager shellcode which consists of a couple of hundred bytes, and does some basic checks and only then queries the configured C2 for the fully featured backdoor. We can search for signs of this stager shellcode by applying the filter http.request.uri matches "/....$" in wireshark.

Searching for the stager shellcode in wireshark Searching for the stager shellcode in wireshark

We get one result, the request made to the endpoint /TnHS (apparently) is just an endpoint consisted of 4 random alphanumeric characters. However they are not completely random: their 8-bit checksum is a member of a small set of constants.Knowing this, the path TnHS present in the pcap file can be confirmed that it is a valid path to download a 64-bit full beacon (CS x64) after running the metatool (from Didier Stevens Beta Suite) which can be used to analyse suspicious URLs to find relation to exploitation tools such as Cobalt Strike or Metasploit by calculating the checksum of URLs.

Checksum calculation using metatool Checksum calculation with metatool

To start the analysis of the encrypted traffic we start by extracting the beacon download data of the pcap capture file:

  1. Filter by http traffic;
  2. Go to File->Export Objects->http;
  3. Save packet number 48.

Extract download beacon data Extract beacon download data

Using this beacon data and the tool 1768.py we can get some relevant information about the C2 traffic in our capture.

1768.py output 1768.py output

From the tool 1768.py output above, the beacon communicates with the IP address 192.168.116[.]128 (option 0x0008) on port 80 (option 0x0002). GET requests use path /g.pixel (option 0x0008), and POST requests use path /submit.php (option 0x000a) At the bottom we also get info about a guess of the Cobalt Strike version (4.3). We also get a lot of other information like the payload type (windows-beacon_http-reverse_http), public key, Host Header, etc. Even knowing that the output didn’t give us a known RSA private key, we have a process memory dump that we can leverage to decrypt the CS traffic using the approach documented in this blog post written by Didier Stevens from NVISO Labs.

The tool cs-extract-key (also from DidierStevensSuite) looks in the dumped process memory to find valid AES and HMAC keys using different techniques depending on the CS version. An explanation of these techniques can be found here. To efectively use this tool we need a sample of encrypted data of one of the POST requests.

To grab this data in wireshark we can apply the filter http.request.method==POST and get the value in the Data section in the packet details pane or we can use a tshark command like:

1
tshark -r capture.pcap -Y "http.request.method==POST" -Tfields -e data

to read the capture file, filter POST requests and output their data. Either way, we should be able to get a sample of encrypted data. I chose the following encrypted data sample to work with:

1
00000090bc42642121ebc0a784136ca4a86ef41d66fde0358f119ca6c246fac05765288ab7e21c86418f55052815f1da9521ea5f85253b7a657d37857bfbd2cf9f7ddcd16c063d81f1becfb6faef5df286db10b30d020f30c120b30f8f7beae361ddc8cbf5b36063c60ab5218f5cc0b93c089048eacde1dbbca3877a1b093dd076370de61250f922c396cdf4fcda4c6409a53971

With this data we can now run the tool and extract the cryptographic keys from the Cobalt Strike beacon process dump with:

1
./cs-extract-key.py -c <ENCRYPTED_DATA> proc.dmp

cs-extract-key.py output cs-extract-key.py output

From the output above, we get the HMAC key 24a0f5e701439f460d52ef4810f592f3 and the AES key 3c4267894c6fee7a5aaa4d13e0289051. Now it is possible to easily decrypt the traffic with the help of the tool cs parse traffic, also from DidierStevensSuite. The extracted keys must be specified after the flag -k in the format HMACkey:AESkey resulting in the command:

1
./cs-parse-traffic.py --extract capture.pcap -k 24a0f5e701439f460d52ef4810f592f3:3c4267894c6fee7a5aaa4d13e0289051

After the tool finishes running, we get some .vir files. Analyzing the cs parse traffic terminal output, packet number 1983 contains the POST request with the data of the file password.txt that was downloaded from the victim computer (image below).

cs-parse-traffic output cs-parse-traffic output

The data of the file password.txt was saved in our directory with the md5 hash value of 61ca2f3dc9212781c983f9e13a99be08 in the file name. Let’s run cat to see the contents of this file.

1
2
3
4
5
6
7
8
$ cat payload-61ca2f3dc9212781c983f9e13a99be08.vir
DO NOT READ!!!
PRIVATE INFORMATION!!!
...
STOP READING!!!!
...
AYY I TOLD YOU NOT TO READ
...

flag Finding the flag at the end of the file

At the end of the file is the password kalmar{My_F4v0r1t3_G4m3_1s_Cobalt_Strike:gL0b4l_0p3r4t0rs} which is the flag needed to solve the challenge.


References

This post is licensed under CC BY 4.0 by the author.