CryptoCabana Kiosk — Cloud CTF Writeup (Spoiler-Free)
Category: Cloud (Azure)
Difficulty: Medium
Points: 90
Tools used: Azure Cloud Shell (bash), curl, jq, Azure CLI (az)
Scenario
CryptoCabana is a kiosk web app that lets visitors "back up" their crypto wallet seed phrase with one click, promising "Backed up. Sleep easy." The objective: find out what the kiosk is quietly trusting to reach into storage on its own, and see how far that trust actually extends.
Methodology
1. Client-side recon
Visited the site and pulled the page source before interacting with the UI. It's a static single-page app hosted on Azure Blob Storage's static website feature (<account>.z13.web.core.windows.net).
Fetching the referenced JavaScript revealed a hardcoded SAS (Shared Access Signature) token used to write backups directly to blob storage from the browser.
Finding: a SAS token shipped to every visitor's browser. Decoding the parameters showed the real problem wasn't the intended use case (writing a backup blob) — it was scope:
| Param | Meaning |
|---|---|
ss=b |
Blob service |
srt=sco |
Service + Container + Object — account-wide, not scoped to one container |
sp=rl |
Read + List |
se=2099-... |
Effectively never expires |
A token meant for "drop a file in backups" was actually valid for listing and reading the entire storage account.
2. Storage account enumeration
Anonymous account-level listing is never possible in Azure Blob Storage regardless of configuration — that call always returns ResourceNotFound.
But a service-scoped SAS token changes that. Appending the leaked token to a service-level "list containers" request revealed every container in the account, including one whose name suggested it held something more valuable than backups.
3. Discovering the second container
Listing that container's contents (same SAS, container-scoped) revealed two blobs:
- A decoy file, matching the theme of the app (a fake seed phrase).
- A JSON credential file for a service principal — including a
key_vault_nameandkey_vault_uripointing to a real Azure Key Vault, with a note from "IT" about rotating it if it ever leaked.
This was the pivot from "storage account" to "real Azure Key Vault."
4. Authenticating to Azure AD and enumerating the Key Vault
Used az login --service-principal with the leaked client_id / client_secret / tenant_id, then listed secrets in the vault.
Four secrets were present, structured as shards of a larger value, plus one long-expired secret (expiry date in the past — Key Vault refuses to hand back an expired secret's current value on a plain "get").
5. The decoy: a rotated secret
Most shards returned clean data. One shard's current value, however, wasn't a data fragment — it was a note explaining that the secret had been rotated after "IT flagged it," with a hint that the old value was still recoverable.
Key Vault keeps prior versions of a secret unless they're explicitly disabled or purged. Listing the version history for that secret and pulling the original (pre-rotation) version recovered the real fragment.
6. Assembling the flag
Concatenating the shards (using the recovered pre-rotation value for the middle one) produced the final flag — a well-known crypto adage, formatted as THM{...}.
Key takeaways
- Client-side secrets are public secrets. Anything shipped in JS served to a browser must be treated as fully exposed. SAS tokens embedded client-side should be scoped as narrowly as possible: single container (
srt=co, notsco), minimum permissions (write-only for a backup flow, not read+list), and short expiry (minutes to hours, not decades). - Secret sprawl compounds. One over-scoped SAS token led to an account-wide enumeration, which led to a service principal credential, which led to a full Key Vault. Each layer should be independently access-controlled so a leak in one doesn't cascade.
- Rotation isn't deletion. Rotating a secret's value in Key Vault leaves prior versions retrievable unless you explicitly disable or purge them. If a secret is known to have leaked, rotating it is necessary but not sufficient — old versions need to be disabled too.
- Detection angles for a SOC: Storage Account diagnostic logs would show anonymous/SAS-authenticated requests to
?comp=listat the service level — a rare and suspicious call pattern worth alerting on. Azure AD sign-in logs would show the service principal authenticating from an unexpected source. Key Vault diagnostic logs would showSecretGetandSecretListVersionscalls shortly after the credential was first used — a useful correlation chain to hunt on.