Analysis of an Encoded Cobalt Strike Beacon

Published: 2022-09-06
Last Updated: 2022-09-06 07:52:59 UTC
by Didier Stevens (Version: 1)
0 comment(s)

I also created a video for this diary entry.

Someone reached out to me for the analysis of a Cobalt Strike beacon. This is the sample.

My tool 1768.py (a tool to analyse Cobalt Strike beacons) isn't able to find the configuration:

When something like this happens, I always try option -r. Option -r is raw mode: by default, 1768.py analyses the relevant sections of a PE file, but in raw mode, it takes a look at the complete file.

But this too doesn't work.

What you can do in a case like this, is execute the sample inside a sandbox, make a process memory dump of it, and then have 1768.py analyse the process memory dump. This often works for obfuscated/packed samples.

But first, I took a look at the PE file with my tool pecheck.py, to see if I could recognize anything that my tool didn't catch.

And there is an overlay (data appended to the end of the PE file). This overlay has a high entropy, and it's 256 KB and represents more than 90% of the total size of the PE file.

Let's take a look at the sections of the PE file to confirm this:

These are indeed all small sections, the largest is 10 KB. So that's too small to contain a stageless Cobalt Strike beacon, but the overlay is large enough.

Let's take a look at the overlay:

That doesn't ring a bell to me. But it seems that there is a repeating byte sequence at the end. Let's take a closer look:

Indeed: there is a repeating sequence of 18 bytes here (I highlighted 2 of them in red and green). This often happens when a PE file is XORed with a key: the end of a PE file is often a series of NUL bytes (0x00), and thus it reveals the XOR key.

I did recover the XOR key with trial-and-error, but I'm not going to explain this here (I do explain it in the video, about halfway). What I did do, is update my tool xor-kpa.py that I use to perform XOR known plaintext attacks. I added a definition for the encoded public key header found in a Cobalt Strike configuration: cs-key-dot.

Let's try that:

And indeed, a key was found, and it's very likely a good key, because 15 extra bytes where found. This means that a repetition of the key found 15 extra bytes matching the cs-key-dot signature.

I now use option -d to let xor-kpa.py decode the payload with the XOR key that was listed as last (thus with the highest probability of being correct), and I feed this output into 1768.py:

And now we have recovered the configuration.

 

Didier Stevens
Senior handler
Microsoft MVP
blog.DidierStevens.com

Keywords: cobalt strike 1768
0 comment(s)

Comments


Diary Archives