Unlike Caesar, each letter is replaced by a different letter according to an arbitrary mapping (not a simple shift). We solve it by comparing the letter frequency of the ciphertext to the known letter frequency in English, and guessing short words (the, and, a...).
- Platform: picoGym
- Category: Cryptography
- Points: 150 pts
- Difficulty: Beginner
- Technique: Monoalphabetic substitution, frequency analysis
Challenge description
The challenge provides a fairly long, fully encrypted text, with no hint other than the challenge's name:
"Not all ciphers are too complicated. Sometimes, all you need to do is find the correct letters."
The text contains several hundred characters — that's no accident, as we'll see, the more ciphertext there is, the more reliable frequency analysis becomes.
Step 1 — The difference from Caesar: monoalphabetic substitution
Here, there's no simple shift: each letter of the alphabet is mapped to another letter according to an arbitrary correspondence (for example A→Q, B→W, C→E...), fixed once and for all for the entire message. This gives 26! (26 factorial) possible combinations — an astronomical number, far too large for naive brute force like on Caesar.
But substitution remains vulnerable to a structural weakness: it preserves the relative frequency of letters. If "E" is the most used letter in English, then in the ciphertext, the most frequent letter very likely corresponds to "E".
Step 2 — Frequency analysis
We start by counting the occurrence of each letter in the ciphertext with collections.Counter:
from collections import Counter
with open("ciphertext.txt") as f:
text = f.read().lower()
letters = [c for c in text if c.isalpha()]
freq = Counter(letters)
for letter, count in freq.most_common():
pct = 100 * count / len(letters)
print(f"{letter} : {count:4d} occurrences ({pct:.1f}%)")
x : 187 occurrences (12.4%)
q : 143 occurrences ( 9.5%)
z : 121 occurrences ( 8.0%)
j : 98 occurrences ( 6.5%)
...
We compare this ranking to the known letter frequency in English: E (12.7%), T (9.1%), A (8.2%), O (7.5%), I (7.0%), N (6.7%)... First hypothesis: x → E, q → T, z → A, j → O.
Step 3 — Deduce mappings and iterate
Overall frequency gives a starting point, but it's never enough to solve the text in one shot — you have to refine it with structural clues:
- Single-letter words in English can only be
AorI - The most common three-letter words are often
THEorAND - Consecutive doubled letters (like
SS,LL,EE) point toward certain common pairs - Punctuation and word structure (apostrophes, short words at the end of a sentence) provide further clues
We progressively substitute the safest letters, re-read the partially decrypted text, and correct wrong hypotheses as recognizable words emerge:
Before: xqz zex ol jax os qjx pxrq ...
After (E,T,A,O known): ..e ..a .. .a. .. e..a...
By iterating several times, the text becomes more and more readable until it reveals complete words, then whole sentences, and finally the expected pattern picoCTF{...}.
Step 4 — Verify with an automatic solver
To save time or check your work, there are online substitution solvers like quipqiup.com, which use an English dictionary and a search algorithm to automatically suggest the most likely mapping. It's an excellent way to confirm a solution found manually, or to unblock a text too short for reliable frequency analysis.
🚩 picoCTF{ flag intentionally hidden }
The flag is deliberately hidden — follow the method, you've earned it. 💪
Key takeaways
Monoalphabetic substitution has a huge key space (26!), but it doesn't hide the underlying statistical structure of the language — and that's exactly what frequency analysis exploits.
- Frequency analysis is THE basic technique against any simple substitution cipher — it's what has made these ciphers obsolete for centuries against an adversary with enough ciphertext
- The longer the ciphertext, the closer the frequency distribution gets to the language's theoretical distribution, and the easier it is to solve
- Combining letter frequency with recognizing short words (A, I, THE, AND) dramatically speeds up solving compared to a purely statistical approach
Originally published on CTFdojo — join the CTFdojo Discord to discuss writeups and get notified about new ones.
This article was originally published by DEV Community and written by CTFDojo.
Read original article on DEV Community