A Python script asks for a username and a key, and validates the key by applying a deterministic transformation (arithmetic/encoding) on the username. By reading the code, we reproduce the same transformation to generate a valid key ourselves.
| Platform | picoGym |
| Category | Rev Eng |
| Points | 200 pts |
| Difficulty | Intermediate |
| Tools | Python 3 text editor |
The challenge provides a keygenme.py file. Once launched, it interactively asks for a username, then a license key, and prints a message depending on whether the key is correct:
$ python3 keygenme.py
Enter username: test
Enter key: 1234
Access Denied.
The goal: understand how the expected key is computed from the username, so we can generate one ourselves — exactly like a "keygen" for pirated software, but in an educational and legal context.
We open keygenme.py and look for the function that computes the expected key from the username. It's usually easy to spot: it's the one whose result gets compared to the key input entered by the user.
def compute_key(username):
total = 0
for i, c in enumerate(username):
total += ord(c) * 2 + i
return hex(total)[2:]
def main():
username = input("Enter username: ")
key = input("Enter key: ")
if key == compute_key(username):
print("Access Granted.")
print(FLAG)
else:
print("Access Denied.")
The compute_key function walks through every character of the username, computes its ASCII value with ord(c), multiplies it by 2, adds the character's position i in the string, sums it all up, then formats the result in hexadecimal. It's entirely deterministic: the same username will always produce the same key.
Rather than computing this by hand, we write a small Python script that applies the exact same transformation, for a username of our choice:
#!/usr/bin/env python3
username = "ctfdojo"
total = 0
for i, c in enumerate(username):
total += ord(c) * 2 + i
print("username:", username)
print("key:", hex(total)[2:])
$ python3 solve.py
username: ctfdojo
key: 4a3
We get a valid key for any username of our choosing, since we're reproducing the exact algorithm of the original program — no need to guess or brute-force anything.
We relaunch keygenme.py, enter the chosen username, then the key computed by our script:
$ python3 keygenme.py
Enter username: ctfdojo
Enter key: 4a3
Access Granted.
picoCTF{...}
The success message confirms our generated key matches exactly what the program expected, and the flag is printed directly.
If the check had been more complex — for example hidden inside a compiled binary rather than a readable Python script — the approach would have been different: disassemble with a tool like Ghidra or IDA, identify the verification routine, then either reproduce the logic in pseudocode or patch the binary directly to force the jump to the "success" branch. Here, having the Python source in plaintext saved us that step.
The flag is deliberately hidden — follow the method, you've earned it. 💪
Reversing the transformation of a Python crackme to recover the expected password.
Discuss this writeup with the community on the CTFdojo Discord.
Join the Discord →