Description
A mysterious file named enc_flag hides nested encodings. Your task is to unwrap each layer until the plain-text flag appears.
Setup
Fetch enc_flag from a shell where you can chain decoding utilities.
Detect how deep the nesting goes: try CyberChef Magic, or loop base64 -d until picoCTF{ appears.
wget https://artifacts.picoctf.net/c/451/enc_flagSolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1
Detect how many layers you haveObservationI noticed the file is named enc_flag and its contents look like Base64 at a glance, but a single decode produces another Base64-looking blob, which suggested the same encoding was applied multiple times and a sentinel-driven loop was needed to find the exact depth.Loop base64 decoding and stop when the output contains picoCTF{. That confirms the depth without guessing.pythonpython3 - <<'PY' import base64, pathlib data = pathlib.Path('enc_flag').read_bytes().strip() for i in range(1, 20): try: data = base64.b64decode(data) except Exception as e: print(f'layer {i}: decode failed ({e})') break if b'picoCTF{' in data: print(f'layer {i}: found flag -> {data.decode(errors="replace")}') break print(f'layer {i}: still encoded ({data[:32]!r}...)') PYExpected output
layer 1: still encoded (b'VkZSSmVFNVhTWGRPUkVsNFRWUn...'...) layer 2: still encoded (b'VFZSSk1FNVVXVE5PUkVsNFRWUn...'...) layer 6: found flag -> picoCTF{base64_n3st...e523f49}What didn't work first
Tried: Run 'base64 -d enc_flag' once and assume the result is plaintext.
A single decode emits another Base64-looking blob, not the flag. The loop output shows at least six layers; stopping after one leaves five layers of encoding still in place. The sentinel-driven loop exists precisely to discover the real depth rather than assuming it.
Tried: Pipe the file through 'strings enc_flag' to find the flag without decoding.
Base64 characters are all printable ASCII, so 'strings' returns the raw encoded blob unchanged - it has no way to detect or reverse the encoding. The flag is not present as a literal string at any intermediate layer; it only appears after all layers are decoded.
Learn more
Nested Base64 encoding means the data has been Base64-encoded several times in a row. Each layer wraps the previous output, so to recover the original you decode exactly as many times as it was encoded. Use the self-terminating loop above to learn the exact count for your instance rather than assuming a fixed number.
The loop above is more robust than counting layers by eye: it stops as soon as
picoCTF{appears and tells you how many decodes that took. If the output ever stops looking like Base64 (mixed case + digits +=padding) before the flag shows, the next layer is probably hex, gzip, or a different encoding instead.Step 2
Apply the fixed-depth decode chain (once you know N)ObservationI noticed the detection loop from step 1 reported a specific layer count N, which suggested building a flat pipeline of exactly N base64 decode stages to efficiently extract the flag in a single command.Once the loop tells you the depth N, a flat shell pipeline reads enc_flag once and pipes through N-1 more decodes. The example below shows six decodes; adjust the number of stages to the N your loop reported.bashbase64 --decode enc_flag | base64 --decode | base64 --decode | base64 --decode | base64 --decode | base64 --decodeExpected output
picoCTF{base64_n3st...e523f49}What didn't work first
Tried: Hard-code six decode stages without first running the detection loop, then get no output.
The number of layers is not guaranteed to be six across all challenge instances; it can vary. If your instance uses a different depth, the pipeline either errors out (too many decodes produce invalid Base64) or outputs a partially decoded blob that still is not the flag. The detection loop in step 1 exists to find the exact count for your specific download.
Tried: Use 'base64 -d' (BSD/macOS default) and see 'invalid input' errors mid-pipeline.
BSD base64 is stricter about whitespace and newlines than GNU base64 and may reject intermediate decoded output that contains unexpected bytes. Switching to GNU base64 (available on Linux or via 'coreutils' on macOS with Homebrew) or using the Python loop from step 1 avoids this sensitivity entirely.
Learn more
The first
base64 --decode enc_flagreads the file directly (no UUOC) and emits decoded bytes. Each subsequent| base64 --decodepeels another layer. After N total decodes (six in this example) you land on plain ASCII containing the flag; if it has not appeared, add or remove a stage.Want a sanity-check sentinel inside the pipeline? Append
| grep -o "picoCTF{[^}]*}". If the flag has not surfaced, grep prints nothing and you know the depth was off by at least one.Step 3
Alternative: CyberChef MagicObservationI noticed CyberChef's Magic operation can fingerprint and auto-cascade decoders, which suggested it as a one-click browser-based alternative that avoids writing any script for straightforward multi-layer Base64 inputs.CyberChef's Magic operation auto-detects multi-layer Base64 and decodes until the output stops looking encoded.Learn more
CyberChef ships a Magic operation that fingerprints the input and tries cascades of decoders until the output stops looking encoded. For pure multi-layer Base64 it nails this challenge in one click.
Magic's limits matter though: it does not handle hex-or-compressed layers cleanly, so if a layer mid-stack is gzipped, XOR'd with a key, or reversed, Magic gives up. In those cases drop into the recipe panel and chain operations manually.
Interactive tools
- Base64 & Base32 DecoderDecode Base64 and Base32 strings with auto-detection. Multi-layer mode unwraps nested encodings automatically.
- Cipher Identifier & Auto-DecoderPaste any ciphertext and the tool auto-runs every common decoder (base64, hex, Morse, ROT, Atbash, Bacon, binary, decimal, URL) and ranks the results by English-likeness.
Flag
Reveal flag
picoCTF{base64_n3st...e523f49}
Each Base64 decode peels a layer; run the self-terminating loop until picoCTF{ appears (the depth is fixed per instance) to reveal the flag.