Flag: zdk{rewlNdinG_tHe_COUnter_r3USe5_tHe_s7Re4m}
TL;DR
The service reset its stream cipher's counter to the same starting state on every connection, so the keystream behind a published ciphertext could be reproduced on demand. Encrypting a block of zero bytes handed back that exact keystream in the clear, and XORing it against the published ciphertext recovered the flag directly.
Target
ncat --ssl rewind-<instance>.chals.z0d1ak.org 1337
Vulnerability
The banner announced the bug outright: "the operator swears the stream is fresh every time — watch what happens when the counter keeps rewinding." On connect, the service printed a fixed 45-byte ciphertext, secret_ct, and offered a menu:
[1] Show encrypted token
[2] Encrypt attacker-controlled bytes (hex)
[3] Exit
Reconnecting and calling option [1] repeatedly returned the identical secret_ct every time — confirmation that the cipher's counter/nonce was rewound to the same state at the start of each session rather than advancing, so the keystream protecting the secret token was never actually fresh.
Exploit
For any stream cipher, C = P XOR KS. If two ciphertexts share a keystream:
C1 = P1 XOR KS
C2 = P2 XOR KS
Choosing P2 as all-zero bytes of the same length as secret_ct (45 bytes / 90 hex chars) meant the returned ciphertext was the keystream, since 0x00 XOR KS = KS. From there:
- Recorded
secret_ctfrom option[1]. - Called option
[2]with00* 45 as the plaintext. - The server returned
ct = f9e2529b...— the raw keystream. - Computed
flag = secret_ct XOR ct, which decoded tozdk{rewlNdinG_tHe_COUnter_r3USe5_tHe_s7Re4m}.
Results
A single connection and one chosen-plaintext request were enough to recover the flag — no brute force or timing analysis required once the rewind behavior was confirmed via a repeat of option [1].
Tools & Files
ncat --sslfor the initial TLS connection and menu reconnaissance- Python 3 with
pwntools(run inside a Kali container) to script the exact[2]request and capture the response - A short inline Python XOR against the two hex strings to recover the plaintext
Note on this writeup
The original solver script was not kept on disk; this writeup was reconstructed from session notes and the recorded server transcript rather than a preserved, re-runnable script. If the original script turns up elsewhere, attaching it would strengthen the submission.
Takeaway
"Fresh every time" claims are worth verifying, not trusting — a service that resets cipher state to a fixed point on every session turns an encryption oracle into a keystream-reveal oracle, which is the textbook two-time-pad break.