Query Details
// Hunt : Hunt - Storage Anonymous and SAS-Token Access Timeline (90 Days)
// Tactics : Collection, Exfiltration
// MITRE : T1530
// Purpose : Surface the full timeline of anonymous and SAS-authenticated access to Storage Blobs from public IPs over 90 days. Use to baseline normal patterns, confirm Rule-13 alerts, and identify persistent low-and-slow exfiltration that stays under the hourly threshold.
//==========================================================================================
let PrivateRanges = dynamic(["10.", "172.16.", "172.17.", "172.18.", "172.19.", "172.20.",
"172.21.", "172.22.", "172.23.", "172.24.", "172.25.", "172.26.", "172.27.", "172.28.",
"172.29.", "172.30.", "172.31.", "192.168.", "168.63.", "169.254."]);
StorageBlobLogs
| where TimeGenerated > ago(90d)
| where AuthenticationType in~ ("Anonymous", "SasToken")
| where StatusCode == 200
| where isnotempty(CallerIpAddress)
| where not(CallerIpAddress has_any (PrivateRanges))
| summarize
AccessCount = count(),
DistinctBlobs = dcount(ObjectKey),
DistinctContainers = dcount(tostring(split(ObjectKey, "/")[0])),
TotalBytesGB = round(sum(ResponseBodySize) / 1073741824.0, 3),
Operations = make_set(OperationName, 5),
EarliestAccess = min(TimeGenerated),
LatestAccess = max(TimeGenerated)
by CallerIpAddress, AuthenticationType, AccountName, bin(TimeGenerated, 1d)
| order by TotalBytesGB desc, AccessCount desc
This query is designed to analyze and summarize access patterns to storage blobs over the past 90 days, focusing specifically on anonymous and SAS-token authenticated access from public IP addresses. Here's a breakdown of what the query does:
Private IP Filtering: It defines a list of private IP address ranges and filters out any access logs that originate from these private IPs, focusing only on public IP addresses.
Data Source: The query pulls data from StorageBlobLogs, which contains logs of access to storage blobs.
Time Frame: It considers logs generated in the last 90 days.
Authentication Type: It filters for access that was authenticated using either "Anonymous" or "SasToken".
Successful Access: It only includes logs where the access was successful (HTTP status code 200).
Data Aggregation: For each combination of public IP address, authentication type, storage account name, and each day:
AccessCount).DistinctBlobs).DistinctContainers).TotalBytesGB).Operations).Sorting: The results are sorted by the total data accessed in gigabytes and then by the number of access attempts, both in descending order.
The purpose of this query is to establish a baseline of normal access patterns, confirm alerts from a specific rule (Rule-13), and detect any ongoing, subtle data exfiltration activities that might not trigger hourly alerts due to their low and slow nature.

David Alonso
Released: March 12, 2026
Tables
Keywords
Operators