Codebook Beginner picoMini 2022 Solution

Published: April 2, 2026

Description

Run code.py using the codebook.txt file to get the flag.

Download both code.py and codebook.txt from the challenge page.

Place both files in the same directory before running.

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1
    Run the script with codebook.txt present
    Observation
    I noticed the challenge provided two files, code.py and codebook.txt, and the description explicitly said to run code.py using codebook.txt, which suggested the script reads the codebook at runtime to decode the flag rather than having the key embedded inline.
    Execute code.py from the directory that also contains codebook.txt. The script reads the codebook, decodes the flag, and prints it automatically.
    python
    python3 code.py

    Expected output

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

    Tried: Run python3 code.py from a different directory, such as your home folder, after downloading the files to ~/Downloads.

    Python resolves open("codebook.txt") relative to the current working directory, not the script's location. Running from the wrong directory produces FileNotFoundError: [Errno 2] No such file or directory: 'codebook.txt'. The fix is to cd into the folder containing both files before running, so both code.py and codebook.txt share the same working directory.

    Tried: Download only code.py and try to run it without codebook.txt, assuming the script has the key embedded.

    The script has no inline fallback - it reads the codebook at runtime via open(). Without codebook.txt present, execution halts immediately with a FileNotFoundError before any decoding logic runs. Both files must be downloaded from the challenge page and placed together in one directory.

    Learn more

    A codebook is a lookup table that maps one set of symbols to another. In this challenge, code.py reads codebook.txt to translate encoded values back into the readable flag. This pattern mirrors historical encryption methods like one-time pads or stream ciphers, where a separate key document was required for decryption.

    The critical lesson here is about relative file paths. When Python opens a file with open("codebook.txt"), it looks in the current working directory - whichever directory your terminal session is in when you run the command, not necessarily where the script lives. Running the script from the wrong directory causes a FileNotFoundError.

    In real-world development and security contexts, this dependency between files is usually documented or handled programmatically (e.g., using os.path.dirname(__file__) to locate the codebook relative to the script). Always check whether a script expects companion files and confirm your working directory before running.

    Codebook-style ciphers have a long history in cryptography. Before modern algorithms, nations and militaries used physical codebooks where each word or phrase was assigned a numeric code group. The receiver looked up each incoming number in their copy of the same codebook to decode the message. The security of the system depended entirely on keeping the codebook secret - if an adversary captured a codebook, every past and future message encrypted with it was compromised. This is fundamentally different from modern public-key cryptography, where the algorithm is public but the key remains private.

    In this challenge, the XOR key assembled from specific positions in codebook.txt acts as a simple symmetric key: whoever has the file can decode the flag, and whoever lacks it cannot. This mirrors real-world scenarios where configuration files, key files, or credential files must accompany an application. Security misconfigurations often arise when these companion files are accidentally committed to version control, left world-readable on a server, or bundled inside a Docker image.

    When analyzing unfamiliar scripts in CTF or malware research, a useful first step is to scan for all open() calls and import statements to understand what external resources the script depends on. In Python, open() reveals file dependencies, while imports like requests or socket indicate network activity. Mapping these dependencies before running the script gives you a complete picture of what it expects from the environment and what it might do.

    More advanced codebook-style challenges may obfuscate the lookup mechanism - for example, computing a hash of each character and comparing it against precomputed values, or encoding the codebook itself in base64 within the script. The core technique of reading the script, identifying its decoding logic, and supplying the required key material remains the same regardless of how the obfuscation is layered on top.

Interactive tools
  • Base64 & Base32 DecoderDecode Base64 and Base32 strings with auto-detection. Multi-layer mode unwraps nested encodings automatically.
  • Recipe ChainStack decoders into a pipeline: Base64, hex, ROT, XOR, Morse, URL, Atbash, Vigenère, and more. Magic mode auto-discovers the chain. Bookmark the URL to save it.
  • Number Base ConverterConvert numbers between binary, octal, decimal, and hexadecimal instantly. Enter any value and see all four bases update in real time.

Flag

Reveal flag

picoCTF{c0d3b00k_455157_...}

The script requires both files to be in the same directory - a common pitfall for beginners who only download one file or run the script from a different working directory.

Key takeaway

Python's open() resolves file paths relative to the current working directory, not the script's location; when a script requires a companion file, both must be in the same directory you launch the command from. Codebook-style ciphers pair a decoding function with a key document - the security of the scheme depends entirely on keeping that document secret, just as historical military codebooks had to be guarded physically.

Related reading

Want more Beginner picoMini 2022 writeups?

Useful tools for General Skills

What to try next