TryHackMeEasy

Hacker Holidays — Day 4: Packed Light

A PCAP shows a covert channel exfiltrating one byte per HTTP request inside a Cookie header — base64 plus a single-byte XOR, broken instantly with a known-plaintext crib on the flag format.

Grey hooded mascot holding a laptop with a wifi signal icon

Event: Hacker Holidays — The Byte Lotus Hotel · Day 4 · Forensics (Network / PCAP) File: traffic.pcapng

The Setup

A short capture from the guest network. Something beacons out to an odd :8080 host “every second like clockwork,” and the data is dribbled out one byte at a time (“packed light”), base64-encoded and XOR-obscured. Objective: find the covert channel, reassemble the bytes, decode the flag.

Covert channel: data exfiltrated inside an HTTP Cookie header, one byte per request.

Step 1 — Overview

capinfos traffic.pcapng          # 1,348 pkts, 41s capture
tshark -r traffic.pcapng -q -z io,phs

The protocol hierarchy shows only 62 HTTP frames in a sea of TLS/QUIC/SSDP noise — the plaintext HTTP is where to look.

Step 2 — Isolate the Beacon

tshark -r traffic.pcapng -Y "http.request && tcp.port==8080" \
  -T fields -e frame.time_relative -e http.request.uri -e http.host
2.60    /temp/updates.py    byte-lotus-hotel.thm:8080
15.95   /                   byte-lotus-hotel.thm:8080
16.07   /                   byte-lotus-hotel.thm:8080
...      (30 × GET / on a tight loop)
  • The first request pulls /temp/updates.py — the exfil script fetching itself.
  • Then a steady loop of GET / to the same host. Regular, low-volume — the “quiet little errand.”

Step 3 — Find Where the Data Hides

Dump full headers of those requests:

tshark -r traffic.pcapng -Y "http.request && tcp.port==8080" -O http

Two tells stand out on every beacon:

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) ByteLotusClient/1.1
Cookie: hotel_sess_state=HA==
  • The bogus ByteLotusClient/1.1 User-Agent = @0xMia’s “not a real app.”
  • hotel_sess_state changes every request: HA==, AA==, BQ==, Mw==, Hg==, ew== … Each is base64 of a single byte. That’s the smuggled payload — one char per beacon.

Step 4 — Reassemble + Decode

Base64-decoding the cookies gives non-printable bytes → 1C 00 05 33 1E 7B .... That points to a single-byte XOR. Use the known flag prefix THM{ as a crib:

cipher byteplaintextkey
0x1CT (0x54)0x48
0x00H (0x48)0x48
0x05M (0x4D)0x48
0x33{ (0x7B)0x48

Key is constant = 0x48 ('H'). Applying it to all 30 bytes recovers the flag.

One-liner

tshark -r traffic.pcapng -Y 'http.cookie contains "hotel_sess_state"' -T fields -e http.cookie \
| sed 's/.*hotel_sess_state=//' \
| python3 -c 'import sys,base64; print("".join(chr(base64.b64decode(l.strip())[0]^0x48) for l in sys.stdin))'
THM{redacted}

Takeaways

  • Exfil doesn’t need a weird protocol — it hides in normal-looking HTTP. Here it was a legit-looking Cookie header on a beacon loop; nothing about the packets screamed “malware” except the fake User-Agent and the metronomic timing.
  • Timing is a signal. Perfectly regular, low-byte requests to a single host = beaconing. Sort by frame.time_relative and the pattern jumps out.
  • Layered obfuscation is shallow here: base64 (to survive the header) → single-byte XOR (to hide from a casual grep). A crib on the known flag format breaks the XOR instantly.
  • Detection idea: flag outbound HTTP with non-standard User-Agents + high-regularity intervals + monotonically changing cookies. Blue-team calls this beacon analysis.

Flag

THM{redacted}