Event Horizon
Unearth the secrets beyond the Event Horizon. - by hadrian3689
The following post by 0xb0b is licensed under CC BY 4.0
In this challenge we are provided the following files:
powershell.DMP traffic.pcapng
The attacker was able to find the correct pair of credentials for the email service. What were they? Format: email:password
We scroll down the network traffic until we reach the SMTP traffic. There we are able to spot some brute force happening. Around packet 4665
, we identify a successful login.

We follow the TCP traffic and are able to extract the base64-encoded credentials which lead to a successful login.


What was the body of the email that was sent by the attacker?
We inspect the followed TCP traffic and are able to extract the body of the email sent by the attacker.

What command initiated the malicious script download?
To identify what command initiated the malicous script download we extract the base64 encoded file in the attachment.

We decode the content and on the very end of the script we see the command used to download the malicious file. The malicious file downloaded is radius.ps1
. Next , we look for the download of that file in the PCAP.

What is the initial AES key that is used for decrypting the C2 traffic?
We look for the malicious file download, and spot it on packet no. 4722
:
http://10.0.2.45/radius.ps1

We follow the TCP traffic, and see that the script downloaded contains a base64 encoded payload which also uses IO.Compression.DeflateStream
.

We use CyberChef to decode the blob and apply the Raw Inflate
recipe to reverse the compression.
The blob is actually a ms-dos executeable, which we can identify by the MZ magic bytes.

We save the output of our CyberChef decoding into a file and calculate a md5 hash.

We provide that hash to Virustotal and we see its something malicious that is known in the wild and is somewhat related to Covenant.

In the details section we see its a PE32 executable that uses .NET Libraries.

We see that it is a .NET
assembly. It is possible to decompile and get the information we need via Ghirda, but I was not able to do so, same with the room Chrome
. Since it is a .NET
binary we can make use of decompilers specific fot .NET
binaries like dnSPY.exe,
which allows us to do this very easily
It is probably possible to use dnSpy.exe
via Wine, but this did not work properly on my machine. If you still want to try it, you can do this as follows: WINEPREFIX=$HOME/.<INSERT YOUR PREFIX> wine dnSpy.exe
. The executable can be obtained from the following resource:
If you have not setup Visual Studio Code yet checkout the following resource:
We are using the ILSpy extension on VSCode to decompile the binary
The ILSpy
plugin can be easily installed via the marketplace.

After having the plugin installed hit CTRL+SHIFT+P
and enter ILSpy: Pick assembly from file system
to pick the evidence.exe
. In the Execute Stager Class we are able to spot the key used.

What is the Administrator NTLM hash that the attacker found?
Upon researching about Covenant we immediatly come across the CovenantDecrypter. Which is designed to decrypt the communication data of Covenant traffic. From the decompilation and the results from VirusTotal we can tell it might be a Covenant C2 Agent.
And all the data neceessary to decrypt the Covenant traffic (stage0 POST data and a minidump file of an infected process) is provided by the challenge:
What do you need ?
The data traffic of Covenant is extracted from a network capture and stored in a separate file.
The AES key, which is embedded in the stage 0 binary, employed at the beginning of the communication.
A minidump file of an infected process.
The following quoted section from the CovenantDecryptor repository shows how the Covenant communication is setup.
The Covenant communication initialization consists of 3 stages :
Stage0 :
The infected agent initiates an RSA session by transmitting a public key encrypted using the
SetupAESKey
, which is embedded in a malicious executable. Before sending, it formats the text as described in GruntHTTPStager with the type set to 0.The C2 transfers a
SessionKey
, encrypted with the RSA public key, for subsequent communication.Stage1 :
The infected agent employs the
SetupAESKey
to decrypt the message, and then leverages the RSA private key to decrypt theSessionKey
. Afterwards, it encrypts 4 randomly generated bytes with theSessionKey
and transmits them. Before sending, it formats the text as described in GruntHTTPStagerwith the type set to 1.The C2 decrypts the 4 bytes using the
SessionKey
, appends 4 additional randomly generated bytes and transfers the resulting 8 bytes data to the infected agent.Stage2 :
The infected agent decrypts the 8 bytes with the
SessionKey
. Subsequently, it checks if the first 4 bytes match the data it had previously transmitted, and proceeds transfer the last 4 bytes back to the C2. Before sending, it formats the text as described in GruntHTTPStager with the type set to 2.The C2 decrypts the 4 bytes and verifies if they correspond to those it had transmitted earlier.
Once verification is complete, data can be exchanged.
CovenantDecryptor is composed of two utilities. The
extract_privatekey
script retrieves the p and q primes from a minidump file to construct an RSA private key by employing the public modulus. Thedecrypt_covenant_traffic
script consists of 3 commandsmodulus
,key
anddecrypt
. The first command extracts the modulus from Covenant communication, while the second recovers the AES key used for encrypting data traffic. Lastly, the third command decrypts the traffic.
Next, we follow the steps shown in the repository to decrypt the communication of the C2.
But first we need to extract the Stage0 POST data. We find the Stage0 POST request which starts with packet no. 4742
:

We follow the HTTP stream, and save the content to a file.


Next, we follow the steps shown in the repository.
Extract the modulus from the stage 0 request of an infected host:
python3 CovenantDecryptor/decrypt_covenant_traffic.py modulus -i traffic.txt -k "REDACTED" -t base64
Unfortuntely it fails, but trying only the POST data manually it works.

So for the workaround we use tshark to only extract the POST data from the traffic and work with that from now on.
tshark -r traffic.pcapng -Y "http.request.method == POST" -T fields -e http.file_data > post_data.txt

We run the command again against the post_data.txt
and are able to extract the modulus this time.
python3 CovenantDecryptor/decrypt_covenant_traffic.py modulus -i post_data.txt -k "REDACTED" -t base64

Retrieve the RSA private key from a minidump file of an infected Covenant process:
Next, we extract the private key from the process dump using the modulus.
python3 CovenantDecryptor/extract_privatekey.py -i powershell.DMP -m $(cat mod.txt) -o ./

Recover the SessionKey
from the stage 0 response of Covenant C2, which is employed to encrypt network traffic:
SessionKey
from the stage 0 response of Covenant C2, which is employed to encrypt network traffic:Then, we recover the SessionKey
from the stage 0 response of Covenant C2, which is employed to encrypt network traffic:
python3 CovenantDecryptor/decrypt_covenant_traffic.py key -i post_data.txt --key "REDACTED" -t base64 -r privkey1.pem -s 1
But it errors for some reason.

We just need the response from stage0 which is on packet 4745:

We copy the response to a file called response.txt
, and execute the following command to retrieve the AES key.
python3 CovenantDecryptor/decrypt_covenant_traffic.py key -i response.txt --key "REDACTED" -t base64 -r privkey1.pem

Decrypt the Covenant communication:
To decrypt the Covenant communication we use the last command from the instruction and use our post_data.txt
file again. We have now decrypted the traffic and are able to spot the ntlm hash.
python3 CovenantDecryptor/decrypt_covenant_traffic.py decrypt -i post_data.txt -k "REDACTED AES KEY" -t hex

What is the flag?
From our previous decryption we noticed that message 8 contains a big chunk of base64 encoded data followed by another one. We use CyberChef to decode it and see that it is actually an image by the magic bytes.

Next, we render that image using CyberChaef and see that it is a capture of the desktop of the machine containing the final flag.

Last updated
Was this helpful?