PICOCTF 2026 • FORENSICS • CELLULAR & NETWORK DFIR

Rogue Tower: Cellular IMSI Catcher & Exfiltration Analysis

By Abdo•6 min read•PicoCTF 2026
EVIDENCE PCAProgue_tower.pcap
ROGUE TOWERCELLID: 92058
VICTIM IMSI310410308555787
RECOVERED FLAGpicoCTF{r0gu3...}
Cellular IMSI Catcher & Rogue Base Station Forensics
FIGURE 1: Cellular RF Interception & Packet DissectionSDR Beacon Triage & KPA Decryption
Challenge Scenario

An unauthorized cellular base station (IMSI Catcher / Stingray) was detected operating in the area, spoofing mobile network beacons to lure devices away from commercial carrier towers. Our objective is to analyze the captured packet trace (rogue_tower.pcap), identify the rogue tower, trace the compromised handset, and reconstruct the exfiltrated flag.

01. Spotting the Rogue Base Station

Cellular base stations broadcast identity beacons so mobile devices can negotiate connections. In the PCAP, filtering for UDP broadcast traffic on port 55000 displays these advertised towers:

WIRESHARK BEACON DISCOVERY: UDP 55000
Wireshark UDP Tower Beacons
TERMINAL • TSHARK BEACON FILTER
tshark -r rogue_tower.pcap -Y "udp.port == 55000" -T fields -e data.text
// Terminal Output:
CARRIER: Verizon PLMN=310410 CELLID=15606
CARRIER: AT&T PLMN=310410 CELLID=15607
UNAUTHORIZED-TEST-NETWORK PLMN=00101 CELLID=92058

While packets 1 and 2 broadcast legitimate carriers, Frame 14 broadcasts an explicit UNAUTHORIZED-TEST-NETWORK with CELLID=92058.

02. Tracking the Compromised Handset

Next, we filter HTTP registration requests to see which handset attached to the rogue tower by searching for cell identifier 92058:

TERMINAL • IDENTIFY VICTIM BY CELLID
tshark -r rogue_tower.pcap -Y "http.user_agent contains '92058'" -T fields -e ip.src -e http.user_agent
10.100.50.122   MobileDevice/1.0 (IMSI:310410308555787; CELL:92058)

Device 10.100.50.122 connected directly to the rogue cell. Its International Mobile Subscriber Identity is IMSI: 310410308555787.

03. Exfiltration Reconstruction & Stream Reassembly

Following the HTTP connection from 10.100.50.122, we see the endpoint establishing cleartext POST requests to 198.51.100.58:443:

WIRESHARK HTTP STREAM FOLLOW
Wireshark HTTP Stream Exfiltration

Across frames 17 through 22, the payload is transmitted in 6 consecutive POST requests:

Frame 17 (9 B)QFFWWnZjf
Frame 18 (9 B)kxCCFJABm
Frame 19 (9 B)hbBFxUakE
Frame 20 (9 B)FQAtFb1xX
Frame 21 (9 B)VgEHAAQBR
Frame 22 (3 B)Q==
// Reassembled Base64 String:
QFFWWnZjfkxCCFJABmhbBFxUakEFQAtFb1xXVgEHAAQBRQ==

04. Known Plaintext Attack (KPA) & XOR Decryption

Base64 decoding produces 34 raw bytes of ciphertext. Since flags adhere to the standard prefix picoCTF{, we perform a Known Plaintext Attack to calculate the keystream:

Ciphertext[0..7] ⊕ "picoCTF{" = Keystream
0x40 ⊕ 'p' (0x70) = '0'
0x51 ⊕ 'i' (0x69) = '8'
0x56 ⊕ 'c' (0x63) = '5'
0x5A ⊕ 'o' (0x6F) = '5'
0x76 ⊕ 'C' (0x43) = '5'
0x63 ⊕ 'T' (0x54) = '7'
0x7E ⊕ 'F' (0x46) = '8'
0x4C ⊕ '{' (0x7B) = '7'
Recovered Key: "08555787" (matches last 8 digits of IMSI: 310410308555787)

Option A: Decrypt via Python One-Liner

TERMINAL • PYTHON SOLVER
python -c "import base64; b = base64.b64decode('QFFWWnZjfkxCCFJABmhbBFxUakEFQAtFb1xXVgEHAAQBRQ=='); key = b'08555787'; print(bytes([x ^ key[i % len(key)] for i, x in enumerate(b)]).decode())"

Option B: Decrypt via CyberChef

  1. Paste input: QFFWWnZjfkxCCFJABmhbBFxUakEFQAtFb1xXVgEHAAQBRQ==
  2. Add recipe: From Base64
  3. Add recipe: XOR with Key: 08555787 (Type: UTF8)
OFFICIAL CAPTURED FLAGpicoCTF{r0gu3_c3ll_t0w3r_dbc40831}