L3m0nCTF2025-Writeups
Challenge Overview: Rotating Shadows
Cryptography/RotatingShadows/Readme.md
Challenge Overview: Rotating Shadows
Category: Cryptography
Event: L3m0nCTF 2025
Role: Challenge Author
๐ ๏ธ Author Note
This challenge was authored by me for L3m0nCTF 2025.
The following explanation describes the intended analysis path used to solve the challenge.
Intended Analysis Path
The challenge was designed to test a player's ability to:
- distinguish contextual hints from ciphertext
- extract structured identifiers rather than decode text
- recognize external references used as indirect disclosure mechanisms
- reconstruct a custom mechanical cipher from descriptive notes
Brute-force or blind decoding approaches were intentionally ineffective.
Analysis Phase 1 โ Identifying Non-Cipher Data
The challenge text includes a sentence that stands out:
โNot Less Visible, but always rotating, gears under.โ
This sentence is not part of the ciphertext file and does not resemble encrypted data. Given the hints and wording (โetchedโ, โhandwrittenโ), it is likely intentional and meaningful.
Analysis Phase 2 โ Structural Extraction
Instead of interpreting the sentence semantically, we examine its structure.
Taking the initial letters of each word:
Not โ N
Less โ L
Visible, โ V
but โ b
always โ a
rotating, โ r
gears โ g
under. โ u
This yields:
NLVbargu
The mixed casing suggests it should be used as-is, not decoded further.
Analysis Phase 3 โ Interpreting the Extracted Identifier
This Pastebin was intentionally referenced indirectly to test whether solvers would treat the sentence as an identifier rather than encoded data.
The extracted string NLVbargu does not resemble ciphertext, a key, or encoded data.
In CTFs, such identifiers are often used as external references*. Trying it as a path on common public paste services leads to:
https://pastebin.com/NLVbargu
This Pastebin contains the missing description of the cipher mechanism, including:
- Two alphabet wheels
- Their initial configurations
- How they change after each character
Analysis Phase 4 โ Reconstructing the Cipher Mechanism
From the Pastebin notes, the cipher operates mechanically as follows:
Analysis Phase 5 โ Applying the Reconstructed Cipher
Using the algorithm from the Pastebin and the ciphertext provided in the text file:
PFRLGJEUCZIVFCNGXOMTRKYH
We simulate the wheel behavior in reverse:
- For each ciphertext character:
- Find its index in Wheel B
- Take the character at the same index in Wheel A as plaintext
- Apply the same rotations and wheel mutations
Reference Implementation
# decrypt_custom.py
# Decrypts the custom rotating-wheel cipher
CIPHERTEXT = "PFRLGJEUCZIVFCNGXOMTRKYH"
LEFT_START = "GZQFHKDOVYINRUXTCALSPBEMWJ"
RIGHT_START = "YPMRDFZKQHATVJCNWOGIBLUESX"
def rotate(lst, n):
return lst[n:] + lst[:n]
L = list(LEFT_START)
R = list(RIGHT_START)
plaintext = ""
for ch in CIPHERTEXT:
idx = R.index(ch)
pt = L[idx]
plaintext += pt
# rotate BOTH wheels by same index
L = rotate(L, idx)
R = rotate(R, idx)
# wheel mutations
L = L[:2] + L[3:] + [L[2]]
R = R[:1] + R[2:] + [R[1]]
print("Recovered message:")
print(plaintext)
Running this process over the full ciphertext yields:
ZKQBLUEMTHPRDXCSWAGNQHFV
Final Output
The challenge specifies the submission format:
L3m0nCTF{...}
Placing the recovered message inside the wrapper:
Flag
L3m0nCTF{ZKQBLUEMTHPRDXCSWAGNQHFV}