Serpentine Beginner picoMini 2022 Solution

Published: April 2, 2026

Description

Option 'b' in this Python script should print the flag but prints an error instead.

Download serpentine.py from the challenge page.

Open it in a text editor and read through the menu logic.

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1
    Identify the bug
    Observation
    I noticed the challenge description says option 'b' prints an error instead of the flag, which suggested the bug is a logic error in the 'b' branch rather than a syntax problem, and that running the script would reveal what the branch actually does versus what it should do.
    Run the script and press 'b'. Instead of printing the flag, it prints a message saying it called the wrong function. Open the source and find the 'b' branch - it calls a placeholder print statement instead of print_flag().
    python
    python3 serpentine.py
    What didn't work first

    Tried: Run the script and assume the error is a Python syntax error that prevents execution.

    The script runs cleanly with no syntax error - Python parses it successfully and launches the menu. The problem is a logic bug in the 'b' branch that calls the wrong function, which only manifests at runtime when that branch is reached. Syntax checkers like 'python3 -m py_compile' will report no issues, pointing you away from the real problem.

    Tried: Search the script for 'flag' with grep to find where the flag is stored as a string literal.

    The flag is not stored as a plain string in the source - it is built or printed by the print_flag() function. grep for 'flag' will show you the function definition and the broken 'b' branch, but not a hardcoded flag value. The goal is to trace which branch runs when 'b' is pressed, not to extract a static string.

    Learn more

    This challenge teaches a fundamental debugging skill: reading error messages and tracing program flow. The script runs without crashing (no syntax error), but produces the wrong output - a logic bug rather than a syntax error. Logic bugs are often harder to find because the interpreter cannot detect them; only you can, by understanding what the code should do versus what it actually does.

    The menu-driven structure (options a, b, c, etc.) is a common pattern in interactive scripts and command-line tools. Each option maps to a branch in an if/elif/else chain. When a branch calls the wrong function or omits a function call entirely, the user sees unexpected behavior rather than a crash.

    A key technique here is reading the source before running. Once you know the script has a "b" option that should print the flag, you can search for that branch in the code and immediately see what it actually does - without needing to run and interact with the script repeatedly.

  2. Step 2
    Fix the 'b' branch
    Observation
    I noticed the source code shows the 'b' branch calls the wrong function instead of print_flag(), which suggested a single-line substitution replacing the incorrect call with print_flag() would be the minimal targeted fix.
    In the elif branch for option 'b', replace the incorrect print statement with a call to print_flag(). The function is already defined at the top of the script.
    Learn more

    Functions in Python are reusable blocks of code defined with the def keyword. Calling a function means invoking its code by name with parentheses: print_flag(). Omitting the parentheses references the function object without calling it - a common mistake that produces no error but also does nothing useful.

    The bug in this script is that the b branch contains a print() statement (or calls some other function) instead of print_flag(). This might have been an intentional challenge design - simulating the kind of copy-paste error or incomplete implementation that happens in real codebases.

    When fixing bugs in unfamiliar code, the safest approach is to make the smallest possible change that corrects the behavior - in this case, a single line replacement. Larger refactors risk introducing new bugs or changing behavior in unintended ways.

  3. Step 3
    Run the fixed script
    Observation
    I noticed the fix replaced the incorrect call with print_flag(), which suggested re-running serpentine.py and selecting option 'b' would now invoke the correct function and print the flag.
    Execute the fixed script and press 'b' at the menu. print_flag() is called and the flag is printed.
    python
    python3 serpentine.py

    Expected output

    picoCTF{...}
    Learn more

    Verifying the fix by running the script confirms the entire chain works: the menu is displayed, option 'b' is accepted, the correct branch is executed, print_flag() is called, and the flag appears. This end-to-end verification is essential - a fix that eliminates the error message but fails to produce the flag has not actually solved the problem.

    The challenge name "serpentine" is a reference to Python (whose logo is a snake). The word also implies winding, twisting paths - mirroring the indirect route to the flag caused by the misdirected function call. Many picoCTF challenge names are puns or thematic references worth noting.

    The broader skill here is code modification: reading existing code, understanding its intent, identifying where it deviates from that intent, and making a targeted correction. This is the daily work of software debugging and is directly applicable to reverse engineering challenges where you modify or patch programs to change their behavior.

Interactive tools
  • 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.
  • 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.

Flag

Reveal flag

picoCTF{7h3_r04d_l355_7r4v3l3d_...}

The fix is a one-line edit - understanding what a function does versus what the code currently calls is the core skill tested here.

Key takeaway

Logic bugs are invisible to interpreters and compilers because the code is syntactically valid; only someone who understands the intended behavior can recognize the deviation. Reading source code to trace control flow, identifying which branch executes for a given input, and making the smallest targeted fix are the core skills of software debugging and binary patching alike. The same read-trace-fix loop applies when reversing obfuscated malware, patching license checks in compiled binaries, or auditing authentication code for incorrect branch conditions.

Related reading

Want more Beginner picoMini 2022 writeups?

Useful tools for General Skills

What to try next