A ransomware gang called pantalones forgot to delete their exfil script before zipping the victim data. That one mistake unravelled everything — their backend panel URL, their API key, and eventually their own admin credentials. This is how we turned the hunters into the hunted.
Flare, SANS, and WiCyS ran a beginner-friendly browser-based CTF across three days. The premise: a careless ransomware collective called pantalones got sloppy. Our job was to trace their OPSEC failures and expose their infrastructure. No Kali, no paid tools — just a Tor Browser and the willingness to read carefully.
The challenge was framed as three phases: forensics, exploitation, and decoding. That framing was accurate. Each phase fed into the next.
Navigated to the provided onion address. Found a ransomware leak site with six victims: four on countdown timers, two already marked LEAKED (QuantumCore and AetherFlow). Checked page source immediately — found a base64 comment and three nav pages (index, crew, about).
HTML comment: bm90X3RoZV9mbGFnX2tlZXBfbG9va2luZw== decodes to not_the_flag_keep_looking. Noted and moved on.
/robots.txt disallowed two paths: /api.php and /admin.php. Both returned 404 on plain GET — filed for later.
Browsed /downloads/aetherflow/. Downloaded aetherflow_leak.zip. Inside: four files, including a hidden dotfile .exfil.sh — the gang's own upload script, accidentally packaged. The TODO comment at the bottom said it all: delete this before zipping.
The script contained the gang's backend panel onion URL and API key. Routed curl through Tor Browser's SOCKS5 proxy (port 9150) and hit /api.php with the key. Got back a full action menu.
Enumerated action=messages with sequential conversation_id values. In conversation 2: crypt sent mora her own password "encoded" in base64. UGFudGFsMG4zc19SdWwzeiE= → Pantal0n3s_Rul3z!
POST to /admin.php with username=mora&password=Pantal0n3s_Rul3z!. Dashboard loaded. Flag sitting in the decryption key column, styled in CSS rainbow animation.
The leak site ran on PHP (every page ended in .php). That detail matters: PHP backends on a CTF site usually mean there's something to interact with, something beyond static content. The nav had three pages — Leaks, Crew, About — and the page source for the index had everything rendered client-side via a JavaScript array. No server-side rendering meant the full victim data, including browse/download paths, was visible in source without any auth.
Classic CTF misdirection. The comment is there to catch people who stop at the first encoded string they find. Noted the download paths for both leaked victims and moved on.
Two endpoints the gang tried to hide. Both 404'd on bare GET requests — no login form visible, no response. Filed. The backend must need something we didn't have yet.
QuantumCore's directory contained three files: employee records (SHA-256 hashed SSNs, bcrypt-hashed service account credentials), financial transactions, and internal Slack-style communications. The comms file had a moment worth flagging:
Ian McCarthy (IT Director) sent a private message to the wrong channel at 16:30, immediately followed by a genuine incident alert. Sloppy, but not the flag. The real OPSEC failure was coming from the AetherFlow side.
The AetherFlow directory contained a zip. Inside the zip, alongside the expected victim data,
was a hidden dotfile: .exfil.sh.
This was the gang's own data exfiltration script — written by vex, dated May 30.
The last line of the script:
# TODO: delete this before zipping
This gave us everything we needed for phase two: the backend panel URL, the API key format, and the endpoint structure. Note the panel onion was different from the public leak site — a separate hidden server.
Tor Browser exposes a SOCKS5 proxy on localhost port 9150. We can route any curl request through it to resolve .onion addresses:
The API was live on the main leak site — not the downed panel onion from the script.
The messages action
stood out immediately. Ransomware gang crew chat, accessible with a hardcoded API key.
The messages endpoint needed a conversation_id.
Tried sequential integers starting from 0.
Conversations 0–4 all returned crew discussions. Conversation 3 was the most satisfying:
Conversation 2 contained the credential we needed. mora had lost her FTP password after a machine reset and asked crypt for it. Crypt, apparently irritated by the recurring request, "encoded" it:
Base64 is an encoding scheme, not encryption. It provides zero confidentiality. Mora's note that nobody had cracked it since 2011 is technically true — because there was nothing to crack. Anyone who reads the chat can decode it in two seconds.
We now had a username (mora, from the crew page) and her password.
The /admin.php endpoint
had shown a 404 on GET but earlier testing with POST and the API key had returned
an HTML login form. We sent the credentials:
The panel dashboard listed all six victims with their ransom amounts, status, and decryption keys. The Sisterhood of the Travelling Packets entry — the CTF organisers themselves, listed as victims of the gang they'd built — had the flag as the decryption key, rendered in a rainbow CSS animation.
The challenge was explicitly framed around a sloppy gang's failures. Here's the full list, in the order we exploited them:
vex packaged his own exfil script alongside the victim data. It contained the backend panel URL, the API key, and the endpoint structure. The TODO comment confirmed he knew it should be deleted. This was the initial pivot point for everything that followed.
pantalonesgroup was baked into the script in plaintext. Even if the script hadn't been leaked, storing credentials in scripts rather than environment variables is unsafe practice.
The X-Panel-Key was a single shared secret with no per-user identity, no rate limiting, and no logging beyond chat references. Once we had the key, we had full API access. vex's reasoning: "it's behind Tor, who cares." Obscurity is not a control.
Sharing passwords in team messaging — even encoded ones — means every chat log is a credential store. crypt called this out explicitly. mora's response was that the password hadn't been cracked since 2011. Base64 isn't a cracking problem; it's a reading problem.
UGFudGFsMG4zc19SdWwzeiE= is not encrypted. Base64 is a reversible encoding with no key. Anyone with the encoded string can decode it in two seconds. This is a recurring misconception worth calling out explicitly.
When crypt detected us enumerating the chat logs at 4 AM, he told vex to rotate the panel key immediately. vex said he'd do it in the morning. By then we had the flag. Incident response doesn't have business hours.
This challenge was a well-constructed beginner introduction to the real shape of threat actor OPSEC failures. Real ransomware groups make exactly these mistakes: credentials in scripts, scripts in archives, passwords in chat, delayed incident response.
Get-ChildItem -Force on Windows, ls -la on Linux. Dotfiles don't show by default.conversation_id starting from 0 yielded the gang's entire internal history.