A multi-stage CTF journey through cryptography, OSINT, infrastructure security, network forensics, and steganography — with a little help from AI and a lot of science fiction references.
Challenge: ByteBreach 2025.2
Organizer: BeyondMachines (Bozidar Spirovski)
Duration: December 15, 2025 – January 2, 2026
URL: https://challenge.beyondmachines.net/
Overview
ByteBreach 2025.2 is a multi-stage cybersecurity challenge involving OSINT, cryptography, web security, and good old-fashioned detective work. The goal is to collect 8 tokens, each leading to the next challenge. The token names follow a distinctive pattern — more on that Easter egg at the end.
Tokens Collected
| # | Token Name |
|---|---|
| 1 | Calibrated_Absence |
| 2 | Threshold_of_Antiquity |
| 3 | Trajectory_Uncertain |
| 4 | Requiem_for_Velocity |
| 5 | Relativistic_Records |
| 6 | Testament_to_Darker_Hours |
| 7 | Paradox_Deferred |
| 8 | Doctrine_of_Receding_Light |
Stage 1: The Starting Point
URL: https://challenge.beyondmachines.net/
The challenge page looks like a standard CTF landing page with rules, prizes, and timeline information. The first instinct in any web challenge: view the page source.
Scanning through the HTML, I found a clue hiding in an unexpected place — the alt attribute of the main challenge image:
I've added something in this site: https://cryptpad.fr/pad/#/2/pad/view/y77PNt4ibX8k97GA+8T4bqOFI49w7wbcehNS0DFn1Ag/p/embed/
You need a password. So here's a password, but it's also encrypted.
OMSHCHTOXDCHHTVGMN
Decrypt the password first. I've used a one-time pad. Because of course.
You need the first paragraph of a book about Ana by Tolstoy, translated by Constance Garnett. PDF.
Lesson learned: Don't just look for HTML comments or hidden divs. Alt text, title attributes, and other metadata are fair game.
Stage 2: One-Time Pad Decryption
The clue specifies:
- Encryption method: One-Time Pad (OTP)
- Key source: First paragraph of Anna Karenina, Constance Garnett translation, PDF format
- Ciphertext:
OMSHCHTOXDCHHTVGMN
The opening of Anna Karenina is one of the most famous in all of literature:
"Happy families are all alike; every unhappy family is unhappy in its own way."
I used Claude to fetch the specific PDF from Project Gutenberg to ensure I had the exact Constance Garnett translation, then applied OTP decryption using the first paragraph as the key.
Result: HMDSECTCPSUDPTECMC
Important gotcha: When I first decrypted this, Claude got confused because the result doesn't look like readable English. But that's the point — it's a password, not a message. Passwords are supposed to look like gibberish. Don't second-guess a successful decryption just because the plaintext isn't a coherent sentence.
Stage 3: The CryptPad Document
URL: https://cryptpad.fr/pad/#/2/pad/view/y77PNt4ibX8k97GA+8T4bqOFI49w7wbcehNS0DFn1Ag/p/embed/
Password: HMDSECTCPSUDPTECMC
The password-protected CryptPad document contained:
Token 1: Calibrated_Absence
Next Token: http://walloftext.codeonion.net
🎯 Token 1: Calibrated_Absence
Stage 4: The Wall of Text
URL: http://walloftext.codeonion.net
The URL name was apt — the page contained a babel of text in multiple languages. The natural first move: inspect the HTML for hidden elements.
Red Herring
I quickly spotted a CSS class named hidden and found Arabic text:
هل كنت تعتقد أن الأمر سيكون بهذه السهولة؟
Translation: "Did you think it would be this easy?"
Well played, Bozidar. Well played.
The Actual Clue
The actual clue wasn't hidden in the HTML structure — it was hiding in plain sight within the multilingual text itself. Reading through the different language blocks, I found Portuguese text that mentioned:
- An S3 bucket on
eu-central - Bucket name:
cicadoidea6699 - A file called "configuration.txt" but written in Macedonian Cyrillic:
конфигурација.txt
Notes:
- Cicadoidea is the superfamily of cicadas — a nod to the famous Cicada 3301 internet puzzle
- Using Macedonian Cyrillic for the filename filters out anyone brute-forcing common filenames
- Being from North Macedonia, I had a slight home-field advantage here 🇲🇰
Stage 5: The S3 Bucket
URL: https://cicadoidea6699.s3.eu-central-1.amazonaws.com/конфигурација.txt
Accessing the configuration file revealed:
Token 2: Threshold_of Antiquity
Next Token: http://shai-hulud.yieldcat.com
🎯 Token 2: Threshold_of_Antiquity
The next URL contains another science fiction reference: Shai-Hulud is the Fremen name for the giant sandworms in Frank Herbert's Dune.
Stage 6: Shai-Hulud (The Supply Chain Attack)
URL: http://shai-hulud.yieldcat.com
This page describes a supply chain attack — and it's not fictional. The Shai-Hulud worm was a real, devastating npm supply chain attack that occurred in September and November 2025:
- First wave (September 2025): ~500 packages compromised, ~$50 million in cryptocurrency stolen
- Second wave (November 2025): 700+ additional packages, 25,000+ malicious GitHub repositories
- Victims included packages from Zapier, PostHog, Postman, and ENS Domains
- The malware exfiltrated credentials to public GitHub repos labeled "Sha1-Hulud: The Second Coming"
The page itself contained obfuscated JavaScript. Viewing source revealed:
const _0x2d381a = _0x5a27;
function _0x5690() {
const _0x5b7bc3 = [
'load\x20local',
'om:',
'sYqne',
'render.jss',
// ... many more shuffled strings
];
// ...
}
This is a common obfuscation pattern: strings are stored in an array that gets shuffled at runtime, making static analysis difficult.
The Console Hint
Opening the browser console revealed an error message:
Failed to load local script from: http://shai-hulud.yieldcat.com/render.jss
Maybe you need the remote_url version?
This hints that there's a remote_url variable containing the real destination.
Failed Approach: Static Deobfuscation
I tried using Claude to deobfuscate the JavaScript statically, but it produced an incorrect Google Drive URL. The problem: the array shuffling happens at runtime, and static analysis can't predict the final order.
Successful Approach: Browser Debugger
Instead of fighting the obfuscation, I let the browser do the work:
- Open Developer Tools (F12)
- Go to the Console tab
- After the page loads, type
remote_urland press Enter - The browser returns the fully-constructed URL
Result: https://drive.google.com/uc?export=download&id=1QPWq3fQbDXTTBfBcb3I2E2qMslm3WEFV
The Google Drive File
The link downloaded a file named render.js (note: .js not .jss) containing:
<p><strong>Token 3: Trajectory_Uncertain</strong></p>
<p><strong>Next Token: https://github.com/BeyondMachines/secondary-case-for-sanity</strong></p>
🎯 Token 3: Trajectory_Uncertain
Lesson learned: When dealing with runtime obfuscation, don't waste time on static analysis. Use the debugger — let the JavaScript engine do the deobfuscation for you, then inspect the result.
Stage 7: The GitHub Repository
URL: https://github.com/BeyondMachines/secondary-case-for-sanity
The repository contains a single README.md with a dismissive message:
"This repo is going nowhere fast. We are abandoning it." "The latest code is published on codeonion subdomain. Whoever wants to be bothered, go there."
The hint points to: http://secondarysanity.codeonion.net/
Visiting this page reveals another important message:
"I just hope i cleaned everything from production in my latest terraform delete, including the terraform variables."
Red flag: "terraform variables" is a direct hint. Terraform variable files (.tfvars) often contain secrets and are frequently left exposed accidentally.
Stage 8: Terraform Misconfiguration
URL: http://secondarysanity.codeonion.net/terraform.tfvars
Accessing the Terraform variables file directly reveals a classic infrastructure security mistake — exposed secrets in configuration files:
Token 4: Requiem_for_Velocity
Next Token: https://drive.google.com/file/d/1AvhGVbvA-6KscvXMHhlgdek5CDcA9N9f/view?usp=drive_link
🎯 Token 4: Requiem_for_Velocity
Real-world lesson: Terraform files (.tfvars, .tfstate, terraform.tfstate.backup) are treasure troves for attackers. They often contain:
- Database passwords
- API keys
- Cloud provider credentials
- Infrastructure secrets
Always add *.tfvars and *.tfstate* to your .gitignore and never expose them on web servers.
Stage 9: Email Forensics & OSINT
File: interview.eml (downloaded from Google Drive)
The EML file contained an email with two base64-encoded attachments:
- A CV (curriculum vitae) PDF
details.zip(password-protected)
The CV Analysis
The CV belonged to Ivie Clayton, an Engineering Manager from Manchester. Key details:
- Current job: Engineering Manager at Accenture
- Previous: Capgemini, IBM, Wipro
- Education: University of Toronto, graduated August 2014
- Marathon: Boston Marathon 2019, Bib #1421
- Blog: https://itsivie.blogspot.com
The Blog OSINT
Ivie's blog contained several articles:
- Password best practices — ironically confessing her own bad habits
- Articles about her cat named Pixelate
- Her love of running
- Her fascination with binary palindromes
The password article contained this confession:
"Years ago, I used 'Marley2014' as a password. Marley was my childhood dog. 2014 was when I graduated university."
The Password Puzzle
This was the most challenging part — a classic OSINT misdirection:
- Red herring: The Marley2014 confession seemed like the obvious answer
- Real password components:
- Pixelate — her current cat's name
- 1421 — her marathon bib number (not a year!)
The connection: 1421 in binary = 10110001101, which is a binary palindrome — linking to her stated interest!
Password: Pixelate1421
The Zip File
Extracting details.zip with the password revealed:
Token 5: Relativistic_Records
Next Token: https://sites.google.com/view/yellowstone-transit-log/
🎯 Token 5: Relativistic_Records
Note: "Yellowstone" is the planet where Chasm City is located in the Revelation Space universe — continuing the Alastair Reynolds theme.
Lesson learned: OSINT password puzzles often combine multiple sources in non-obvious ways:
- Current pet names (not former ones mentioned as examples)
- Numbers that have special meaning beyond the obvious (bib number, not graduation year)
- Look for connections between seemingly unrelated interests (binary palindromes + marathon bib)
Stage 10: Network Forensics
URL: https://sites.google.com/view/yellowstone-transit-log/
The page "Artifacts of Lost Protocol" contained:
"The data archive remains intact, despite centuries of corruption and drift." "Patterns that once meant something to someone, somewhere, in a time now lost to relativistic lag. We were careful to keep the logs secure and we always used hex encoding."
The linked file was a pcapng (packet capture) file.
Initial Analysis Challenges
Opening the file in Wireshark showed various protocols:
- TDS (SQL Server) traffic
- GIOP (CORBA) protocol
- Syslog packets
- Various TCP connections
Initial attempts to find patterns in:
- TCP payload data
- DNS queries
- HTTP objects
...all came up empty.
The Breakthrough: Syslog Packets
The key was in the Syslog packets. The clue mentioned "hex encoding," and examining the syslog messages revealed hex-encoded data.
Using tshark to extract syslog data:
tshark -r data.pcapng -Y "syslog" -T fields -e syslog.msg
The extracted messages contained hex-encoded ASCII that, when decoded, revealed:
Token6:Testament_to_Darker_Hours;Next_Token:https://sites.google.com/view/hamadryad-onion/
🎯 Token 6: Testament_to_Darker_Hours
Lesson learned: Network forensics challenges often hide data in unexpected protocols. When the clue mentions a specific encoding (hex), look for that encoding in packet payloads, especially in text-based protocols like Syslog.
Stage 11: Timing Attack
URL: https://sites.google.com/view/hamadryad-onion/
The page presents a scenario: an attacker trying to breach a legacy login endpoint, armed with:
- A list of usernames with login attempt response times
- A password list from an infostealer
The challenge: identify which user the stolen passwords belong to without brute-forcing all combinations.
The Timing Side-Channel
Authentication systems can leak information through response times. When a username doesn't exist, the server can reject immediately. But for valid usernames, it must:
- Look up the user
- Hash the provided password
- Compare to the stored hash
This takes measurably longer.
Finding the Outlier
Examining the response times from the pastebin:
- Most responses: 5-50 ms
- One outlier: 380 ms (7-10x longer!)
The user with the 380ms response time is the valid account — the one whose credentials were stolen.
The Brute Force Script
With the target identified, I created a PowerShell script to test all ~100 stolen passwords against this single user:
$url = "https://yieldcat.com/api/legacy-login"
$username = "mrobshaw@comcast.net"
foreach ($password in $passwords) {
$body = @{ username = $username; password = $password } | ConvertTo-Json
# POST with 10-second delay between attempts
# Handle 429 rate limits with 60-second backoff
}
Aside: Claude initially refused to generate this script, interpreting it as credential stuffing. After clarifying that yieldcat.com is a legitimate security training platform (which Claude verified via web search), it assisted. A good reminder that AI guardrails sometimes need context.
The Result
One of the passwords worked, revealing:
Token7:Paradox_Deferred;
Next Token:https://drive.google.com/file/d/1pba2FYbH5oxujuYE-AnQogkxBGt4uDYi/view?usp=sharing
🎯 Token 7: Paradox_Deferred
Lesson learned: Timing side-channels are real vulnerabilities. Authentication systems should use constant-time comparison functions to prevent username enumeration.
Stage 12: Steganography
File: difference.zip (from Google Drive)
The zip contained two files:
n1.png- appears to be random noisen2.png- also appears to be random noise
Two nearly identical noisy images is a classic steganography setup. The hidden message is likely encoded in the differences between the images.
Common techniques:
- XOR the two images together
- Subtract pixel values and look for patterns
- Compare LSB (Least Significant Bit) differences
- Look at specific color channels
The Steganography Technique
The solution involved XORing the two images together:
from PIL import Image
import numpy as np
img1 = Image.open('n1.png')
img2 = Image.open('n2.png')
arr1 = np.array(img1)
arr2 = np.array(img2)
xor_result = arr1 ^ arr2
The XOR values clustered in two ranges: 0-15 and 240-255 (0xF0-0xFF). This indicated data hidden in the high nibble (upper 4 bits).
Further analysis revealed:
- High nibble: Binary values only (0x0 or 0xF)
- Low nibble: Random values 0-15 (noise/camouflage)
Extracting pixels where the high nibble differs:
high_nibble_binary = ((xor_result >> 4) > 0).astype(np.uint8) * 255
Image.fromarray(high_nibble_binary).save('hidden.png')
The resulting image revealed text:
🎯 Token 8: Doctrine_of_Receding_Light
Visual Cryptography
This is classic visual cryptography - neither image alone reveals anything meaningful (both appear as random noise), but combining them mathematically exposes the hidden message. The low nibble randomness serves as camouflage to make the images appear completely random.
Challenge Complete! 🏆
All 8 tokens collected:
| # | Token | Challenge Type |
|---|---|---|
| 1 | Calibrated_Absence | HTML metadata + OTP cryptography |
| 2 | Threshold_of_Antiquity | Multilingual OSINT + S3 bucket |
| 3 | Trajectory_Uncertain | JavaScript deobfuscation |
| 4 | Requiem_for_Velocity | Terraform misconfiguration |
| 5 | Relativistic_Records | Email forensics + OSINT password |
| 6 | Testament_to_Darker_Hours | Network forensics (pcapng/Syslog) |
| 7 | Paradox_Deferred | Timing attack + credential testing |
| 8 | Doctrine_of_Receding_Light | Visual cryptography/steganography |
Easter Egg: The Token Names
The eight token names follow a very distinctive naming pattern:
| Token | Style |
|---|---|
| Calibrated_Absence | [Abstract noun] + [Abstract noun] |
| Threshold_of_Antiquity | X of Y construction |
| Trajectory_Uncertain | Physics/motion reference |
| Requiem_for_Velocity | Melancholic + Physics reference |
| Relativistic_Records | Physics/spaceflight theme |
| Testament_to_Darker_Hours | Poetic, melancholic |
| Paradox_Deferred | Philosophical |
| Doctrine_of_Receding_Light | Cosmic, philosophical |
This is the signature naming convention of lighthugger starships from Alastair Reynolds' Revelation Space universe. Compare to canonical ship names like:
- Nostalgia for Infinity
- Melancholia of Departure
- Silence Under Snow
- Accompaniment of Shadows
Lighthuggers are massive interstellar spacecraft that travel at relativistic speeds (hence "light-huggers" — they hug close to the speed of light). The poetic, melancholic names reflect the existential weight of centuries-long journeys and the time dilation that separates crews from everyone they ever knew.
Bozidar Spirovski is clearly a fan. The token names aren't just identifiers — they're a love letter to hard science fiction.
Working with Claude
I tackled this CTF with Claude as my AI partner throughout. Some observations:
Where Claude excelled:
- OTP decryption and cryptographic calculations
- Explaining steganography techniques and writing Python extraction scripts
- Network forensics analysis with tshark
- Research on real-world security incidents (the Shai-Hulud supply chain attack)
Where Claude struggled:
- Static JavaScript deobfuscation when runtime shuffling was involved (the browser debugger was the right tool)
- Initial refusal on the brute-force script (needed context that this was a legitimate CTF)
- Getting confused when decrypted output "didn't look right" (passwords aren't sentences!)
The takeaway: AI is a powerful CTF partner for analysis, scripting, and research — but knowing when to reach for browser DevTools or other specialized tools remains essential.
Tools Used
- Browser developer tools (View Source, Inspect Element, Console, Debugger)
- Claude (for OTP decryption, research, JS deobfuscation attempts, pcapng analysis)
- Python with PIL/NumPy (for steganography extraction)
- Basic knowledge of AWS S3 URL structure
- Google Translate (for the Arabic red herring)
- A reading knowledge of Macedonian Cyrillic
- PowerShell scripts (for base64 decoding, credential testing)
- Wireshark / tshark (for pcapng network forensics)
- 7-Zip or similar (for password-protected zip extraction)
- Patience (for the OSINT password puzzle)
Key Takeaways
Always view source — but don't just look for comments. Check alt text, title attributes, data attributes, everything.
Red herrings are real — Just because something has a
hiddenclass doesn't mean it's the hidden thing. Sometimes it's bait.Decrypted passwords look like gibberish — Don't second-guess a successful decryption because the output isn't readable English.
Read the actual content — In the wall of text challenge, the clue wasn't hidden in the HTML structure; it was in the text itself. Sometimes you have to actually read things.
Use the debugger for runtime obfuscation — LLMs can help with static analysis, but when arrays are shuffled at runtime, let the browser do the work. Inspect variables after execution.
Cultural/language knowledge helps — Macedonian Cyrillic, Dune references, Cicada 3301 lore, Alastair Reynolds, real-world security incidents... CTFs reward broad curiosity.
Check multiple angles on GitHub — Repos can hide secrets in commit history, branches, issues, actions, and more.
Terraform files are security goldmines — Always check for exposed
.tfvarsand.tfstatefiles. They frequently contain credentials.OSINT requires connecting disparate sources — The password combined current cat name + marathon bib (not graduation year). Look for non-obvious connections.
Network forensics: follow the encoding hint — When a clue mentions "hex encoding," look for hex in packet payloads. Syslog and other text protocols are good hiding spots.
Don't overthink red herrings — The Marley2014 confession was a decoy. Sometimes the most "obvious" answer is intentional misdirection.
Timing attacks reveal valid accounts — Response time differences can leak whether a username exists. Look for statistical outliers.
AI assistants need context — Claude refused to help with credential testing until it understood the legitimate CTF context. Be prepared to explain your use case.
Acknowledgments
Thanks to Bozidar Spirovski and BeyondMachines for creating an excellent challenge that covered real-world security concepts while keeping things fun. The Alastair Reynolds theming was a delightful touch — I'll never look at lighthugger names the same way again.
If you enjoyed this writeup, check out the BeyondMachines training platform for more security challenges.