Description
A "digital ghost" exfiltrated data through a small capture file. Sort the packets chronologically, reassemble the attacker's Base64 blobs, and decode them to reveal the stolen message.
Grab the PCAP and run capinfos to see capture duration and packet count.
Open it in Wireshark (or pull TCP payloads with tshark). Sort by time so you can read the exfiltration stream in order.
wget https://challenge-files.picoctf.net/c_verbal_sleep/4d25aca04e2409ba0d917d8ed27d49c6fb616ff9603fa3926712cce623a3d7f5/myNetworkTraffic.pcapcapinfos myNetworkTraffic.pcaptshark -r myNetworkTraffic.pcap -Y tcp -T fields -e frame.number -e frame.time_epoch -e tcp.payloadSolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1
Identify the suspicious payloadsObservationI noticed the TCP payload fields in the capture contained tiny ASCII strings ending with '==' padding, which is a hallmark of Base64 encoding and suggested the attacker had fragmented and encoded the exfiltrated data before transmitting it over TCP.The capture contains TCP segments whose data fields are tiny Base64 strings ending with==padding. Print frame numbers + payloads with tshark; the packets are captured out of chronological order, so you must sort by the epoch timestamp column to reconstruct the correct sequence. The sorted order (by frame.time_epoch ascending) is: packets 9, 21, 17, 15, 20, 13, 8. Note: zsteg is for image steganography, not pcaps - do not reach for it here.bash# Print frame number, timestamp, payload for the chunked TCP flow: tshark -r myNetworkTraffic.pcap -Y 'tcp.port == <PORT>' \ -T fields -e frame.number -e frame.time_epoch -e tcp.payload # Packets are out of chronological order; sort the output by the timestamp column to get the correct sequence.Expected output
picoCTF{1t_w4snt_th4t_34sy_tbh_4r_...}What didn't work first
Tried: Sort the tshark output by frame.number instead of frame.time_epoch to get the exfiltration sequence.
Frame numbers reflect capture order on disk, not the chronological order of transmission. In this challenge the packets were captured out of order, so sorting by frame.number produces a jumbled sequence and the concatenated Base64 decodes to garbage. The correct field to sort on is frame.time_epoch (ascending), which recovers the actual send order: 9, 21, 17, 15, 20, 13, 8.
Tried: Use tshark without a display filter, printing all TCP payloads, to locate the Base64 chunks.
Without a port filter the output includes TCP handshake and ACK packets that carry empty payloads, producing blank lines that break the concatenation and make it hard to spot which frames hold the actual data. Adding -Y 'tcp.payload' (or filtering by the specific destination port) narrows the output to only the frames that carry payload bytes.
Learn more
PCAP (Packet Capture) files store raw network traffic recorded by tools like
tcpdump, Wireshark, or network taps. The PCAP format stores each packet with a precise timestamp, enabling chronological reconstruction of conversations. PCAP analysis is a core skill in network forensics, incident response, and network-based CTF challenges.Data exfiltration via TCP payload is one of the simplest covert channel techniques. An attacker who has compromised a host can embed stolen data in the payloads of outbound TCP connections, sometimes disguised as legitimate traffic. Fragmenting the data into small chunks (as here, with individual Base64 segments) mimics the behavior of keep-alive packets or protocol handshakes and can evade simple size-based anomaly detection.
Real-world exfiltration is often more sophisticated: data can be hidden in DNS query names (DNS tunneling), ICMP echo request payloads, HTTP User-Agent headers, or timing intervals between packets (covert timing channels). Tools like dnscat2 and iodine automate DNS-based exfiltration. Network detection tools like Zeek and Suricata include signatures for many of these patterns.
Step 2
Concatenate in order and decodeObservationI noticed each Base64 chunk decoded individually to only a fragment of the flag (for example, 'cGljb0NURg==' decodes to 'picoCTF'), which suggested all chunks needed to be concatenated into a single Base64 string first and then decoded in one pass to recover the complete flag.Canonical workflow here is manual extraction with tshark, because it makes the ordering explicit. Copy thecGljb0NURg==,ezF0X3c0cw==, ...fQ==strings in chronological order, concatenate, and pipe throughbase64 -d. The output starts withpicoCTF{; if it doesn't, the packet order is wrong, so re-sort and try again. Wireshark's Follow TCP Stream is the GUI alternate - same data, just reassembled for you.bash# Concatenate the chunks (no newlines) and decode:bashprintf '%s' 'cGljb0NURg==ezF0X3c0cw==bnRfdGg0dA==XzM0c3lfdA==YmhfNHJfOA==ZTEwZTgzOQ==fQ==' | base64 -dbash# One segment per line works too if you prefer:bashprintf 'cGljb0NURg==\nezF0X3c0cw==\nbnRfdGg0dA==\nXzM0c3lfdA==\nYmhfNHJfOA==\nZTEwZTgzOQ==\nfQ==\n' | base64 -dbash# Expected: a string starting with picoCTF{What didn't work first
Tried: Pipe the raw hex payload bytes directly from tshark into base64 -d without converting them to ASCII first.
tshark -e tcp.payload outputs the payload as a hex string (e.g. '6347386a6230...'), not as the Base64 text the attacker sent. Piping that hex string into base64 -d decodes the hex digits as if they were Base64 characters, producing binary garbage. You must first convert the hex to the ASCII characters it represents (e.g. with xxd -r -p or python3 bytes.fromhex) to recover the Base64 string, then decode that.
Tried: Decode each Base64 chunk separately and concatenate the decoded fragments to build the flag.
Each individual chunk decodes to only a fragment of the flag (e.g. 'cGljb0NURg==' decodes to 'picoCTF', '==fQ==' decodes to '}'), so decoding them separately gives pieces that are missing the boundaries between fragments. The correct approach concatenates all the Base64 strings first into one continuous string, then performs a single base64 -d on the whole thing to recover the complete flag without gaps or repeated padding characters.
Learn more
Packet ordering matters critically in network forensics. PCAP files record packets in the order they were captured, which usually reflects network arrival order, but TCP guarantees in-order delivery from the application's perspective. When packets are out of capture order (due to network reordering or parallel paths), you must re-sort by TCP sequence number, not by capture time, to reconstruct the byte stream correctly.
Wireshark's Follow TCP Stream feature (right-click a packet, Follow, TCP Stream) automatically reassembles a complete TCP conversation in sequence-number order, handles retransmissions, and presents the payload as continuous text or hex. This is usually the fastest way to extract application-layer data from a PCAP, and it is the recommended alternate workflow if the manual
tsharkapproach above feels fiddly. For UDP-based challenges, Follow UDP Stream works similarly but without reassembly guarantees.Base64 is an encoding scheme, not encryption. It maps arbitrary binary data to a 64-character alphabet (
A-Z,a-z,0-9,+,/) plus=padding, and increases size by about 33%. The fact that the attacker used Base64 rather than encryption reveals a fundamental mistake: encoding is reversible by anyone without a key. Sophisticated exfiltration would encrypt the data with a key the attacker controls before encoding, which is exactly what command-and-control frameworks like Cobalt Strike and Metasploit do by default. CyberChef (the GCHQ-developed web tool) is exceptionally useful for chaining decoders if you need more than one transformation in sequence.
Interactive tools
- File Magic IdentifierIdentify file types from magic numbers. Paste hex bytes or drop a file to detect PNG, JPEG, ZIP, PDF, ELF, PCAP, SQLite, and dozens of other formats.
- Image Metadata ViewerRead EXIF, XMP, JPEG comments, and PNG tEXt / iTXt / zTXt chunks from images entirely in the browser. Highlights flag-like values.
Flag
Reveal flag
picoCTF{1t_w4snt_th4t_34sy_tbh_4r_8e...}
If you use Wireshark, the Follow TCP Stream view also displays the Base64 segments in order once you pick the first packet.