Skip to content

This tool is not affiliated with, endorsed by or sponsored by Microsoft Corporation. Azure, Microsoft Azure and Microsoft Defender for Cloud are trademarks of the Microsoft group of companies. Other names are trademarks of their respective owners.

Azure Storage data exfiltration: SAS tokens and blob logs

Investigate Azure Storage data exfiltration: listAccountSas and listKeys in the Activity Log, GetBlob bursts in blob logs, SAS token hashes, what to rotate.

Published on 5 min read

TL;DR. Storage exfiltration leaves two kinds of traces. In the Activity Log: listKeys/action, listAccountSas/action, listServiceSas/action, and configuration changes that open the account (allowBlobPublicAccess: true, firewall defaultAction: Allow). In the storage resource logs (StorageRead / StorageBlobLogs, only if enabled): GetBlob requests with the caller IP, the authentication type, a hash of the SAS or token, the object key and the bytes returned. A SAS signed client-side with an account key is never logged at creation; you only see it when it is used. Rotating both account keys revokes account and service SAS.

The storage account is where the data is. The investigation question after a cloud compromise is almost always "what did they take?", and for blob storage that question is answerable — if the right diagnostic setting existed.

How attackers get to the data

PathControl-plane trace (Activity Log)Data-plane trace (storage log)
Read the account keys, sign their own SAS offlineMicrosoft.Storage/storageAccounts/listKeys/actionGetBlob with SAS or AccountKey authentication
Ask Azure Resource Manager to mint an account or service SASlistAccountSas/action / listServiceSas/actionGetBlob with SAS authentication, statusText SASSuccess
Use an Entra identity with a data role (Storage Blob Data Reader…)Possibly a roleAssignments/write firstGetBlob with OAuth, requester object ID
Make a container publicstorageAccounts/write or containers/write with public accessGetBlob with Anonymous
Open the storage firewallstorageAccounts/write with defaultAction: Allow or public network access enabledRequests from IPs that were blocked before

MITRE ATT&CK tracks the collection as T1530 Data from Cloud Storage. Storm-0501, as documented by Microsoft Threat Intelligence, used listkeys/action and exfiltrated with AzCopy before mass-deleting storage accounts.

The SAS problem: creation is invisible

A shared access signature is a signed URL. Microsoft's documentation is blunt: "It's not possible to audit the generation of SAS tokens", and a SAS token "is not tracked by Azure Storage in any way" (SAS overview). A SAS signed locally with an account key produces no event at all. What you can see:

  • listKeys/action — someone retrieved the keys (and could sign unlimited SAS offline).
  • listAccountSas/action / listServiceSas/action — someone asked ARM to sign one. The request body shows the requested services, permissions, start and expiry.
  • Every use of a SAS, in the storage resource logs, if enabled.

Microsoft's recommendation to disallow Shared Key authorization on accounts that do not need it removes the whole class: without Shared Key, account and service SAS stop working.

Reading StorageBlobLogs

The Blob Storage monitoring reference documents the fields. The ones that matter for exfiltration:

Field (storage export)ExampleWhy
operationNameGetBlob, ListBlobs, PutBlob, DeleteBlobWhat happened
callerIpAddress203.0.113.66:51234Where from (note the port suffix)
identity.typeSAS, AccountKey, OAuth, AnonymousHow the request was authorized
identity.tokenHashkey1(…),SasSignature(…)Which key signed the SAS, and a SHA-256 of the SAS itself
identity.requester.objectIdGUIDThe Entra identity, for OAuth
properties.objectKey/account/container/blobWhich blob
properties.responseBodySizebytesHow much left
properties.userAgentHeaderAzCopy/10.x …Which tool
statusCode / statusText200 / SASSuccessSuccess or failure

The SasSignature(…) hash is your pivot: every request with the same hash used the same SAS token, whoever held it. The analyzer uses it as the principal for SAS access (shown as sas:<hash prefix>), so one leaked SAS appears as one entity with its IPs and total bytes.

Storage logs are voluminous. The analyzer keeps routine reads out of the events table but still counts and evaluates every one of them.

What the analyzer flags

RuleDetectsLevel
AZ-ST-001Account or service SAS generated through ARM (listAccountSas, listServiceSas)High
AZ-ST-002Account keys listed or regeneratedLow
AZ-ST-003Anonymous blob access enabled on the account or a containerHigh
AZ-ST-004Storage firewall opened to all networksMedium
AZ-ST-005Bulk download: at least 50 distinct blobs read by the same identity from the same IP within 60 minutes, with total bytesHigh
AZ-ST-006Anonymous blob readsMedium
AZ-VM-005Disk or snapshot exported with a SAS URLHigh

AZ-ST-002 is low on purpose: the portal's storage browser, Function Apps and backup tools list keys all the time. It becomes interesting next to other findings.

Sizing the exposure

Breach-notification work needs facts, not "the attacker had access to the account". Build them from the logs:

  1. List the blobs read by the suspicious principal / SAS hash / IP: object keys, sizes, timestamps. The Azure Forensics analyzer groups them per identity, IP and account, with the byte total.
  2. Separate reads from listings. ListBlobs reveals names; GetBlob reveals content.
  3. Check partial reads. A downloadRange field means only part of the blob was transferred.
  4. Check writes and deletes (StorageWrite, StorageDelete): ransomware-style actors delete after copying.
  5. Check the other services. Blob logs do not cover Files, Queues or Tables; each has its own log categories.

For example, in the site's fictional sample, one SAS used from one IP reads 330 distinct backup blobs in 18 minutes, about 48.6 GB in total. That number, per container, is what legal teams need.

Remediation

  • Rotate both storage account keys. Microsoft documents that account and service SAS are signed with the account key, so regenerating the key invalidates them. User delegation SAS are revoked by revoking user delegation keys.
  • Disable anonymous access and restore the firewall (default action Deny, private endpoints).
  • Consider disallowing Shared Key authorization.
  • Enable StorageRead / StorageWrite / StorageDelete on the blob service of sensitive accounts, now.
  • Establish what data was read, for notification obligations (for example the GDPR's 72-hour notification to the supervisory authority, Article 33).

Related articles

NSG and VNet flow logs analysis for incident response: tuple formats, bytes and flow states, spotting exfiltration, mining and attacker IPs, blind spots.
How attackers abuse Azure service principals and managed identities: leaked secrets, IMDS token theft, federated credentials, runbooks, and the log signals.
Deleted diagnostic settings, removed Activity Log export, Defender plans set to Free, locks and NSG rules: spotting Azure defense evasion, and what survives.

This tool is not affiliated with, endorsed by or sponsored by Microsoft Corporation. Azure, Microsoft Azure and Microsoft Defender for Cloud are trademarks of the Microsoft group of companies. Other names are trademarks of their respective owners.