The Caesar cipher has exactly 26 possible shifts (modulo the 26 letters of the alphabet). A Python script that tests all 26 shifts and looks for picoCTF in the result finds the right one in a fraction of a second.
- Platform: picoGym
- Category: Cryptography
- Points: 100 pts
- Difficulty: Beginner
- Technique: Caesar cipher, brute force
Challenge description
The challenge provides a ciphertext and a hint that clearly points the way:
"I made my really long password more secure by adding 26 to each letter... modulo the number of letters."
tmgsgxj{________________________}
The word "modulo" combined with text that looks like letters shuffled in a regular pattern is a strong hint toward a Caesar cipher.
Step 1 — Understand the Caesar cipher
The Caesar cipher is one of the oldest known ciphers: each letter of the plaintext is replaced by the letter located n positions further in the alphabet, where n is the shift (the key). For example, with a shift of 3: A→D, B→E, C→F, etc. Once we reach Z, we wrap back around to A — hence the "modulo 26" in the hint, since the Latin alphabet has 26 letters.
Mathematically, for a letter at position p in the alphabet (A=0, B=1, ..., Z=25) and a shift k:
encryption: c = (p + k) mod 26
decryption: p = (c - k) mod 26
Step 2 — Brute force across the 26 shifts
Caesar's fundamental weakness is that the key space is ridiculously small: there are only 26 possible shifts (0 to 25), one of which does nothing (shift 0) and one of which is the famous ROT13 (shift 13). No need to guess anything: we test all 26 in a loop and see which one produces readable text.
def caesar_decrypt(text, shift):
result = []
for ch in text:
if ch.isalpha():
base = ord('A') if ch.isupper() else ord('a')
decoded = chr((ord(ch) - base - shift) % 26 + base)
result.append(decoded)
else:
result.append(ch) # leave digits, punctuation, spaces untouched
return ''.join(result)
ciphertext = "tmgsgxj{________________________}"
for shift in range(26):
print(f"shift {shift:2d} : {caesar_decrypt(ciphertext, shift)}")
Step 3 — Identify the right shift
Running the script gives us 26 lines of output. Most are gibberish, but one jumps right out — the one starting with picoCTF{:
shift 0 : tmgsgxj{________________________}
shift 1 : slfrfwi{...}
...
shift 3 : qjdpduf{...}
shift 4 : picoctf{________________________}
shift 5 : ohbnbse{...}
...
shift 13 : ghtdtjy{...}
...
Shift 4 gives perfectly readable text, with the expected prefix picoctf{ — that's our shift. In practice, you just scan the 26 lines by eye, or script the detection by automatically searching for the substring picoctf{ in each output.
🚩 picoCTF{ flag intentionally hidden }
The flag is deliberately hidden — follow the method, you've earned it. 💪
Key takeaways
Caesar is the textbook example of a cipher "broken by design": its security relies entirely on the secrecy of the method, not on mathematical robustness. As soon as you know it's Caesar, the key is found instantly.
- The Caesar cipher is cryptographically weak because its key space is ridiculously small (26) — always consider brute force first on such a small key space
- Searching for a known pattern (here
picoCTF{) across the 26 outputs lets you fully automate detecting the right shift, with no manual reading - This principle generalizes to ROT13 and any substitution variant with a fixed shift — the number of keys is always bounded by the size of the alphabet
Originally published on CTFdojo — join the CTFdojo Discord to discuss writeups and get notified about new ones.
Top comments (0)