Trivial Flag Transfer Protocol picoCTF 2021 Solution

Published: April 2, 2026

Description

Figure out how they are communicating, then find the flag. Download tftp.pcapng.

Download tftp.pcapng.

bash
wget <url>/tftp.pcapng

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1
    Export all TFTP objects from the capture
    Observation
    I noticed the file was named tftp.pcapng, and TFTP (Trivial File Transfer Protocol) transmits files in plaintext over UDP, which suggested that every transferred file would be fully recoverable from the capture using Wireshark's Export Objects feature.
    Open tftp.pcapng in Wireshark, then File > Export Objects > TFTP. You'll recover instructions.txt, plan, picture1.bmp, picture2.bmp, picture3.bmp, and program.deb.
    bash
    wireshark tftp.pcapng
    What didn't work first

    Tried: Trying to extract files with tcpdump or tshark -r tftp.pcapng -x instead of Wireshark's Export Objects menu

    tshark -x prints raw hex of each packet, not reassembled file payloads. TFTP DATA blocks are split across many UDP frames, so you get fragmented hex dumps rather than complete files. Wireshark's File > Export Objects > TFTP walks the DATA block sequence numbers and reassembles each transfer into a single file automatically.

    Tried: Filtering for HTTP or TCP streams in Wireshark expecting to find transferred files there

    TFTP runs over UDP port 69, not TCP, so TCP stream reassembly finds nothing. The Export Objects menu only works when you select TFTP from the protocol list; the HTTP entry will be empty. Check the Protocol column in the packet list - frames labeled 'TFTP' under UDP confirm the right protocol.

    Learn more

    TFTP packet primer. TFTP runs over UDP/69 with a tiny opcode-driven format:

    • 1 = RRQ (read request): opcode | filename\0 | mode\0
    • 2 = WRQ (write request): same shape as RRQ
    • 3 = DATA: opcode | block# | up to 512 bytes
    • 4 = ACK: opcode | block#
    • 5 = ERROR: opcode | errcode | message\0

    Filename and mode in RRQ/WRQ are NUL-terminated ASCII strings. Because everything is plaintext, Wireshark's Export Objects walks the DATA blocks and reassembles complete files. See Wireshark for CTF for the broader protocol-analysis playbook.

  2. Step 2
    Decode the text files with ROT13
    Observation
    I noticed that instructions.txt and plan contained text with recognizable English word patterns but uniformly shifted letters, which is the hallmark of a letter-substitution cipher and suggested trying ROT13 as the most common 26-letter-alphabet self-inverse shift.
    instructions.txt and plan are ROT13. Decode them to learn the steg tool (steghide) and the passphrase. Look for the passphrase on a clearly-marked line: often the last line of the file or a label like 'password:' or 'passphrase:'.
    bash
    tr 'A-Za-z' 'N-ZA-Mn-za-m' < instructions.txt
    bash
    tr 'A-Za-z' 'N-ZA-Mn-za-m' < plan
    What didn't work first

    Tried: Trying caesar cipher with a different shift (ROT7, ROT18) because the first few words still look garbled

    ROT13 is shift-13 and is its own inverse, so applying it once decodes the message completely. If output still looks garbled, the most common mistake is applying the tr command to the wrong file or misreading the hex-edited filename from the Wireshark export. Re-check the exact filenames produced by Export Objects - they are case-sensitive.

    Tried: Using base64 -d or xxd to decode the text files instead of ROT13

    Base64 output contains only alphanumeric characters plus +/= and has no recognizable English word patterns even when shifted. The exported files here contain recognizable but shifted English words (e.g. 'HFRQ' decodes to 'USED'), which is the signature of a letter-substitution cipher like ROT13, not base64 encoding.

  3. Step 3
    Extract the hidden data from picture3.bmp
    Observation
    I noticed the ROT13-decoded plan explicitly named steghide as the tool and identified picture3.bmp as the carrier with DUEDILIGENCE as the passphrase, which suggested running steghide extract on that specific image to recover the hidden flag.
    Use steghide on picture3.bmp with the recovered passphrase (DUEDILIGENCE in the canonical solve). The output file contains the flag.
    bash
    steghide extract -sf picture3.bmp -p DUEDILIGENCE
    bash
    cat flag.txt

    Expected output

    picoCTF{h1dd3n_1n_pLa1n_51GHT_...}
    What didn't work first

    Tried: Running steghide extract on picture1.bmp or picture2.bmp with the recovered passphrase instead of picture3.bmp

    Steghide will report 'could not extract any data' or a capacity/checksum error on the carrier images that have no embedded payload. Only picture3.bmp contains hidden data. The decoded plan file explicitly directs you to the third image - re-read the ROT13 decoded output carefully to confirm which file is named.

    Tried: Trying zsteg or binwalk on the .bmp files instead of steghide, because those are common stego tools

    zsteg targets PNG and BMP LSB planes but does not understand steghide's format, which modifies pixel color values in the spatial domain and encrypts the payload with AES keyed by the passphrase. zsteg will show random-looking LSB data rather than the plaintext flag. The decoded instructions explicitly name steghide as the tool, so the passphrase-based extraction via steghide -sf is the correct path.

    Learn more

    Steghide hides data inside image and audio carriers by tweaking pixel/sample values; the payload is encrypted with a passphrase. -sf selects the stego file and -p passes the passphrase. See steganography tools for the broader toolkit (zsteg for PNG LSB, binwalk for embedded archives, stegsolve for visual bit planes).

    This challenge chains TFTP recovery, ROT13 decoding, and steghide extraction. Each clue is hidden in the previous step's output, a common multi-stage pattern in forensics CTFs.

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.
  • StegallDrop any file and Stegall runs every applicable steg technique in parallel: LSB sweeps, bit planes, spectrograms, polyglot carving, metadata, whitespace decode, and a 6-layer base/ROT/XOR/zlib cascade. Recursively unpacks results and surfaces flag matches.

Flag

Reveal flag

picoCTF{h1dd3n_1n_pLa1n_51GHT_...}

TFTP transfers files without encryption: export all objects from the capture, decode the ROT13 instructions to recover the steghide passphrase, and pull the flag out of picture3.bmp.

Key takeaway

Multi-stage forensics chains model how real exfiltration works: each layer of obfuscation (a cleartext protocol, a simple cipher, a steganographic carrier) adds friction without providing true security. TFTP exposes every transferred file to any network observer; ROT13 is a transparency illusion, not encryption; and steghide merely hides data rather than protecting it cryptographically if the passphrase is recoverable. Recognizing that attackers with a full packet capture can peel every layer offline is why defense-in-depth requires actual encryption at every hop, not just obscurity at one.

Related reading

Want more picoCTF 2021 writeups?

Useful tools for Forensics

What to try next