Shifting Away
Shifting Away
Platform: Broncoctf2026 | Category: Cryptography | Type: Challenge | Difficulty: Easy | OS: NA | Author: D3v0o0Nu11 | Date: 2026-07-11 | Status: Solved Techniques: position_dependent_caesar, known_plaintext_attack, semantic_clue_analysis
Summary
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.
Recon
Port scan
bash read-only • copy allowednmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
| Port | Service | Version | Notes |
|---|---|---|---|
| <PORT> | <SVC> | <VER> | <notes> |
Enumeration highlights
- Event:
broncoctf2026| ID:20260711_broncoctf2026_shifting_away - Tags: known_plaintext, classical_cipher, caesar_cipher, progressive_shift, position_dependent_shift
- Indicators: lyrics reference 'char after char', shift increases per character, underscores/braces unchanged but still count as position, known flag prefix bronco{ enables shift derivation
- Source:
20260711_broncoctf2026_shifting_away.md
Foothold
Vulnerability / Misconfiguration
- position_dependent_caesar
- known_plaintext_attack
- semantic_clue_analysis
bash read-only • copy allowed<command>
Exploitation
- See original writeup content for detailed exploitation.
Privilege Escalation
Enumeration
bash read-only • copy allowedsudo -l find / -perm -4000 2>/dev/null getcap -r / 2>/dev/null cat /etc/crontab ps aux
Exploitation
- N/A for challenge-type writeup; see exploitation above.
- Flag obtained via challenge solve.
bash read-only • copy allowed<command>
Flags
| Flag | Location | Value |
|---|---|---|
| flag | REDACTED |
Key Takeaways / Lessons
- position_dependent_caesar
- known_plaintext_attack
- semantic_clue_analysis
- Tags: known_plaintext, classical_cipher, caesar_cipher, progressive_shift, position_dependent_shift
Original Writeup
<details><summary>Click to expand original content</summary>Shifting Away — broncoctf2026
Description
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.
Analysis
The lyric drives the whole solution:
- "I'm slowly shifting ... Char after char" → this is a Caesar cipher whose shift amount increases per character (a progressive / position-dependent shift), not a fixed rotation.
- "Underscores against the stream / Braces against the stream" → the
_,{, 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).
Solution
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.
python read-only • copy allowed#!/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}
Failed approaches (for other agents)
- Advancing the shift only on alphabetic characters (skipping braces/underscores): the first word decodes, but everything after a separator turns to gibberish because the index falls out of sync.
- Resetting the shift counter at each underscore/separator: also produces gibberish.
The correct model keeps a single monotonic counter over the entire string, exactly as the lyric ("underscores/braces against the stream") describes.
</details>signed by XESXOR