Introduction

Blob Storage Challenge in the Neighborhood

Difficulty:
Help the Goose Grace near the pond find which Azure Storage account has been misconfigured to allow public blob access by analyzing the export file.

Grace the Goose is over by the frozen lake with a cranberry-pi:

image-20251107105534096
Grace

Grace

HONK!!! HONK!!!!

The Neighborhood HOA uses Azure storage accounts for various IT operations.

You’ve been asked to audit their storage security configuration to ensure no sensitive data is publicly accessible.

Recent security reports suggest some storage accounts might have public blob access enabled, creating potential data exposure risks.

The Storage Secrets terminal opens up a terminal with two panes. The top pane has instructions, and the bottom a place to interact:

image-20251107105743415

Solution

Background

Azure Blob Storage is Microsoft’s object storage solution, similar to AWS S3. The hierarchy works like this:

  • Subscription - The billing/management boundary
  • Resource Group - A logical container for related resources
  • Storage Account - A namespace for storage services (blobs, files, queues, tables)
  • Container - Similar to a folder, holds blobs
  • Blob - The actual file/object

A critical security setting is allowBlobPublicAccess at the storage account level. When enabled, individual containers can be configured to allow anonymous access - meaning anyone on the internet can read the files without authentication.

#1

You may not know this but the Azure cli help messages are very easy to access. First, try typing: $ az help | less

To complete this, I just need to run the given command, az help | less. az is the command line tool for interactign with Azure cloud. This opens the help output:

image-20251107105942599

#2

Next, you’ve already been configured with credentials. 🔑

$ az account show \| less

  • Pipe the output to | less so you can scroll.
  • Press ‘q’ to exit less.

Running the given command (minus the less, not needed here) shows the user I’m logged in as:

neighbor@2f4d0caec829:~$ az account show
{
  "environmentName": "AzureCloud",
  "id": "2b0942f3-9bca-484b-a508-abdae2db5e64",
  "isDefault": true,
  "name": "theneighborhood-sub",
  "state": "Enabled",
  "tenantId": "90a38eda-4006-4dd5-924c-6ca55cacc14d",
  "user": {
    "name": "theneighborhood@theneighborhood.invalid",
    "type": "user"
  }
}

I’m running as theneighborhood@theneighborhood.invalid. This data is also cached in the .azure directory in the current user’s home directory:

neighbor@2f4d0caec829:~$ cat .azure/azureProfile.json 
{
  "subscriptions": [
    {
      "id": "2b0942f3-9bca-484b-a508-abdae2db5e64",
      "name": "theneighborhood-sub",
      "state": "Enabled",
      "user": {
        "name": "theneighborhood@theneighborhood.invalid",
        "type": "user"
      },
      "isDefault": true,
      "tenantId": "90a38eda-4006-4dd5-924c-6ca55cacc14d",
      "environmentName": "AzureCloud"
    }
  ],
  "installationId": "1de3b9db-5e5b-48a5-81e5-7eafe2d2bace"

If I move that file, I’m no longer logged in:

neighbor@2f4d0caec829:~$ mv .azure/azureProfile.json{,.bk} 
neighbor@2f4d0caec829:~$ az account show
Please run 'az login' to setup account.
neighbor@2f4d0caec829:~$ mv .azure/azureProfile.json{.bk,}

#3

Now that you’ve run a few commands, Let’s take a look at some Azure storage accounts. Try: az storage account list | less For more information: https://learn.microsoft.com/en-us/cli/azure/storage/account?view=azure-cli-latest

A storage account is Azure’s top-level namespace for data storage. Each account can contain multiple containers, and each container holds blobs (files). The id field in the output shows the full Azure Resource Manager (ARM) path: subscription → resource group → provider → resource.

This command outputs a lot of data. I’ll use jq to parse the JSON data and show bits at a time. It’s a list with 6 items:

neighbor@2f4d0caec829:~$ az storage account list | jq '.|length'
6

For example, the first one looks like:

neighbor@2f4d0caec829:~$ az storage account list | jq .[0]
{
  "id": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/theneighborhood-rg1/providers/Microsoft.Storage/storageAccounts/neighborhood1",
  "kind": "StorageV2",
  "location": "eastus",
  "name": "neighborhood1",
  "properties": {
    "accessTier": "Hot",
    "allowBlobPublicAccess": false,
    "encryption": {
      "keySource": "Microsoft.Storage",
      "services": {
        "blob": {
          "enabled": true
        }
      }
    },
    "minimumTlsVersion": "TLS1_2"
  },
  "resourceGroup": "theneighborhood-rg1",
  "sku": {
    "name": "Standard_LRS"
  },
  "tags": {
    "env": "dev"
  }
}

They have names neighborhood1 - neighborhood6:

neighbor@2f4d0caec829:~$ az storage account list | jq -r .[].name
neighborhood1
neighborhood2
neighborhood3
neighborhood4
neighborhood5
neighborhood6

Looking at the properties of each account, the second one jumps out as potentially having a security issue:

neighbor@38c41877bb80:~$ az storage account list | jq '.[1]'
{
  "id": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/theneighborhood-rg1/providers/Microsoft.Storage/storageAccounts/neighborhood2",
  "kind": "StorageV2",
  "location": "eastus2",
  "name": "neighborhood2",
  "properties": {
    "accessTier": "Cool",
    "allowBlobPublicAccess": true,
    "encryption": {
      "keySource": "Microsoft.Storage",
      "services": {
        "blob": {
          "enabled": false
        }
      }
    },
    "minimumTlsVersion": "TLS1_0"
  },
  "resourceGroup": "theneighborhood-rg1",
  "sku": {
    "name": "Standard_GRS"
  },
  "tags": {
    "owner": "Admin"
  }
}

allowBlobPublicAccess is set to true. This could be ok if it is meant to host files for the public, but it’s worth investigating further.

#4

hmm… one of these looks suspicious 🚨, i think there may be a misconfiguration here somewhere. Try showing the account that has a common misconfiguration: az storage account show --name xxxxxxxxxx | less

Running az storage account show --name neighborhood2 shows the same information, but it does show the challenge that I’m focused on the correct account:

neighbor@38c41877bb80:~$ az storage account show --name neighborhood2
{
  "id": "/subscriptions/2b0942f3-9bca-484b-a508-abdae2db5e64/resourceGroups/theneighborhood-rg1/providers/Microsoft.Storage/storageAccounts/neighborhood2",
  "name": "neighborhood2",
  "location": "eastus2",
  "kind": "StorageV2",
  "sku": {
    "name": "Standard_GRS"
  },
  "properties": {
    "accessTier": "Cool",
    "allowBlobPublicAccess": true,
    "minimumTlsVersion": "TLS1_0",
    "encryption": {
      "services": {
        "blob": {
          "enabled": false
        }
      },
      "keySource": "Microsoft.Storage"
    }
  },
  "resourceGroup": "theneighborhood-rg1",
  "tags": {
    "owner": "Admin"
  }
}

#5

Now we need to list containers in neighborhood2. After running the command what’s interesting in the list? For more information: https://learn.microsoft.com/en-us/cli/azure/storage/container?view=azure-cli-latest#az-storage-container-list

I’ll run the az storage container list command with the --account-name flag to get containers associated with this account:

neighbor@38c41877bb80:~$ az storage container list --account-name neighborhood2
[
  {
    "name": "public",
    "properties": {
      "lastModified": "2024-01-15T09:00:00Z",
      "publicAccess": "Blob"
    }
  },
  {
    "name": "private",
    "properties": {
      "lastModified": "2024-02-05T11:12:00Z",
      "publicAccess": null
    }
  }
]

There are two containers. The publicAccess property controls anonymous access:

  • "Blob" - Anyone can read blobs if they know the URL (but can’t list the container)
  • "Container" - Anyone can list and read all blobs
  • null - No anonymous access (authentication required)

The “public” container with publicAccess: "Blob" means files are accessible to anyone who knows the URL.

#6

Let’s take a look at the blob list in the public container for neighborhood2. For more information: https://learn.microsoft.com/en-us/cli/azure/storage/blob?view=azure-cli-latest#az-storage-blob-list

I’ll give the az storage blob list command both the container name and the account name:

neighbor@38c41877bb80:~$ az storage blob list --container-name public --account-name neighborhood2
[
  {
    "name": "refrigerator_inventory.pdf",
    "properties": {
      "contentLength": 45678,
      "contentType": "application/pdf",
      "metadata": {
        "created_by": "NeighborhoodWatch",
        "document_type": "inventory",
        "last_updated": "2024-12-15"
      }
    }
  },
  {
    "name": "admin_credentials.txt",
    "properties": {
      "contentLength": 1024,
      "contentType": "text/plain",
      "metadata": {
        "note": "admins only"
      }
    }
  },
  {
    "name": "network_config.json",
    "properties": {
      "contentLength": 2048,
      "contentType": "application/json",
      "metadata": {
        "encrypted": "false",
        "environment": "prod"
      }
    }
  }
]

There are three files. Two of these (admin_credentials.txt and network_config.json) clearly shouldn’t be in a publicly accessible container. This is exactly the kind of misconfiguration that leads to data breaches.

#7

Try downloading and viewing the blob file named admin_credentials.txt from the public container. 💡 hint: --file /dev/stdout should print in the terminal. Dont forget to use | less!

The documentation for az shows a download command:

neighbor@38c41877bb80:~$ az storage blob download -c public -n admin_credentials.txt --file /dev/stdout 
                                          
# You have discovered an Azure Storage account with "allowBlobPublicAccess": true.
# This misconfiguration allows ANYONE on the internet to view and download files
# from the blob container without authentication.
                                          
# Public blob access is highly insecure when sensitive data (like admin credentials) 
# is stored in these containers. Always disable public access unless absolutely required.

Azure Portal Credentials    
User: azureadmin
Pass: AzUR3!P@ssw0rd#2025 

Windows Server Credentials
User: administrator
Pass: W1nD0ws$Srv!@42  
                                          
SQL Server Credentials
User: sa
Pass: SqL!P@55#2025$

Active Directory Domain Admin
User: corp\administrator
Pass: D0m@in#Adm!n$765

Exchange Admin Credentials
User: exchangeadmin
Pass: Exch@ng3!M@il#432

VMware vSphere Credentials
User: vsphereadmin
Pass: VMW@r3#Clu$ter!99

Network Switch Credentials
User: netadmin
Pass: N3t!Sw!tch$C0nfig#

Firewall Admin Credentials
User: fwadmin
Pass: F1r3W@ll#S3cur3!77

Backup Server Credentials
User: backupadmin
Pass: B@ckUp!Srv#2025$

Monitoring System Admin
User: monitoradmin
Pass: M0n!t0r#Sys$P@ss!

SharePoint Admin Credentials
User: spadmin
Pass: Sh@r3P0!nt#Adm!n2025

Git Server Admin
User: gitadmin
Pass: G1t#Srv!Rep0$C0de

That’s a lot of passwords!

Outro

On completing question 7, the banner says:

🎊 Great, you found the misconfiguration allowing public access to sensitive information!

✅ Challenge Complete! To finish, type: finish

Running finish completes the challenge.

Storage Secrets

Congratulations! You have completed the Storage Secrets challenge!

Grace seems annoyed in a goose-like manner:

Grace

Grace

HONK HONK HONK! ‘No sensitive data publicly accessible’ they claimed. Meanwhile, literally everything was public! Good save, security expert!