Description
A classic Crackme. Find the password, get the flag! Binary can be downloaded here. Crack the Binary file locally and recover the password. Use the same password on the server to get the flag! Access the server using nc titan.picoctf.net 56916
Setup
Download crackme100 and load it into Ghidra.
Install gdb so you can break before the comparison and read the real secret string from memory.
wget https://artifacts.picoctf.net/c_titan/83/crackme100 && \
chmod +x crackme100sudo apt install gdbSolution
Walk me through it- Step 1Understand the mangling loop in GhidraIn Ghidra, rename variables so the logic reads cleanly (local_c is the outer counter i, local_10 is the inner counter j, local_a8 is the input buffer). The loop runs three rounds. Each round, for every character j, it computes intermediate values from the index j and the constants 0x55/0x33/0xF, adds (input[j] - 'a'), then reduces the result modulo 26 back into the lowercase range. After three rounds it calls memcmp against the stored secret string and prints the flag on a match.
Learn more
A crackme is a program designed to be reverse-engineered. The goal is to recover the correct password without source. Ghidra's decompiler is the key tool: after importing the binary and running analysis, open
mainin the decompiler pane. Renaming variables makes the three-round transformation readable.The binary reads up to 50 characters of user input into
local_a8, then runs a three-iteration loop that applies the same index-dependent modular arithmetic to each byte. After the loop it compares the transformed buffer against the stored secret string withmemcmp. The important subtlety: the value the binary compares against is not the password you type, it is the password after three rounds of mangling. The constants printed near the top ofmain(the movabs values like0x676d76727970786c) are the bytes of that already-mangled target, not the password itself. - Step 2Break in gdb and read the real comparison stringDisassemble main with objdump to find the address right after the constant stores. A breakpoint at 0x4011e8 lands after every movabs has populated the secret buffer. Run, then info locals reveals the comparison string lxpyrvmgduiprervmoqkvfqrblqpvqueeuzmpqgycirxthsjaw. That 50-character string is the mangled target the input must equal after three rounds.bash
objdump -D crackme100 | lessbashgdb crackme100bashbreak *0x4011e8bashrunbashinfo localsThe buffer prints aslxpyrvmgduiprervmoqkvfqrblqpvqueeuzmpqgycirxthsjaw. Copy that string; the next step reverses the three rounds to recover the password that produces it.Learn more
gdb (the GNU Debugger) lets you pause a running binary and inspect memory and registers. Here it sidesteps reverse-engineering the constant layout by hand: instead of decoding each movabs value into ASCII, you let the program populate the buffer itself, then read it out. Use
objdump -Dto read the disassembly and pick an address after the last movabs but beforesetvbufis called, so the secret buffer is fully written but the program has not yet started its real work.Setting
break *0x4011e8stops execution at that instruction address,runexecutes up to the breakpoint, andinfo localsdumps the current stack variables, where the comparison string is visible. This dynamic-analysis shortcut is often faster and less error-prone than statically reconstructing data from movabs immediates. - Step 3Reverse the three rounds in PythonRecreate the per-character math from Ghidra, but invert the addition: instead of adding the index-derived offset to (input - 'a'), subtract it from (cipher - 'a') modulo 26. Loop the same three times over the captured comparison string, and the recovered password falls out.python
python3 - <<'PY' c = "lxpyrvmgduiprervmoqkvfqrblqpvqueeuzmpqgycirxthsjaw" p = ['' for _ in c] for i in range(3): for j in range(len(c)): v7 = (85 & (j % 255)) + (85 & ((j % 255) >> 1)) v6 = (v7 & 51) + (51 & (v7 >> 2)) x = (ord(c[j]) - 97) % 26 y = (x - ((v6 & 15) + (15 & (v6 >> 4)))) % 26 p[j] = chr(y + 97) c = ''.join(p) print(c) PYLearn more
The constants 0x55 (85), 0x33 (51), and 0xF (15) are bit masks. The original loop computes an offset from the character index j: it masks
j % 255with 85 and adds a shifted copy, masks that with 51 and adds a shifted copy, then masks with 15. That offset is added to(input[j] - 'a')and reduced modulo 26. Because the offset depends only on j (not on the input), it is the same on every pass, so undoing the round is a simple subtraction modulo 26.The script reproduces the offset exactly (
v7,v6, and the final(v6 & 15) + (15 & (v6 >> 4))term), then subtracts it from each mangled byte. Repeating the inverse three times mirrors the three forward rounds, recovering the lowercase password the program expects. - Step 4Submit remotelyTest the recovered password locally against crackme100 first; if it prints the sample flag, the recovery is correct. Then connect to the server and enter the same password to receive the real flag.bash
nc titan.picoctf.net 56916Learn more
netcat (
nc) provides a raw TCP connection to the server. You type directly to the server process's stdin and see its stdout in your terminal. The pattern of cracking locally then submitting remotely is common in reversing challenges: the remote service runs the same binary but returns the real flag only after correct input, keeping the flag out of the downloadable binary.From a security perspective, this challenge illustrates why storing a verifiable password as a reversibly-transformed string in a binary is not secure. Any determined attacker with the binary can recover the password through static analysis plus a short script, or simply by reading the comparison buffer at runtime. Real applications should use a cryptographic hash (bcrypt, Argon2, scrypt) where reversing the transformation is computationally infeasible.
Related guides
How to Use Ghidra for Reverse Engineering CTF Challenges
A full walkthrough of Ghidra: importing binaries, reading decompiled C, renaming variables, and tracing password comparison logic.
Beginner's Guide to Netcat for CTFs
This challenge ends with nc submission. Learn how nc works and how to automate it for challenges with more complex interactions.
Flag
picoCTF{s0lv3_angry_symb0ls_150f...}
Entering the recovered password on the remote instance prints the flag.