$ cat writeup.md…
$ cat writeup.md…
broncoctf2026
Task: ciphertext encrypted with a position-dependent Caesar where the shift grows per absolute character index. Solution: read the lyric clues (shift per char; underscores/braces skip transformation but still advance the counter), then decrypt with P[i]=(C[i]-base+i) mod 26 + base, confirmed by the bronco{ prefix.
I'm slowly shifting, shifting afar / Char after char, char after char / I'm slowly shifting (shifting afar) // And it feels like I'm fighting / Underscores against the stream / Braces against the stream // (Source Material: Mr. Probz, 2013)
Ciphertext:
bqmkyj{Ldfmam_Nfd_Abxjpb_Thhdqeia_Snqn_Vzey_Bok_TdudakQkwfy_Kkhxbte_Yo_Jnfvdeueqq}
English summary: A single ciphertext string is given along with a "Waves" (Mr. Probz) parody lyric. The lyric is the crux — it encodes exactly how the shift behaves and how non-alphabetic characters interact with the position counter.
The lyric drives the whole solution:
_, {, and
} characters are not transformed, but they still "swim against the stream", i.e.
they remain part of the flow and still advance the position counter.So the shift applied to a letter equals its absolute zero-based index in the whole string (including separators), not a counter that only ticks on letters.
Known-plaintext confirmation. The flag wrapper is known to be bronco{. Comparing
ciphertext bqmkyj{ to plaintext bronco{:
| i | C | P | shift (C-P) |
|---|---|---|---|
| 0 | b | b | +0 |
| 1 | q | r | +1 (r+1=s? -> decrypt C-i) |
| 2 | m | o | +2 |
| 3 | k | n | +3 |
| 4 | y | c | +4 |
| 5 | j | o | +5 |
| 6 | { | { | unchanged, but i still advances |
The required per-letter shifts are exactly +0,+1,+2,+3,+4,+5, matching the
absolute-index rule. Decryption therefore subtracts the index (mod 26).
For each alphabetic character at absolute zero-based string index i:
P[i] = (C[i] - base + i) mod 26 + base (base = 'A' or 'a')
Non-alphabetic characters ({, }, _) are emitted unchanged, but i still
increments for them.
#!/usr/bin/env python3 CT = "bqmkyj{Ldfmam_Nfd_Abxjpb_Thhdqeia_Snqn_Vzey_Bok_TdudakQkwfy_Kkhxbte_Yo_Jnfvdeueqq}" def decrypt(ciphertext: str) -> str: output = [] for index, char in enumerate(ciphertext): if char.isalpha(): base = ord("A") if char.isupper() else ord("a") output.append(chr((ord(char) - base + index) % 26 + base)) else: output.append(char) return "".join(output) print(decrypt(CT)) # bronco{REDACTED}
The correct model keeps a single monotonic counter over the entire string, exactly as the lyric ("underscores/braces against the stream") describes.
cat /etc/motd
Liked this one?
Pro unlocks every writeup, every flag, and API access. $9/mo.
$ grep --similar