Solve CTF Crypto Challenges with Real Tools

Crack Base64, hex, Caesar, and Vigenere ciphers using CyberChef and Linux CLI.

Introduction

30 Second Summary

Every Capture the Flag competition hides its answers behind layers of encoded text. A scrambled string might look like random characters, but it could be a simple encoding that takes seconds to crack with the right tool.

In this project, you will build a crypto-cracking workflow using CyberChef and Linux command-line tools. You will practice each technique on self-generated data, then prove it works on real challenges from CyLab Security Academy's picoGym.

What You'll Build

Picture this: someone hands you a mystery file full of garbled text, and within minutes you have identified the encoding, peeled every layer, and extracted the hidden flag.

By the end of this project, you'll have:

  • A workflow that decodes Base64 and hex flags in seconds using both CyberChef recipes and Linux CLI pipes.
  • A recon reflex that identifies mystery files and extracts hidden strings with three commands you will run on every unknown download.
  • A working Python brute-force script that cracks any Caesar cipher by testing all 26 possible shifts and printing the readable result.
  • Secret Mission: an optional challenge to push your skills further.

Are there any prerequisites?

This project assumes you have WSL with Ubuntu installed and Python 3.13 available. You should also be comfortable with basic Linux command-line navigation (cd, ls, cat).

Before We Start

Before diving into cracking codes and solving challenges, let's lock in what you're about to build and why it matters.

Set Up Your CTF Toolkit

Cracking encoded flags requires the right tools at your fingertips. In this step, you will verify six Linux CLI tools, set up CyberChef in your browser, and create the account you need for real CTF challenges.

Most CLI tools come pre-installed with Ubuntu on WSL. A quick check now prevents a frustrating command not found error from stopping you mid-challenge.

In this step, get ready to:
  • Verify six CLI tools are installed in your WSL terminal.
  • Set up CyberChef and create a free CyLab Security Academy account.
  • Create your working directory and confirm the toolkit works with a test decode.
Verify your CLI tools are installed

The six tools you will use throughout this project are file, strings, xxd, base64, tr, and grep. Together, they form your core toolkit for identifying unknown data, extracting readable content, and decoding encoded strings.

  • Press the Windows key to open your search bar.
  • Type Ubuntu and press Enter to open your WSL terminal.
  • Check that all six tools are installed by running this command:
which file strings xxd base64 tr grep

✔️ I see six file paths

You should see one path per line, like /usr/bin/file and /usr/bin/strings. All six tools are installed and ready to go.

ⓧ Some paths are missing

If any tool did not print a path, install the missing packages by running this command:

sudo apt update && sudo apt install -y file binutils vim-common coreutils

Enter your password when prompted. After the install finishes, run the which command again to confirm all six paths now appear.

What do these tools do?

  • file identifies what type of data a file contains.
  • strings extracts printable text from binary files.
  • xxd creates hex dumps and converts hex back to binary.
  • base64 encodes and decodes Base64 data.
  • tr translates or swaps characters in text, used for ROT13 decoding.
  • grep searches text for patterns, useful for finding flags in noisy output.
Open CyberChef and create your CyLab Security Academy account

CyberChef is a browser-based tool built by GCHQ for encoding, decoding, and data transformation. It runs entirely in your browser with no server component, so your data stays private.

  • Open your browser and navigate to https://gchq.github.io/CyberChef/.
  • Verify the page loads with four areas: Operations (left), Recipe (middle), Input (top-right), and Output (bottom-right).
  • Bookmark the page so you can return to it quickly throughout this project.

Now you need access to picoGym, the practice space where all the real CTF challenges live.

  • Navigate to https://cylabacademy.org/.
  • Click Sign Up to create a free account, or log in if you already have one.
  • After signing in, look for the picoGym section to confirm you can access the practice challenges.

Had a picoCTF account before May 2026?

picoCTF.org rebranded to CyLab Security Academy on May 8, 2026. If you had an existing picoCTF account, log in with those same credentials. No new account is needed.

Create your working directory and test the toolkit

You need a dedicated directory for the scripts and files you will create throughout this project. On WSL, working under your Linux home directory is much faster than working under /mnt/c/.

  • Switch back to your WSL terminal.
  • Create your working directory and move into it by running these commands:
mkdir -p ~/ctf/crypto
cd ~/ctf/crypto
  • Confirm you are in the right directory by running:
pwd

You should see a path ending in /ctf/crypto.

  • Confirm Python is available by running:
python3 --version

You should see Python 3.13.12 printed to the terminal.

  • Decode a test Base64 string by running this command:
echo 'cGljb0NURntlbmNvZGluZ19mdW59' | base64 -d

What does this command do?

echo sends the Base64 string to standard output. The pipe | passes that output to base64 -d, which decodes it back to plain text.

You should see picoCTF{encoding_fun} printed to the terminal. This is the standard flag format used in picoCTF challenges.

Time for the final toolkit check. Before you run the next two commands, what do you think each one will print?

  • Check that xxd is working by running:
xxd --version
  • Confirm base64 decoding works on a different string by running:
echo 'dGVzdA==' | base64 -d

The first command prints a version string for xxd. The second prints test. If both succeed, your toolkit is fully operational.

Seeing command not found?

  • Make sure you are running these commands inside your WSL Ubuntu terminal, not PowerShell or Command Prompt.
  • If you skipped the tool install earlier, scroll back up and follow the install instructions in the outcome tabs.
  • If xxd is specifically missing, it may live in a different package on your Ubuntu version. Try running sudo apt install -y vim-common.

Help me fix missing CLI tools in WSL

Your toolkit is ready. Next up, you will crack your first flags using CyberChef and the command line.

Crack Your First Flags with CyberChef

Your toolkit is verified and your working directory is ready. Now it is time to put those tools to work on actual encoded data.

Base64 is the most common encoding you will encounter in CTF challenges. CyberChef can decode it in seconds, but you also need to know how to decode from the command line. Many challenges hand you files instead of text blobs you can paste into a browser.

In this step, get ready to:
  • Decode Base64-encoded flags using both CyberChef and the CLI.
  • Crack a double-layer encoded flag with a multi-step CyberChef recipe.
  • Solve two real picoCTF challenges on picoGym using ROT13.
Encode and decode a Base64 flag

Every CTF challenge hides a flag behind one or more encoding layers. The first encoding you need to master is Base64, which converts binary data into printable ASCII characters.

What is Base64?

Base64 re-encodes data using only the characters A-Z, a-z, 0-9, +, and /. It often ends with = or == as padding.

Base64 is an encoding, not encryption. Anyone can reverse it without a key. CTF challenge designers use it because it makes binary data look like a harmless text string.

  • Switch to your WSL terminal and make sure you are in your working directory by running:
cd ~/ctf/crypto
  • Generate a Base64-encoded flag by running:
echo -n 'flag{cyberchef_is_awesome}' | base64

Your terminal prints a string of letters, numbers, and an = sign at the end. This is the Base64-encoded version of the flag.

  • Copy the encoded output from your terminal.
  • Switch to CyberChef in your browser.
  • Paste the encoded string into the Input pane (top-right).
  • In the Operations panel on the left, type From Base64 in the search box.
  • Drag the From Base64 operation into the Recipe pane (middle).
  • Click Bake.

The Output pane (bottom-right) shows flag{cyberchef_is_awesome}. You just decoded your first flag.

Why learn the CLI when CyberChef works?

CyberChef is perfect for quick decodes in the browser. But many CTF challenges give you downloadable files, not text blobs. The command line lets you pipe file contents directly into decoders without copy-pasting.

  • Return to your WSL terminal and decode the same flag on the command line by running:
echo '[[BASE64_OUTPUT="your Base64 output from the previous command"]]' | base64 -d

The terminal prints flag{cyberchef_is_awesome}. Same flag, different tool.

  • Practice encoding a second flag by running:
echo -n 'flag{practice_makes_perfect}' | base64
  • Copy the output and decode it in CyberChef by pasting it into the Input pane and clicking Bake (the From Base64 operation is still in your Recipe).
  • Then decode it on the CLI using the same pattern:
echo '[[BASE64_OUTPUT2="your second Base64 output"]]' | base64 -d

Both tools print flag{practice_makes_perfect}. Two reps of the same decode, two tools.

CyberChef output looks wrong?

  • Make sure you copied the full encoded string from your terminal. A missing character at the end breaks the decode.
  • Check that the From Base64 operation is in the Recipe pane, not just highlighted in Operations.
  • Help me debug my CyberChef Base64 decode.
Crack a double-encoded flag

CTF designers often stack multiple encoding layers to slow you down. A single decode pass reveals gibberish because there is still another layer underneath.

  • In your WSL terminal, create a double-encoded flag by running:
echo -n 'flag{double_layer}' | base64 | base64

This pipes the flag through Base64 twice. Copy the final output from your terminal.

  • Switch to CyberChef and clear the Input pane.
  • Paste the double-encoded string into Input.

Your Recipe still has one From Base64 operation from earlier. What do you think the output will look like with only one decode pass?

  • Click Bake with the single From Base64 operation.

The output is gibberish. It looks like random characters, not a readable flag. That is expected. One decode pass only peeled the outer Base64 layer, revealing the inner Base64 string that still needs decoding.

  • In the Operations panel, search for From Base64 again.
  • Drag a second From Base64 operation into the Recipe pane, below the first one.
  • Click Bake.

The Output pane now shows flag{double_layer}. Two operations, two layers peeled.

  • Return to your WSL terminal and run the CLI equivalent:
echo '[[DOUBLE_BASE64="your double-encoded output"]]' | base64 -d | base64 -d

The terminal prints flag{double_layer}. The pipe | chains one decode into the next, just like stacking operations in CyberChef's Recipe.

  • Switch back to CyberChef and clear the Recipe pane (remove both operations).
  • Paste the double-encoded string into Input again.
  • Look for the magic wand icon in the Output pane and click it.

CyberChef's Magic operation auto-detects the encoding layers and appends the right operations to your Recipe. The flag appears without you building the recipe manually.

Your fastest path on unknown data

When you do not know what encoding was used, click the magic wand icon first. CyberChef inspects the data up to three levels deep and suggests the right operations.

Solve real picoCTF challenges

You have decoded practice flags you created yourself. Time to prove the same techniques work on real challenges hosted on picoGym.

What is ROT13?

ROT13 is a Caesar cipher with a fixed shift of 13 positions. Each letter is replaced by the letter 13 places ahead in the alphabet.

Since the English alphabet has 26 letters, applying ROT13 twice gives you back the original text. This makes it its own inverse.

  • In your browser, navigate to the Challenge Library on CyLab Security Academy.
  • Search for the challenge called 13 (Cryptography, Easy).
  • Open the challenge description and find the ciphertext.

The ciphertext is cvpbPGS{abg_gbb_onq_bs_n_ceboyrz}. This is ROT13.

  • In CyberChef, clear the Recipe and Input panes.
  • Paste the ciphertext into Input.
  • Search for ROT13 in the Operations panel and drag it into Recipe.
  • Click Bake.

The Output pane shows the decoded flag starting with picoCTF{.

  • Decode the same ciphertext on the CLI by running:
echo 'cvpbPGS{abg_gbb_onq_bs_n_ceboyrz}' | tr 'A-Za-z' 'N-ZA-Mn-za-m'

What does tr do here?

The tr command translates characters. 'A-Za-z' is the input alphabet. 'N-ZA-Mn-za-m' is the same alphabet shifted by 13 positions.

This is the CLI way to apply ROT13 to any string.

  • Copy the decoded flag and submit it on the 13 challenge page on picoGym.

Your first real CTF solve.

  • Return to the Challenge Library and search for the challenge called Mod 26 (Cryptography, Easy).
  • Open the challenge description and copy the ciphertext.
  • Decode it using the same ROT13 technique in CyberChef or the CLI.
  • Submit the flag on the Mod 26 challenge page.

Two solves using the same ROT13 pattern. Recognizing that pattern instantly is the reflex you are building.

Flag not accepted on picoGym?

  • Make sure you are submitting the full decoded string, including the picoCTF{ prefix and } suffix.
  • Check for extra spaces or line breaks at the end of your decoded output.
  • Help me figure out why picoGym is rejecting my flag.

Think back on what you did in this step. You decoded Base64 flags, cracked a double-encoded flag, and solved two real challenges. What do the ciphertexts in both picoCTF challenges have in common?

Both use the exact same encoding: ROT13. Spotting that pattern is the beginning of the recognition reflex you will sharpen throughout this project.

You can decode Base64 and ROT13 in your sleep now. Next up, you will learn the recon reflex for inspecting unknown files before you even try to decode them.

The Recon Reflex and File Inspection

In the last step, you decoded Base64 flags and cracked a ROT13 ciphertext. Every time, you knew exactly what encoding you were looking at.

In real CTFs, you do not get that luxury. You receive a mystery file with no labels, and you have to figure out what is inside before you can decode anything. The recon reflex is the first thing every CTF player runs on unknown data. It is three commands: file, strings, and xxd.

In this step, get ready to:
  • Run the recon reflex on mystery files to identify hidden encoded data.
  • Extract flags from binary noise using Base64 and hex decoding.
  • Find and decode a ROT13 flag hidden among decoy log lines.
Create and inspect a mystery binary file

To practice the recon reflex, you need a file that hides an encoded flag inside random binary noise. You will create one yourself, then pretend you have never seen it before.

  • In your WSL terminal, make sure you are in your working directory by running:
cd ~/ctf/crypto
  • Create a mystery binary file by running this command:
python3 -c "import os; f=open('mystery.bin','wb'); f.write(os.urandom(64)); f.write(b'cGljb0NURntmaWxlX2luc3BlY3Rpb259'); f.write(os.urandom(64)); f.close()"

What does this command do?

This Python one-liner creates a file called mystery.bin. It writes 64 bytes of random garbage, then a Base64-encoded string, then 64 more bytes of random garbage. The encoded flag is buried in noise, just like a real CTF challenge.

  • Confirm the file was created by running:
ls

You should see mystery.bin listed in your directory.

Now forget everything you know about this file. Pretend someone handed it to you in a CTF with no hints. Your first move is always the recon reflex.

  • Run the first recon command to check the file type:
file mystery.bin

The output says data. That means file does not recognize the format. It is unstructured binary. That is your first clue.

  • Run the second recon command to pull out any printable text:
strings mystery.bin

You should see a long string of letters, numbers, and possibly + or = characters mixed in with the output. That looks like Base64.

  • Run the third recon command to see the raw hex dump:
xxd mystery.bin | head -20

The hex dump shows every byte in the file. On the right side, you can see ASCII characters where the Base64 string lives, surrounded by dots (non-printable bytes).

What is the recon reflex?

These three commands are the standard first move on any unknown data in a CTF.

  • file tells you the file type. If it says data, the format is unrecognized.
  • strings pulls out any printable character sequences at least 4 characters long.
  • xxd shows the raw hex dump so you can see exactly where readable text is embedded in the binary.

The strings output gave away a Base64 string. Time to extract and decode it.

  • Extract the Base64 string and decode it in one pipeline by running:
strings mystery.bin | grep -E '^[A-Za-z0-9+/=]{16,}$' | base64 -d

What does this pipeline do?

This chains three commands together using pipes.

  • strings mystery.bin extracts all readable text from the binary file.
  • grep -E '^[A-Za-z0-9+/=]{16,}$' filters for lines that match the Base64 character set (letters, digits, +, /, =) and are at least 16 characters long.
  • base64 -d decodes the Base64 string into readable text.

You should see picoCTF{file_inspection} printed to the terminal. Flag captured.

Not seeing the flag?

  • If strings shows nothing, the file may not have been created properly. Run ls -la mystery.bin and check the file size is around 160 bytes.
  • If grep returns nothing, the -E flag might be missing. Make sure you use a capital E.
  • help me debug my extraction pipeline for mystery.bin
Decode a hex-encoded flag from binary data

Base64 is not the only encoding you will encounter in binary files. Hex encoding is equally common. Its fingerprint is different: only characters 0-9 and a-f, and always an even number of characters.

  • Create a second mystery file with a hex-encoded flag by running:
python3 -c "import os; f=open('mystery2.bin','wb'); f.write(os.urandom(32)); f.write(b'666c61677b6865785f68696464656e7d'); f.write(os.urandom(32)); f.close()"
  • Run the recon reflex on the new file:
file mystery2.bin

Again, data. Unrecognized format.

  • Pull out readable text with:
strings mystery2.bin

You should see a long string of only 0-9 and a-f characters. That is the hex fingerprint. No letters above f, no + or = padding. This is hex, not Base64.

  • Decode the hex string by running:
echo '666c61677b6865785f68696464656e7d' | xxd -r -p

What do the flags -r and -p mean?

  • -r means reverse. Instead of binary-to-hex, it converts hex back to binary.
  • -p means plain hex input with no line numbers or offsets. Just the raw hex string.

You should see flag{hex_hidden} printed to the terminal.

  • Now verify the same result in CyberChef. Switch to CyberChef in your browser.
  • Paste 666c61677b6865785f68696464656e7d into the Input pane.
  • Search for From Hex in the Operations panel and drag it into the Recipe pane.
  • Click Bake.

The Output pane shows flag{hex_hidden}. Same result, two tools.

Seeing garbled output from xxd?

  • Make sure you included both -r and -p. Without -p, xxd expects line numbers and offsets in the input.
  • Check that the hex string has an even number of characters. Odd-length hex is invalid because each byte needs exactly two hex digits.
  • help me decode this hex string with xxd
Find a ROT13 flag hidden in a log file

Not every mystery is a binary file. Sometimes flags hide in plain-text logs, surrounded by normal-looking lines. The recon approach still applies. You scan for patterns that look out of place.

  • Create a fake log file with a hidden ROT13 flag by running:
printf 'ERROR: connection refused\nWARNING: disk full\ncvpbPGS{uvqqra_va_cynva_fvtug}\nINFO: process started\n' > logfile.txt
  • Confirm the file was created by running:
ls

You should see mystery.bin, mystery2.bin, and logfile.txt listed.

  • Search the log file for anything that looks like a picoCTF flag by running:
grep -i 'cvpb\|pico' logfile.txt

Why search for cvpb?

The flag format is picoCTF{...}. If it has been ROT13-encoded, pico becomes cvpb. Searching for both catches the flag whether it is encoded or not.

The output shows the line cvpbPGS{uvqqra_va_cynva_fvtug}. That cvpbPGS pattern looks like a ROT13-shifted picoCTF.

Before you decode it, what flag text do you expect to find inside the curly braces?

  • Decode the ROT13 flag by running:
echo 'cvpbPGS{uvqqra_va_cynva_fvtug}' | tr 'A-Za-z' 'N-ZA-Mn-za-m'

You should see picoCTF{hidden_in_plain_sight} printed to the terminal. Three mystery files, three different encodings, all cracked with the same recon-then-decode workflow.

Encoding fingerprints cheat sheet

  • Base64: Characters A-Za-z0-9+/ with = padding. Length is a multiple of 4.
  • Hex: Only 0-9 and a-f characters. Always an even number of characters.
  • ROT13/Caesar: Looks like English with wrong letters. Punctuation, spaces, and structure are preserved.

tr producing the same text back?

  • Make sure the character ranges in the tr command are wrapped in single quotes, not double quotes. Double quotes can cause the shell to interpret special characters.
  • Check that both ranges are present: 'A-Za-z' maps to 'N-ZA-Mn-za-m'. Swapping them or mistyping a letter will produce wrong output.
  • help me decode this ROT13 string with tr

Your recon reflex is locked in. You know how to look at unknown data, spot encoding fingerprints, and pick the right decoding tool. Next up, you will hit a wall where ROT13 does not work, and you will need to brute-force all 26 Caesar shifts with a Python script.

Crack Caesar Ciphers with Brute Force

You have been using tr to crack ROT13 ciphers with a single command. ROT13 works because the shift is always 13. But Caesar ciphers can use any shift from 1 to 25.

What happens when a challenge uses shift 7, or shift 21? Your ROT13 command produces nonsense. In this step, you will experience that wall firsthand and then write a short Python script that brute-forces all 26 possible shifts to crack any Caesar cipher.

In this step, get ready to:
  • Generate Caesar ciphers with non-13 shifts and confirm ROT13 fails on them.
  • Write a Python brute-force script that tests all 26 shifts at once.
  • Solve the picoCTF "rotation" challenge on picoGym.
Generate a Caesar cipher and try ROT13

ROT13 is a Caesar cipher with shift 13. To see why that matters, you need to try ROT13 on a cipher that uses a different shift.

  • In your WSL terminal, generate a Caesar-shifted flag with shift 7 by running this command:
python3 -c "s='picoCTF{not_just_thirteen}'; print(''.join(chr((ord(c)-65+7)%26+65) if c.isupper() else chr((ord(c)-97+7)%26+97) if c.islower() else c for c in s))"

You should see wpjvJAM{uva_qbza_aopyallu} printed to the terminal. That is your original flag shifted forward by 7 positions in the alphabet.

Before you decode it, ask yourself: will ROT13 give you back the original flag?

  • Try decoding it with ROT13 by running:
echo 'wpjvJAM{uva_qbza_aopyallu}' | tr 'A-Za-z' 'N-ZA-Mn-za-m'

The output is jwviWNZ{hin_domn_nbclnyhu}. Nonsense. ROT13 applied a shift of 13, but the cipher used a shift of 7. The two shifts do not cancel out.

  • Generate a second Caesar-shifted flag, this time with shift 21, by running:
python3 -c "s='flag{brute_force_wins}'; print(''.join(chr((ord(c)-65+21)%26+65) if c.isupper() else chr((ord(c)-97+21)%26+97) if c.islower() else c for c in s))"

You should see agvb{wmpoze_ajmxz_rdin} printed.

  • Try ROT13 on this one too:
echo 'agvb{wmpoze_ajmxz_rdin}' | tr 'A-Za-z' 'N-ZA-Mn-za-m'

Nonsense again. ROT13 only works when the shift happens to be exactly 13.

Why does ROT13 fail here?

ROT13 shifts every letter by 13 positions. If the original cipher used shift 7, ROT13 does not undo it. It just adds another wrong shift on top. To actually reverse a Caesar cipher, you need to shift by the exact same amount in the opposite direction.

The problem is you rarely know what shift was used. With only 26 possible shifts, the fastest approach is to try all of them and read the one that makes sense.

Write the brute-force script

You need a tool that tries all 26 shifts and prints each result so you can spot the readable flag. A short Python script handles this perfectly.

  • Make sure you are in your ~/ctf/crypto directory by running:
cd ~/ctf/crypto
  • Create a new file called caesar_brute.py by opening it in nano:
nano caesar_brute.py
  • Paste the following code into the editor:
import sys

def caesar_brute(ciphertext):
    # Try every possible shift from 0 to 25
    for shift in range(26):
        result = []
        for c in ciphertext:
            if c.isupper():
                # Shift uppercase letters backward
                result.append(chr((ord(c) - 65 - shift) % 26 + 65))
            elif c.islower():
                # Shift lowercase letters backward
                result.append(chr((ord(c) - 97 - shift) % 26 + 97))
            else:
                # Keep non-letter characters unchanged
                result.append(c)
        print(f"Shift {shift:2d}: {''.join(result)}")

# Read ciphertext from the command line argument
if len(sys.argv) != 2:
    print(f"Usage: python3 {sys.argv[0]} '<ciphertext>'")
    sys.exit(1)

caesar_brute(sys.argv[1])

What does this code do?

The caesar_brute function loops through shifts 0 to 25. For each shift, it moves every letter backward by that many positions in the alphabet. Non-letter characters (like {, }, and _) stay unchanged.

The script prints all 26 results. Exactly one of them will contain readable text. That is your flag.

  • Save the file by pressing Ctrl+O, then Enter to confirm the filename.
  • Press Ctrl+X to exit nano.
  • Confirm the file exists by running:
ls

You should see caesar_brute.py alongside mystery.bin, mystery2.bin, and logfile.txt.

  • Run the script on your first shifted string (shift 7) by running:
python3 caesar_brute.py 'wpjvJAM{uva_qbza_aopyallu}'

Look at the output. On the line labeled Shift 7, you should see picoCTF{not_just_thirteen}. The script found the flag that ROT13 could not.

  • Run it again on the second shifted string (shift 21) to get a second rep:
python3 caesar_brute.py 'agvb{wmpoze_ajmxz_rdin}'

On the line labeled Shift 21, you should see flag{brute_force_wins}. Two different shifts, same tool, both cracked.

Script not printing output?

  • Make sure you wrapped the ciphertext in single quotes so the shell does not interpret the curly braces.
  • Check that you saved the file correctly in nano. Run cat caesar_brute.py to verify the contents match the code above.
  • If you see a syntax error, check the f-string on the print line. The curly braces inside the f-string must match exactly.

Still stuck? Why is my caesar_brute.py script not working?

✔️ Awesome, I've got everything!

Great. Make sure you have saved caesar_brute.py before moving on.

ⓧ I'd like to double check the full code

Here is the complete caesar_brute.py file. Make sure your version matches exactly:

import sys

def caesar_brute(ciphertext):
    for shift in range(26):
        result = []
        for c in ciphertext:
            if c.isupper():
                result.append(chr((ord(c) - 65 - shift) % 26 + 65))
            elif c.islower():
                result.append(chr((ord(c) - 97 - shift) % 26 + 97))
            else:
                result.append(c)
        print(f"Shift {shift:2d}: {''.join(result)}")

if len(sys.argv) != 2:
    print(f"Usage: python3 {sys.argv[0]} '<ciphertext>'")
    sys.exit(1)

caesar_brute(sys.argv[1])
Solve the picoCTF rotation challenge

Time to use your brute-force script on a real CTF challenge. The "rotation" challenge on picoGym uses a Caesar cipher, but the shift is not 13.

  • Switch back to your browser and go to picoGym on CyLab Security Academy.
  • Search for the challenge called rotation (Cryptography, picoCTF 2023).
  • Open the challenge and click the download link to get the encrypted file.
  • In your WSL terminal, move the downloaded file to your working directory, or use wget with the download URL provided on the challenge page to download it directly.
  • Read the file contents by running:
cat encrypted.txt

You should see a single line of shifted text. It looks like letters, but they do not spell anything readable.

Before you run your brute-force script, what do you expect to see? Will the flag appear on every line, or only one specific shift?

  • Run your brute-force script on the ciphertext. Copy the text from the file and pass it as an argument:
python3 caesar_brute.py '<paste the ciphertext from the file here>'

Scan the 26 lines of output. Exactly one line starts with picoCTF{. That is your flag.

  • Copy the flag and submit it on the picoGym challenge page.

Solve it in CyberChef too

You can also crack this in CyberChef. Paste the ciphertext into the Input pane, drag the ROT13 operation into the Recipe, and adjust the Amount slider until the Output starts with picoCTF{. Both tools give you the same answer.

Can't find the rotation challenge?

  • Make sure you are on picoGym (the practice section), not a past competition page.
  • Use the search bar and type rotation. Filter by the Cryptography category if needed.
  • If the file downloads but your script shows no picoCTF{ line, double-check you copied the full ciphertext with no extra spaces or newlines.

Need more help? Help me solve the picoCTF rotation challenge using my brute-force script.

You now have a tool that cracks any Caesar cipher regardless of the shift. Next up, you will tackle challenges that stack multiple encoding layers on top of each other. One decode will not be enough.

Peel Multi-Layer Encodings

Your Caesar brute-force script can crack any single-shift cipher. Real CTF challenges go further.

Attackers and challenge authors stack multiple encoding layers on top of each other so that no single tool cracks the flag. In this step, you will create multi-layer encoded flags and peel them apart using CyberChef recipes and piped CLI commands. The critical skill is recognizing each layer's fingerprint and peeling in the correct order, outermost layer first.

In this step, get ready to:
  • Create and decode multi-layer encoded flags using CyberChef recipes and CLI pipes.
  • Learn encoding fingerprints to identify Base64, hex, and Caesar at a glance.
  • Solve the picoCTF interencdec challenge on picoGym by peeling nested encodings.
Create and peel a three-layer encoded flag

To practice multi-layer decoding, you will first build a flag with three encoding layers stacked on top of each other. Then you will peel them off in reverse order.

  • Generate a three-layer encoded flag in your WSL terminal by running this command:
echo -n 'picoCTF{layers_are_fun}' | tr 'A-Za-z' 'N-ZA-Mn-za-m' | xxd -p | base64

What does this command do?

This applies three encoding layers in order:

  • tr applies ROT13, shifting every letter by 13 positions.
  • xxd -p converts the result into a hex-encoded string.
  • base64 wraps the hex in a final Base64 layer.

The outermost layer is Base64. To decode, you peel in reverse: Base64 first, then hex, then ROT13.

Your terminal prints a long encoded string. Copy it.

  • Switch to CyberChef in your browser.
  • Paste the encoded string into the Input pane (top-right).
  • In the Operations panel (left), search for From Base64 and drag it into the Recipe pane (middle).
  • Search for From Hex and drag it into the Recipe pane below From Base64.
  • Search for ROT13 and drag it into the Recipe pane below From Hex.
  • Click Bake.

The Output pane shows picoCTF{layers_are_fun}. Three operations, one recipe, one click. That is the power of CyberChef for multi-layer decoding.

Now replicate the same decode on the command line. CyberChef is fast, but you need the CLI version for scripting and automation.

  • Return to your WSL terminal and decode the encoded string by running this command:
echo '[[ENCODED_FLAG_1="the encoded output from the encoding command above"]]' | base64 -d | xxd -r -p | tr 'A-Za-z' 'N-ZA-Mn-za-m'

The terminal prints picoCTF{layers_are_fun}. Same result, same order of operations, but using piped CLI commands instead of CyberChef.

Why does the CLI pipe order match the CyberChef recipe?

Each pipe stage peels one layer, just like each operation in the CyberChef recipe. The data flows left to right through the pipe: base64 -d strips the outermost Base64 layer, xxd -r -p strips the hex layer, and tr strips the ROT13 layer.

Getting garbled output?

  • Make sure you copied the full encoded string from your terminal output, including any trailing = characters.
  • Check that the pipe order matches the reverse of the encoding order. If you swap xxd -r -p and tr, the output will be nonsense.
  • help me debug garbled output from my multi-layer CLI decode
Practice with a different layer order

The layer order changes everything about how you peel. Swapping even two layers means a completely different recipe. A second rep with a different order builds the reflex.

  • Generate a second multi-layer encoded flag with a different layer order by running this command:
echo -n 'flag{order_matters}' | xxd -p | tr 'A-Za-z' 'N-ZA-Mn-za-m' | base64

How is this different from the first one?

This time the encoding order is hex first, then ROT13, then Base64. The first flag used ROT13 first, then hex, then Base64. Same three operations, different order. The peel order must change to match.

Copy the encoded output from your terminal.

  • Switch to CyberChef and clear the previous recipe by clicking the trash icon in the Recipe pane.
  • Paste the new encoded string into the Input pane.
  • Build a new recipe with three operations in this order: From Base64, then ROT13, then From Hex.
  • Click Bake.

The Output pane shows flag{order_matters}. Notice the recipe order changed because the encoding order changed.

  • Return to your WSL terminal and decode the same string on the CLI by running:
echo '[[ENCODED_FLAG_2="the encoded output from the command above"]]' | base64 -d | tr 'A-Za-z' 'N-ZA-Mn-za-m' | xxd -r -p

The terminal prints flag{order_matters}. The pipe order mirrors the CyberChef recipe: base64 -d first, then tr, then xxd -r -p.

How do I recognize each encoding layer?

Each encoding has a fingerprint you can spot at a glance. Always look at the outermost layer first:

  • Base64: uses characters A-Za-z0-9+/ and often ends with = or == padding. Length is a multiple of 4.
  • Hex: only characters 0-9a-f (or A-F). Always an even number of characters.
  • Caesar/ROT: looks like English with the wrong letters. Punctuation, spaces, and structure are preserved, but every letter is shifted.

Peel the outermost layer first, then re-examine the result. Repeat until you see readable text or a flag.

CLI decode prints binary garbage?

  • The most common cause is having the pipe stages in the wrong order. The peel order must be the exact reverse of the encoding order.
  • If the first flag used ROT13, hex, Base64 encoding, the decode is: base64 -d then xxd -r -p then tr. If the second used hex, ROT13, Base64, the decode is: base64 -d then tr then xxd -r -p.
  • help me fix my multi-layer CLI decode pipe order
Solve the interencdec challenge on picoGym

You have practiced creating and peeling multi-layer encodings on data you made yourself. Now apply the same technique to a real challenge where you do not know the layers in advance.

  • Switch to your browser and go to picoGym on CyLab Security Academy.
  • Search for the challenge called interencdec (Cryptography, Easy, picoCTF 2024).
  • Open the challenge and download the enc_flag file.
  • Open enc_flag in a text editor or run cat on it to see its contents.

You see a long string. Time to use your fingerprint skills. It uses characters A-Za-z0-9+/ and ends with padding. That is the Base64 fingerprint. Start peeling there.

  • Switch to CyberChef and clear any previous recipe.
  • Paste the contents of enc_flag into the Input pane.
  • Drag From Base64 into the Recipe pane and click Bake.

The Output pane shows something wrapped in b'...'. That is a Python bytes literal wrapper. It is not part of the encoded data. You need to strip it before continuing.

  • Search for Find/Replace in the Operations panel and drag it into the Recipe pane below From Base64.
  • In the Find field, type b' to match the opening wrapper. Leave the Replace field empty.
  • Add a second Find/Replace below the first one. In its Find field, type ' (a single quote) to match the closing wrapper. Leave Replace empty.
  • Click Bake.

The Output pane now shows a clean string without the b'...' wrapper. Look at the characters. You see the Base64 fingerprint again.

  • Drag a second From Base64 operation into the Recipe pane below the second Find/Replace.
  • Click Bake.

The output now looks like shifted text. The structure is preserved (curly braces, underscores) but the letters are wrong. That is the Caesar fingerprint.

  • Drag the ROT13 operation into the Recipe pane at the bottom.
  • Click Bake.

Before you check the output, predict: will the default ROT13 shift of 13 produce a readable flag, or will you need to adjust?

Check the Output pane. If the output does not start with picoCTF{, the shift is not 13. This is the same situation you hit in the previous step with non-ROT13 Caesar ciphers.

  • In the ROT13 operation in the Recipe pane, adjust the Amount slider until the Output pane shows a flag starting with picoCTF{.

The flag appears in the Output pane. This is the same multi-layer pattern you just practiced, but with an extra twist: a Python bytes wrapper you had to strip, and a Caesar shift that was not 13.

  • Copy the flag from the Output pane.
  • Return to the interencdec challenge page on picoGym and paste the flag into the submission field.
  • Click Submit.

The challenge page confirms your flag is correct. You just peeled a real multi-layer CTF challenge by recognizing fingerprints and chaining operations.

What made interencdec tricky?

The challenge combined techniques from every previous step: Base64 decoding (Step 2), recognizing encoding fingerprints (Step 3), and Caesar brute-forcing (Step 4). The Python bytes wrapper was the twist. In a real CTF, challenge authors add these small obstacles to slow down automated tools.

Flag not accepted on picoGym?

  • Make sure you copied the entire flag including picoCTF{ and the closing }. Missing a character at the start or end is the most common submission error.
  • If the flag text does not look like readable English inside the braces, your ROT13 shift Amount is wrong. Keep adjusting the slider until the full output is readable.
  • Check that you stripped the b'...' wrapper cleanly. If any leftover characters remain, the second From Base64 decode will produce garbage.
  • help me solve the interencdec challenge

Secret mission

Crack a Vigenere Cipher

Caesar ciphers use one fixed shift. Vigenere ciphers use a repeating keyword where each letter determines a different shift. Your Caesar brute-force script is useless here. Can you exploit a known-plaintext attack to recover the key and crack a real picoCTF Vigenere challenge?

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely on your local WSL filesystem using free tools, so there are no ongoing costs. Decide whether to keep your practice files for future CTF work, come back to them later, or remove them entirely.

Resources you used:

  • ~/ctf/crypto directory containing practice files (mystery.bin, mystery2.bin, logfile.txt) and Python scripts (caesar_brute.py, vigenere_crack.py).

Keep everything running

No action needed. Choose this if you plan to keep practicing CTF challenges or want to reuse your scripts.

  • Your ~/ctf/crypto directory stays on your WSL filesystem with all practice files and Python scripts.
  • Your CyLab Security Academy account remains active for future picoGym challenges.
  • CyberChef is browser-based with no account. Your bookmark stays available whenever you need it.
  • The CLI tools (file, strings, xxd, base64, tr, grep) are standard Ubuntu utilities and remain installed.
  • There are no running services or recurring costs.

Pause - I'll come back to this later

There are no running services to pause in this project. Your files remain on disk until you decide to delete them.

  • Your practice files and scripts stay in ~/ctf/crypto until you return.
  • Come back any time and pick up where you left off.

Delete - I don't want to use this again

Remove all project files from your WSL filesystem. This deletes your practice files and Python scripts permanently.

  • Remove the working directory by running this command in your WSL terminal:
rm -rf ~/ctf/crypto
  • Confirm the directory is gone by running:
ls ~/ctf/crypto

You should see an error indicating the directory no longer exists.

  • Optionally remove your CyberChef bookmark from your browser if you no longer need it.

That's a Wrap!

That's a Wrap!

Nice work. You just built a complete crypto-cracking workflow and proved it works on real CTF challenges. You can now look at an unknown encoded string, identify what was used, pick the right tool, and extract the flag.

What you learned:

  • Built a recon reflex using file, strings, and xxd to identify unknown encodings and extract hidden data from mystery files.
  • Decoded Base64, hex, and ROT13 encodings using both CyberChef recipes and Linux CLI piping, and peeled multi-layer encodings by recognizing fingerprints and chaining operations.
  • Wrote a Python brute-force script to crack Caesar ciphers across all 26 shifts, and solved real picoCTF challenges on picoGym including 13, Mod 26, rotation, and interencdec.
  • Secret Mission: Recovered a Vigenere cipher key using known-plaintext analysis and solved the picoCTF Vigenere challenge on picoGym.

Ready to quiz yourself?