August 14, 2026
Hacker Holidays Day 9: CryptoCabana
The setup
By Devyaniitware
3 min read
The setup
Day 9 moves to a completely different cloud platform — Azure instead of AWS. "CryptoCabana" is a beachside kiosk that promises to back up your crypto wallet's seed phrase "to your own private vault… never stored on your device, never shared." Naturally, that promise doesn't hold.
What's expected: find what the kiosk trusts automatically before you've clicked anything, follow that trust somewhere the kiosk's own page never points you, and recover a flag from a vault that "won't give up the real values on the first ask."
Quick definitions before we start
- SAS token (Shared Access Signature) — Azure's version of a temporary access credential for storage. It can be scoped to specific permissions (read, write, list, etc.) and given an expiry date, but if it's issued with more permissions than the app actually uses, anyone who gets hold of it can use those extra permissions too.
- Azure Key Vault — a dedicated Azure service for storing secrets (passwords, keys, certificates) securely, separate from regular storage. Access is controlled independently, often via a service principal.
- Service principal — essentially an application's own login identity in Azure — a client ID, client secret, and tenant ID that let a script or service authenticate without a human logging in.
- Secret versioning — Key Vault keeps a full history of every value a secret has ever had. "Rotating" a secret (replacing it with a new value) doesn't erase the old version — it just adds a new "current" version on top, and old versions often remain readable.
How I started
Viewing the site's app.js directly revealed everything the "kiosk" needed to function, sitting in plain text: a storage account name, a container name, and a SAS token — used only to PUT (upload) a new backup file.
Decoding the SAS token's query string showed sp=rl — read and list permissions — even though the app itself only ever wrote data. That mismatch was the whole vulnerability.
My thinking process
Since the token allowed reading and listing, not just writing, I asked Azure for things the app never intended to show me:
- Listed the "backups" container — empty (nobody's own request had used it yet in my session).
- Listed the entire storage account (a service-level list, not scoped to one container) — revealed containers the site never mentioned:
$web,backups, and a suspicious third one,vault. - Listed the vault container — found two files:
seed_phrase.txt(flavor text, matching the victim's story) andbackup-service-account.json— a genuine Azure service principal: client ID, client secret, tenant ID, plus the name and URL of an actual Key Vault.
That JSON file explicitly warned: "Rotate this if it ever leaves the vault." Ironic, given it just had.
Using the Azure CLI (had to switch to Azure Cloud Shell after the AttackBox's local az install turned out to be broken), I logged in as this leaked service principal and listed the Key Vault's secrets: three "key-shard" pieces and a master-key.
Two details stood out immediately:
master-keyhad an expired date years in the past.- Its
createdandupdatedtimestamps didn't match — someone had modified it after creation, i.e. rotated it.
First dead end: I assumed the master-key was the rotated secret hiding the real data, and checked its version history — only one version existed. No older value to recover there.
Reconsidering: two of the three key shards fetched cleanly and formed the start and end of the flag (THM{n0t_ur ... ur_c01ns!}), but the middle piece — key-shard-2 — didn't look like flag data at all. Its current value was a note: "Rotated this after IT flagged it — old value should still be recoverable if you know where to look." That was the real clue — it was describing itself, not master-key.
Checking key-shard-2's own version history (not master-key's) showed two versions. Fetching the older one gave the real missing piece.
Getting the flag
Assembling all three shards — two fetched normally, the middle one recovered from its older version — completed the flag.
A fitting nod to the well-known crypto phrase "not your keys, not your coins."
The big takeaway
Temporary or scoped credentials should only ever grant the exact permissions actually needed — nothing more. This SAS token was meant for one narrow purpose (uploading a backup) but was issued with read and list access too, which is what let the app's entire hidden structure be discovered. Separately: rotating a secret doesn't erase its history — if old versions remain readable, "rotating" a leaked secret only helps if access to its past versions is also revoked, not just adding a new value on top.
Next up: Day 10, The Hollow Shell, where a file upload feature turned into a full working exploit only after a string of dead ends: ImageTragick, XXE, and a Zip Slip write primitive that kept getting blocked by template caching.
No version history to dig through here — my LinkedIn and GitHub are current and out in the open.