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.
wireshark packets.pcap &cat encrypt.pySolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1Read the encoding script
ObservationThe 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.bashcat encrypt.pyLearn 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.
Step 2Find the right TCP stream and extract its payload
ObservationThe capture may hold several TCP conversations, and dumping everything interleaves bytes from all of them into garbage. Isolate the one stream carrying the file before extracting anything.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.pcapbash# 2. Right-click a packet -> Follow -> TCP Streambash# 3. Set 'Show data as' to 'Raw'bash# 4. Copy the hex content and save to silentstream.hexExpected output
decoded.bin: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 800x500, 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
That concatenates the data field of every packet across every stream, mixing handshake overhead and unrelated conversations into one hex dump. The result decodes to garbage. Follow a single TCP stream in raw mode before extracting bytes.
Tried: In Wireshark, set 'Show data as' to 'ASCII' instead of 'Raw' before copying the stream content
ASCII mode substitutes dots for non-printable bytes and shows the rest as characters, which is a lossy display format, neither valid hex nor the original binary. Feed it to xxd and you get a failure or a corrupted file. Raw mode emits the actual hex bytes with no substitution.
Learn more
tshark -z conv,tcpdumps 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,Nselects streamN(zero-indexed) and outputs hex; the rest of the pipe strips header lines and decodes hex back to raw bytes.xxd -r -pdecoded.-rmeans "reverse" (hex back to binary).-pmeans "plain": read continuous hex without expectingxxd'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.Step 3Reverse the encoding (subtract key 42)
Observationencrypt.py adds 42 to each byte modulo 256, so subtract 42 the same way to get the original file back.The decoding is the mathematical inverse: original = (encoded - 42) % 256. Apply this to every byte of the extracted stream to recover the original file.pythonpython3 << '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")) EOFWhat 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 and they are not the same operation: XOR undoes itself, while addition needs subtraction. The script adds, so XOR gives different bytes almost everywhere and the output matches no known file magic.
Tried: Use key = 214 and encode with (encoded + 214) % 256 instead of (encoded - 42) % 256
Adding 214 is the same as subtracting 42, since the two sum to 256, so that form works and is simply another way to write the inverse. The real trap nearby is adding 42 a second time, which encodes again rather than decoding and moves every byte further from the original.
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 = 214works without manual wrap. C-style%would return-42for the same input; use(b - 42 + 256) & 0xFFin those languages.The
errors="replace"argument todecode()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 runsfile decoded.binto identify the real format.Step 4Identify the decoded format and read the flag
ObservationWhat comes out is a binary blob of unknown type. Run file over it, read the magic bytes, and open it with whatever they name.Runfile decoded.binto confirm the format. For this challenge the decoded file is an 800x500 baseline JPEG. Rename it to decoded.jpg and open it: the flag is drawn in red text across the middle of an otherwise blank image.bashfile decoded.binbash# For this challenge: JPEG imagebashmv decoded.bin decoded.jpgbashxdg-open decoded.jpgLearn more
filereads the magic bytes and tells you the real format regardless of extension. If it saysdataor something unfamiliar,xxd decoded.bin | headshows 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{tr4ck_th3_tr4ff1c_...}
The encoding scheme is encoded = (original + 42) % 256 - extract the TCP stream from the PCAP, then reverse it with (encoded - 42) % 256 per byte. The flag is shown abbreviated on this page; work the steps above to recover the full value.