PicoCTF Crackme-py Writeup — Reverse a Python Password Check

Rev Eng 2026-12-21 · picoGym · By CTFdojo · ⏱ ... · 👁 ... views
𝕏 Share
TL;DR

The Python script compares user input, after applying a transformation to it (base64 encoding, character shift, etc.), to a hardcoded string. Instead of guessing via brute force, we read the code to identify the transformation, then reverse it mathematically to directly recover the correct password.

PlatformpicoGym
CategoryRev Eng
Points250 pts
DifficultyIntermediate
Tools python3 source reading

Challenge description

The challenge provides a script, crackme.py, which asks for a password and prints a success or failure message based on the result of a comparison:

$ python3 crackme.py
Enter the password: test123
Wrong! Try again.

Unlike a binary crackme that would require a disassembler, here the source code is directly readable — the goal isn't to deobfuscate assembly, but to understand the transformation logic and turn it against itself.

Step 1 — Read the code and locate the comparison

We open crackme.py and look directly for the line that decides success or failure — usually an if comparing a function's result to a constant:

$ cat crackme.py
import base64

EXPECTED = "cGljb0NURntmNGs" # truncated, for example

def transform(pw):
    encoded = base64.b64encode(pw.encode())
    return encoded.decode()

user_input = input("Enter the password: ")

if transform(user_input) == EXPECTED:
    print("Correct! Here's your flag.")
else:
    print("Wrong! Try again.")

The logic is clear: the user's input goes through transform(), and the result is compared to the constant EXPECTED, hardcoded in the file.

Step 2 — Identify the transformation

We look at the body of transform(): here it's a simple base64 encoding applied to the input. Other variants of this challenge may use a Caesar-style character shift, an XOR with a fixed key, or a string reversal — the principle stays the same: precisely identify the operation being performed.

def transform(pw):
    encoded = base64.b64encode(pw.encode())
    return encoded.decode()

# possible variant seen on other versions of the challenge:
# def transform(pw):
#     return ''.join(chr(ord(c) + 3) for c in pw)

The key point: base64.b64encode is a perfectly reversible operation — there's an exact inverse function, base64.b64decode, that loses no information. It's not a one-way hash like MD5 or SHA-256, so there's no need for brute force whatsoever.

Step 3 — Reverse the transformation

Since EXPECTED is known (hardcoded in the file) and the transformation is reversible, we just need to apply the inverse operation directly to EXPECTED to recover the expected password, without ever having to guess or test anything:

import base64

EXPECTED = "cGljb0NURntmNGs..." # full value copied from crackme.py

password = base64.b64decode(EXPECTED).decode()
print(password)
# -> picoCTF{***} (recovered password, masked here)

# If the transformation had been a +3 shift on each character,
# the inverse would simply be a -3 shift:
# password = ''.join(chr(ord(c) - 3) for c in EXPECTED)

In a handful of lines, the expected password falls out directly — no attempts, no iteration, just the exact mathematical inverse of the operation applied by the script.

Step 4 — Verify and grab the flag

We rerun the original script and enter the recovered password:

$ python3 crackme.py
Enter the password: picoCTF{***}
Correct! Here's your flag.
picoCTF{***}

The success message appears, confirming the transformation was correctly reversed, and the flag is revealed.

🚩 picoCTF{flag intentionally hidden}

The flag is deliberately hidden — follow the method, you've earned it. 💪

Key takeaways

This challenge illustrates a fundamental distinction in reverse engineering and applied cryptography:

Resources

Related reading

Rev Eng 2026-10-12 · picoGym

PicoCTF Vault Door Training Writeup — Read a Password from Java Source

Reading a vault door's Java source code to find the plaintext password.

CTFdojo
CTFdojo
Community of ethical hackers writing beginner-friendly CTF writeups and guides.

Got a question or a different approach?

Discuss this writeup with the community on the CTFdojo Discord.

Join the Discord →