Description
I sent my secret flag over the wires, but the bytes got all mixed up! Recover the flag from the pcapng.
Setup
Download capture.pcapng from the challenge page.
Install Wireshark and Python libraries: pip install dpkt scapy
Solution
- Step 1Examine the capture in WiresharkOpen capture.pcapng in Wireshark. The packets are UDP. Each packet carries a portion of XOR-encrypted data whose bytes have been shuffled using a seeded random number generator.
Learn more
pcapng (Packet Capture Next Generation) is the standard file format for network packet captures, used by Wireshark, tcpdump, and most network analysis tools. It stores raw packet data including headers and payloads for every packet captured during a network session. pcapng is the successor to the older pcap format, adding features like multiple interfaces, per-packet timestamps, and comments.
UDP (User Datagram Protocol) is a connectionless transport protocol -- unlike TCP, it has no handshaking, acknowledgment, or guaranteed ordering. Each UDP datagram is independent: they may arrive out of order or not at all. This is relevant to the challenge because the bytes are shuffled across packets, and the correct order must be reconstructed using the shuffle algorithm rather than packet sequence numbers.
Wireshark's Protocol Hierarchy Statistics (
Statistics → Protocol Hierarchy) gives an overview of what protocols are in the capture. Following a UDP stream (Analyze → Follow → UDP Stream) shows all related packets together. Wireshark can also export packet payload bytes for further analysis with external tools. - Step 2Extract the random seed from the first packetThe first packet contains timestamp or seed information used to initialize the shuffle. Extract the packet data with Python using dpkt or scapy.python3 -c " import dpkt, socket with open('capture.pcapng','rb') as f: cap = dpkt.pcapng.Reader(f) for ts, buf in cap: eth = dpkt.ethernet.Ethernet(buf) print(eth.data.data.data[:16].hex()) break "
Learn more
dpkt is a Python library for parsing raw network packet data. It understands the Ethernet frame structure (
dpkt.ethernet.Ethernet), which contains an IP packet (.data), which contains a UDP datagram (.data), which contains the application payload (.data). Each layer is accessed via the.dataattribute, following the network stack from layer 2 (Ethernet) down to the application payload.The seed is transmitted in the first packet so that the receiver can reconstruct the shuffle sequence. This is a critical design flaw: a symmetric key (the seed) is transmitted in the clear alongside the encrypted data. Anyone who captures the traffic can reconstruct the shuffle and decrypt the data -- the encryption provides no security if the key is broadcast openly.
scapy is an alternative Python packet library that is more user-friendly for interactive use but slower for bulk processing.
rdpcap('file.pcapng')reads all packets, and individual layers are accessed via indexing:pkt[UDP].payloadfor UDP payload data. Both libraries are standard tools in network forensics. - Step 3Reverse the shuffleUse the recovered seed to reconstruct the same random shuffle sequence. XOR with the known key to recover the ordered bytes.python3 solve.py
Learn more
Python's random module uses a Mersenne Twister PRNG (pseudorandom number generator). Given the same seed,
random.seed(n)followed by the same sequence of random calls produces identical output every time -- it is entirely deterministic and reproducible. The sender seeded the PRNG with the transmitted value, generated a shuffle permutation, and applied it to the bytes. The receiver (and attacker) repeat this exactly to reconstruct the permutation and reverse it.XOR decryption is the inverse of XOR encryption:
plaintext XOR key = ciphertext, sociphertext XOR key = plaintext. If the key is known (transmitted or guessable), XOR-encrypted data is trivially decrypted by XORing again with the same key. The combination of XOR and shuffle in this challenge adds two layers of obfuscation, but both are reversible once the seed is known.The solve script must: (1) collect payload bytes from all packets in order, (2) seed Python's random module with the extracted seed, (3) generate the same shuffle indices the sender used, (4) apply the inverse permutation, and (5) XOR with the key. The result is the original PNG image bytes containing the flag.
- Step 4View the resulting PNGThe decrypted and un-shuffled bytes form a valid PNG image. Save it and open it -- the flag is rendered visually inside the image.python3 -c " with open('flag.png','wb') as f: f.write(decrypted_bytes) "eog flag.png
Learn more
Writing the recovered bytes to a file and running
file flag.pngconfirms whether the recovery was successful -- a valid PNG starts with the bytes89 50 4E 47 0D 0A 1A 0A(the PNG magic signature). If the output is invalid, the seed extraction or shuffle reversal had an error.This challenge combines several disciplines: network forensics (pcap analysis), cryptography (XOR), randomness (PRNG seeding), and steganography (flag in image). Multi-discipline challenges are common at higher CTF difficulty levels -- the skills required span tools and concepts from different security domains. Building fluency in each domain separately makes combined challenges approachable.
Flag
picoCTF{...}
When randomization is seeded with a value transmitted in the data itself (such as a packet timestamp), the shuffle is fully deterministic and reversible by anyone who captures the seed.