Azure Storage Anonymous Blob Access to Unusual Resource

Identifies the first time an Azure Storage resource receives an anonymous data-plane read (GetBlob and related Get or List operations). Anonymous requests are used to probe public containers and to test stolen blob URLs before a SAS is appended. First-seen resource ID keeps volume down while still covering WireServer-related probes of status or extension blobs.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2026/08/17"
  3integration = ["azure"]
  4maturity = "production"
  5updated_date = "2026/08/17"
  6
  7[rule]
  8author = ["Elastic"]
  9description = """
 10Identifies the first time an Azure Storage resource receives an anonymous data-plane read (GetBlob and related Get or
 11List operations). Anonymous requests are used to probe public containers and to test stolen blob URLs before a SAS is
 12appended. First-seen resource ID keeps volume down while still covering WireServer-related probes of status or extension
 13blobs.
 14"""
 15false_positives = [
 16    """
 17    Intentionally public containers (static websites, public datasets) generate anonymous GetBlob and ListBlobs.
 18    Baseline those storage accounts and exclude `azure.resource.id` after review.
 19    """,
 20    """
 21    Internet-wide scanners will produce first-seen anonymous access on newly created or newly logged accounts. Confirm
 22    whether the account is meant to be public.
 23    """,
 24]
 25from = "now-9m"
 26index = ["logs-azure.platformlogs-*"]
 27language = "kuery"
 28license = "Elastic License v2"
 29name = "Azure Storage Anonymous Blob Access to Unusual Resource"
 30note = """## Triage and analysis
 31
 32### Investigating Azure Storage Anonymous Blob Access to Unusual Resource
 33
 34StorageRead platform logs record `AuthenticationType` as Anonymous when no SAS, OAuth, or account key is presented.
 35A first-seen `azure.resource.id` (typically the blob service
 36`/subscriptions/.../storageAccounts/<account>/blobServices/default`) means this resource has not had anonymous Get or
 37List traffic in the history window.
 38
 39WireServer SAS-replay chains often start with an anonymous GetBlob (HTTP 409/403) against the same object, then a
 40SAS 200. This rule does not require guest-agent path strings; those lab container names are not production
 41observables.
 42
 43`source.ip` is often empty. Use `source.address` (`ip:port`).
 44
 45### Possible investigation steps
 46
 47- Review `event.action`, `azure.platformlogs.statusCode`, and `azure.platformlogs.uri`.
 48- HTTP 200 with Anonymous means the container or blob is publicly readable. HTTP 409/403 is a probe.
 49- Identify the account from `azure.resource.id` / `azure.resource.name` and check whether public access is intended.
 50- Search for SAS-authenticated GetBlob to the same account from the same source shortly after.
 51- If the URI contains `/$system/` or `md-hdd-`, correlate with WireServer access on VMs in the subscription.
 52
 53### False positive analysis
 54
 55- Public blob websites and CDN origins. Exclude the `azure.resource.id` for approved public accounts.
 56- New accounts that enable StorageRead for the first time will alert on the first scanner hit.
 57
 58### Response and remediation
 59
 60- Disable anonymous public access on accounts that should be private.
 61- If a follow-on SAS read exists, revoke that SAS and review how the URL was obtained.
 62- Keep StorageRead diagnostic logs enabled on storage accounts of interest.
 63"""
 64references = [
 65    "https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/storagebloblogs",
 66    "https://learn.microsoft.com/en-us/azure/storage/blobs/anonymous-read-access-prevent",
 67    "https://cybercx.com.au/blog/azure-ssrf-metadata/",
 68    "https://www.netspi.com/blog/technical-blog/cloud-pentesting/decrypting-vm-extension-settings-with-azure-wireserver/",
 69]
 70risk_score = 47
 71rule_id = "eabaf807-e710-4f0f-8943-8d1b436d834a"
 72setup = """#### Required Azure Storage Diagnostic Logs
 73
 74Enable StorageRead diagnostic logs on Azure Storage Accounts and stream them to the Event Hub used by the Azure
 75integration. Anonymous vs SAS is `azure.platformlogs.identity.type`.
 76"""
 77severity = "medium"
 78tags = [
 79    "Domain: Cloud",
 80    "Data Source: Azure",
 81    "Data Source: Azure Platform Logs",
 82    "Platform: Azure",
 83    "Service: Azure Storage",
 84    "Use Case: Threat Detection",
 85    "Tactic: Discovery",
 86    "Tactic: Collection",
 87    "Resources: Investigation Guide",
 88]
 89timestamp_override = "event.ingested"
 90type = "new_terms"
 91
 92query = '''
 93data_stream.dataset: azure.platformlogs and
 94    azure.platformlogs.identity.type: Anonymous and
 95    event.action: (
 96        GetBlob or GetBlobMetadata or GetBlobProperties or GetBlockList or
 97        GetPageRanges or QueryBlobContents or ListBlobs or
 98        GetContainerProperties or GetContainerMetadata or GetContainerAcl
 99    )
100'''
101
102
103[[rule.threat]]
104framework = "MITRE ATT&CK"
105[[rule.threat.technique]]
106id = "T1580"
107name = "Cloud Infrastructure Discovery"
108reference = "https://attack.mitre.org/techniques/T1580/"
109
110
111[rule.threat.tactic]
112id = "TA0007"
113name = "Discovery"
114reference = "https://attack.mitre.org/tactics/TA0007/"
115[[rule.threat]]
116framework = "MITRE ATT&CK"
117[[rule.threat.technique]]
118id = "T1530"
119name = "Data from Cloud Storage"
120reference = "https://attack.mitre.org/techniques/T1530/"
121
122
123[rule.threat.tactic]
124id = "TA0009"
125name = "Collection"
126reference = "https://attack.mitre.org/tactics/TA0009/"
127
128[rule.new_terms]
129field = "new_terms_fields"
130value = ["azure.resource.id"]
131[[rule.new_terms.history_window_start]]
132field = "history_window_start"
133value = "now-7d"

Triage and analysis

Investigating Azure Storage Anonymous Blob Access to Unusual Resource

StorageRead platform logs record AuthenticationType as Anonymous when no SAS, OAuth, or account key is presented. A first-seen azure.resource.id (typically the blob service /subscriptions/.../storageAccounts/<account>/blobServices/default) means this resource has not had anonymous Get or List traffic in the history window.

WireServer SAS-replay chains often start with an anonymous GetBlob (HTTP 409/403) against the same object, then a SAS 200. This rule does not require guest-agent path strings; those lab container names are not production observables.

source.ip is often empty. Use source.address (ip:port).

Possible investigation steps

  • Review event.action, azure.platformlogs.statusCode, and azure.platformlogs.uri.
  • HTTP 200 with Anonymous means the container or blob is publicly readable. HTTP 409/403 is a probe.
  • Identify the account from azure.resource.id / azure.resource.name and check whether public access is intended.
  • Search for SAS-authenticated GetBlob to the same account from the same source shortly after.
  • If the URI contains /$system/ or md-hdd-, correlate with WireServer access on VMs in the subscription.

False positive analysis

  • Public blob websites and CDN origins. Exclude the azure.resource.id for approved public accounts.
  • New accounts that enable StorageRead for the first time will alert on the first scanner hit.

Response and remediation

  • Disable anonymous public access on accounts that should be private.
  • If a follow-on SAS read exists, revoke that SAS and review how the URL was obtained.
  • Keep StorageRead diagnostic logs enabled on storage accounts of interest.

References

Related rules

to-top