Silent Stream picoCTF 2026 Solution

Published: March 20, 2026

Description

We recovered a suspicious packet capture file that seems to contain a transferred file. The sender was kind enough to also share the script they used to encode and send it. Can you reconstruct the original file? Download the PCAP: packets.pcap and encoding encrypt.py .

Download packets.pcap and encrypt.py.

Open the PCAP in Wireshark and read encrypt.py to understand the encoding scheme.

bash
wireshark packets.pcap &
bash
cat encrypt.py

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1
    Read the encoding script
    Observation
    The challenge provided encrypt.py alongside the PCAP, which indicated that understanding the encoding scheme was the essential first step before any extraction or decoding could succeed.
    Open encrypt.py to understand the encoding scheme. The encoder adds a fixed key of 42 to each byte, modulo 256: encoded = (original + 42) % 256. The encoded bytes were then sent over the network and captured in the PCAP.
    bash
    cat encrypt.py
    Learn more

    This encoding scheme is a Caesar cipher applied to raw bytes rather than letters - also called a modular addition cipher or ROT cipher for bytes. By adding a fixed constant (42) to each byte modulo 256, the original byte values are shifted in the byte value space. Unlike XOR, this operation is not its own inverse: to decode, you subtract (or equivalently, add 256 - 42 = 214) rather than applying the same operation again.

    The key value of 42 is not cryptographically meaningful (it is famously "the answer to life, the universe, and everything" from The Hitchhiker's Guide to the Galaxy), emphasizing that this is purely an encoding scheme, not encryption. Real encryption requires keys that are large, random, and secret. A fixed, known key provides no security - it is purely obfuscation.

    In network forensics, understanding the encoding scheme is the first step before extracting and decoding data. Challenge authors often provide the encoding script to simulate a real-world scenario where an analyst has recovered both the captured traffic and, perhaps through source code review or endpoint forensics, the tool used to generate it.

  2. Step 2
    Find the right TCP stream and extract its payload
    Observation
    I noticed the PCAP could contain multiple TCP conversations, and blindly dumping all packet data would interleave bytes from different streams, producing garbage on decode, so isolating the single stream carrying the transferred file was necessary before extracting any bytes.
    Open the PCAP in Wireshark. Right-click any packet in the TCP stream -> Follow -> TCP Stream. In the dialog that opens, set the 'Show data as' dropdown to 'Raw'. Copy the hex content displayed and save it to a file (e.g. silentstream.hex). This hex string is the encoded payload.
    bash
    # In Wireshark:
    bash
    # 1. Open packets.pcap
    bash
    # 2. Right-click a packet -> Follow -> TCP Stream
    bash
    # 3. Set 'Show data as' to 'Raw'
    bash
    # 4. Copy the hex content and save to silentstream.hex

    Expected output

    decoded.bin: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 400x300, components 3
    What didn't work first

    Tried: Export the entire PCAP payload using tshark -r packets.pcap -T fields -e data > all_data.hex without selecting a specific stream

    This dumps the raw data field from every packet across all streams concatenated together, so the hex output interleaves packets from multiple conversations, including TCP handshake overhead and unrelated streams. The resulting blob decodes to garbage because bytes from different conversations are mixed. The correct approach is to isolate a single TCP stream with 'follow,tcp,raw,N' before extracting bytes.

    Tried: In Wireshark, set 'Show data as' to 'ASCII' instead of 'Raw' before copying the stream content

    ASCII mode replaces non-printable bytes with dots and presents printable bytes as characters, so the copied text is neither valid hex nor the raw binary - it is a lossy display format. Feeding that ASCII dump through xxd -r -p will fail or produce a truncated/corrupted binary. Raw mode is required because it emits the actual hex bytes without any display substitution.

    Learn more

    tshark -z conv,tcp dumps a table of every TCP conversation with packet counts and byte totals on each side. Sort by the bytes column; the largest is your transfer. follow,tcp,raw,N selects stream N (zero-indexed) and outputs hex; the rest of the pipe strips header lines and decodes hex back to raw bytes.

    xxd -r -p decoded. -r means "reverse" (hex back to binary). -p means "plain": read continuous hex without expecting xxd's default format (offset column on the left, ASCII column on the right). Together, they consume a stream of hex digits and emit raw bytes, ignoring whitespace.

    See Wireshark for PCAP CTF for the broader pcap workflow and hex dumps for CTF for everything you can do with xxd.

  3. Step 3
    Reverse the encoding (subtract key 42)
    Observation
    I noticed encrypt.py used (original + 42) % 256 on each byte, which meant the inverse operation, subtracting 42 modulo 256, had to be applied to every extracted byte to recover the original file contents.
    The decoding is the mathematical inverse: original = (encoded - 42) % 256. Apply this to every byte of the extracted stream to recover the original file.
    python
    python3 << 'EOF'
    raw = open("silentstream.hex").read().replace("\n", "").replace(" ", "")
    encoded = bytes.fromhex(raw)
    
    key = 42
    decoded = bytes((b - key) % 256 for b in encoded)
    
    with open("decoded.bin", "wb") as f:
        f.write(decoded)
    
    print(decoded.decode(errors="replace"))
    EOF
    What didn't work first

    Tried: Apply XOR 42 to every byte instead of subtracting 42 modulo 256, reasoning that XOR is the standard byte-level reversible operation

    XOR and modular addition are both reversible, but they are different operations - XOR is its own inverse (apply twice to get back the original), whereas modular addition requires subtraction as the inverse. The encrypt.py script explicitly uses (original + 42) % 256, so decoding with XOR produces different output bytes for any byte value where the XOR result differs from subtraction mod 256, which is most values. The decoded output will be garbled and will not match any recognizable file magic.

    Tried: Use key = 214 and encode with (encoded + 214) % 256 instead of (encoded - 42) % 256

    Adding 214 mod 256 is actually mathematically equivalent to subtracting 42 mod 256 because 256 - 42 = 214, so both expressions produce identical results. This approach works correctly and is not a mistake - it is just an alternate way to express the same inverse operation. However, many solvers get confused here and instead try adding 42 a second time (re-encoding rather than decoding), which shifts bytes further away from the original values.

    Learn more

    The modular math. Decoding is (encoded - 42) % 256. Equivalent: (encoded + 214) % 256, since -42 mod 256 = 214. Python's % always returns a non-negative result for positive moduli, so (0 - 42) % 256 = 214 works without manual wrap. C-style % would return -42 for the same input; use (b - 42 + 256) & 0xFF in those languages.

    The errors="replace" argument to decode() substitutes a replacement character (U+FFFD) for any bytes that are not valid UTF-8. This makes the print safe even when the decoded output is binary. The next step runs file decoded.bin to identify the real format.

  4. Step 4
    Identify the decoded format and read the flag
    Observation
    I noticed the decoded output was a raw binary blob of unknown format, so running the file command on decoded.bin was needed to read the magic bytes and confirm the file type before choosing the right viewer to reveal the flag.
    Run file decoded.bin to confirm the format. For this challenge the decoded file is a JPEG image. Rename it to decoded.jpg and open it to read the flag embedded in the image.
    bash
    file decoded.bin
    bash
    # For this challenge: JPEG image
    bash
    mv decoded.bin decoded.jpg
    bash
    xdg-open decoded.jpg
    Learn more

    file reads the magic bytes and tells you the real format regardless of extension. If it says data or something unfamiliar, xxd decoded.bin | head shows the first bytes; the magic number usually identifies it (89 50 4e 47 = PNG, 50 4b 03 04 = ZIP, 7f 45 4c 46 = ELF, 25 50 44 46 = PDF).

    This pattern - encode before transmission, capture the traffic, reverse the encoding - appears in real incident response when attackers use light obfuscation to evade signature-based detection. More sophisticated obfuscation (real encryption, tunneling) needs deeper analysis, but the workflow of identifying the scheme and inverting it is the same.

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.
  • Base64 & Base32 DecoderDecode Base64 and Base32 strings with auto-detection. Multi-layer mode unwraps nested encodings automatically.
Alternate Solution

The byte-level shift of +42 is conceptually the same as a Caesar cipher applied to raw bytes. Use the ROT Cipher tool on this site with a shift of -42 (or equivalently +214) to quickly decode the extracted byte stream without writing any Python code.

Flag

Reveal flag

picoCTF{s1l3nt_str34m_...}

The encoding scheme is encoded = (original + 42) % 256 - extract the TCP stream from the PCAP, then reverse it with (encoded - 42) % 256 per byte.

Key takeaway

Network captures preserve transmitted data in full, and light obfuscation applied before transmission (byte shifting, XOR, simple ciphers) does not provide real confidentiality because the scheme can be identified and inverted. Recognizing modular arithmetic operations and applying their inverse is a core network forensics skill that appears in incident response, malware C2 traffic analysis, and any scenario where an attacker uses encoding to evade signature-based detection. The key insight is that encoding and encryption are different things: a known, fixed transformation offers no security regardless of the key value used.

Related reading

Want more picoCTF 2026 writeups?

Useful tools for Reverse Engineering

What to try next