Skip to main content

Rogue Tower picoCTF 2026 Solution

Analyze captured network traffic to identify a rogue cell tower and recover data that was secretly exfiltrated.

Published: March 20, 2026Updated: August 13, 2026

Description

A suspicious cell tower has been detected. Despite the cellular framing, the capture is ordinary HTTP traffic: a compromised handset beacons to a rogue 'tower' over HTTP, leaking its IMSI in a User-Agent header and exfiltrating the flag as base64 in the request bodies. The flag is XOR-encrypted with a key derived from that IMSI, recovered with a known-plaintext attack.

Open the PCAP in Wireshark. Filter on UDP first: look for a broadcast packet advertising an unauthorized test network. That packet names the rogue tower's cell ID.

Once you know the rogue cell ID, filter on http and find the device whose User-Agent shows that same cell ID - confirming it connected to the rogue tower.

Follow the HTTP conversation between the victim device and the rogue tower.

bash
tshark -r rogue_tower.pcap -Y http -T fields -e http.host -e http.user_agent -e http.request.uri
bash
wireshark rogue_tower.pcap

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1Pull the IMSI from the HTTP User-Agent
    Observation
    The capture is plain HTTP, and the IMSI rides in a User-Agent header. Filter on that rather than any GSM or NAS layer to get the device identity and the key seed.
    Filter on http and read the victim's requests. The device identifies itself in a User-Agent like 'MobileDevice/1.0 (IMSI:310410187936156; CELL:91043)'. Save that IMSI; the last 8 digits are the XOR key.
    bash
    tshark -r rogue_tower.pcap -Y 'http.user_agent contains "IMSI"' -T fields -e http.user_agent
    bash
    # -> MobileDevice/1.0 (IMSI:310410187936156; CELL:91043)

    Expected output

    MobileDevice/1.0 (IMSI:310410187936156; CELL:91043)
    What didn't work first

    Tried: Filtering on GSMTAP or UDP layers looking for NAS or MCC/MNC fields to extract the IMSI from real cellular signaling

    The capture has no GSMTAP encapsulation or GSM radio frames. Wireshark shows no NAS dissector output because the traffic is plain HTTP. The IMSI only appears as a literal string inside the HTTP User-Agent header, so any cellular-layer filter returns zero packets.

    Tried: Using tshark with -e frame.coloring_rule.name or -e wlan.ta to find the rogue cell identity before switching to http filters

    The pcap contains no 802.11 or radio-layer frames, so those fields are empty. The rogue tower's cell ID (CELL:91043) appears only inside the User-Agent string of HTTP requests, not in any packet metadata. The correct approach is to filter on http.user_agent directly.

    Learn more

    Do not chase real cellular signaling. The challenge is dressed up as an IMSI-catcher scenario, but the capture is plain HTTP. There is no GSMTAP, no NAS, no MCC/MNC to filter on. The only cellular artifact is the IMSI string the malware embeds in its User-Agent, which is both the device fingerprint and the seed of the decryption key.

  2. Step 2Reassemble the base64 exfil from the request bodies
    Observation
    The tower receives several POST requests, and each body ends in base64 padding. The flag left in chunks, so concatenate them in request order before decoding.
    The victim sends several HTTP POSTs to the rogue tower, each body carrying a base64 segment (the trailing == is the tell). Follow the HTTP streams and concatenate the segments in request order into one base64 blob.
    bash
    tshark -r rogue_tower.pcap -Y 'http.request.method == "POST"' -T fields -e http.file_data
    bash
    # concatenate the base64 chunks in order
    What didn't work first

    Tried: Base64-decoding the body from a single HTTP POST and treating the result as the complete flag payload

    Each POST body carries one segment. Decode a single chunk and you get a short binary fragment that decrypts to nothing recognizable. Follow every stream and join the segments in request order first.

    Tried: Using tshark -e http.response.body instead of http.file_data to extract the POST contents

    The exfiltrated data is in the request bodies sent by the victim, not in server responses. The field http.file_data captures request body bytes for POST packets. Using http.response.body yields the server's (empty or irrelevant) reply and misses the base64 payload entirely.

    Learn more

    Why base64 then XOR. Naively base64-decoding the blob yields binary garbage, because the plaintext was XOR-encrypted before encoding. The base64 is just transport. You need the key before the bytes mean anything, which is what the next step recovers.

  3. Step 3XOR-decrypt with the IMSI tail (known-plaintext check)
    Observation
    Decoding the reassembled blob gives binary garbage, and the challenge says it is XOR-encrypted with a key from the IMSI. XOR the first bytes against the known picoCTF{ prefix and the right IMSI substring falls out.
    First, try the full IMSI (310410187936156) as the XOR key directly - it produces output but no recognizable flag. Next, apply known-plaintext: XOR the first 8 ciphertext bytes against 'picoCTF' to extract the actual repeating key bytes. Observe that those bytes match the last 8 digits of the IMSI (87936156). Finally, use that derived key to decrypt the full blob. CyberChef: From Base64 -> XOR(87936156, UTF8).
    python
    python3 - <<'PY'
    import base64
    blob = base64.b64decode("<concatenated base64 from the POST bodies>")
    key  = b"87936156"        # last 8 digits of IMSI 310410187936156
    flag = bytes(b ^ key[i % len(key)] for i, b in enumerate(blob))
    print(flag.decode())      # picoCTF{...}
    PY

    The known-plaintext step is the safety net: if XORing the first 8 ciphertext bytes against picoCTF{ does not give a run of identical digits, you concatenated the base64 chunks in the wrong order or grabbed the wrong IMSI substring.

    What didn't work first

    Tried: Using the full 15-digit IMSI (310410187936156) as the XOR key directly, treating it as a UTF-8 byte string

    All 15 digits produce output with no readable prefix, because the key is only the last 8. The known-plaintext check catches it at once: XOR the first eight ciphertext bytes against the flag prefix and the digits that come back tell you the real key length.

    Tried: Applying XOR in CyberChef with key type set to Hex instead of UTF8 for the 8-digit key

    The key is those digits as ASCII characters, one byte each, not the hex number they spell. Choose Hex mode in CyberChef and it reads the string as two 4-byte integers and produces garbage. Use UTF8 or Latin1 so each digit is one key byte.

    Learn more

    Known-plaintext XOR. For a repeating-key XOR, ciphertext XOR plaintext = key at every position. Knowing any stretch of plaintext (the flag prefix) directly exposes that many key bytes. Here it both recovers and confirms the key derivation (the IMSI tail), so you are not guessing. See Wireshark and PCAP for CTF for the stream-following workflow.

Interactive tools
  • Hex ViewerView text or raw hex bytes as a xxd-style hex dump with byte offset, hex columns, and ASCII sidebar. Highlights printable characters and null bytes.
  • Strings ExtractorPull printable text from any binary, library, or image. ASCII and UTF-16 detection, configurable minimum length, flag-like highlight, no command line needed.

Flag

Reveal flag

picoCTF{r0gu3_c3ll_t0w3r_...}

Not real cellular forensics: the pcap is HTTP. The victim leaks its IMSI in the User-Agent (310410187936156) and exfiltrates the flag as base64 in POST bodies. Concatenate the base64, then XOR with the last 8 IMSI digits (87936156), confirming with the picoCTF{ known plaintext.

Key takeaway

Repeating-key XOR falls apart the moment any stretch of plaintext is known: XOR ciphertext against known plaintext and the key bytes at those positions appear directly. A rigid flag prefix hands you eight characters for free every time. Malware analysis and network forensics start the same way, recovering an XOR key from a known header such as file magic bytes, an HTTP signature, or a protocol prefix.

Related reading

Useful tools for Forensics

Where to go next