Detecting and Hunting for Cloud Ransomware Part 3: Azure Storage
Alessandra
Rizzo
Mar 10, 2026
Introduction
This is the third in a series of reports covering ransomware detection across major cloud infrastructures. Following our examination of AWS S3 in Part 1 and Google Cloud Storage in Part 2, this report focuses on Azure Storage attack vectors.
Azure Storage has been a widely documented target for threat actors, as demonstrated by financially motivated threat actors like Storm-0501 who have evolved from traditional on-premises endpoint ransomware to cloud-native techniques. Unlike traditional ransomware that deploys malware, cloud-based ransomware leverages native Azure capabilities to rapidly exfiltrate and encrypt data, destroy backups, and render data inaccessible.
This report examines the primary attack vectors based on in-the-wild attacks reported by Microsoft here and here. We will provide detection coverage using Panther's Python detection engine and log analysis, with the corresponding detection logic. The detections referenced in this report are available in the Panther Analysis repository.
Log Source Requirements
Before deploying these detections, ensure proper Azure logging configuration:
Log Source
Log Type (Panther)
Captures
Azure Monitor Activity Logs
Azure.MonitorActivity
Control plane operations: resource management, deletions, role assignments
Azure Storage Account Logs
Azure.MonitorActivity
Data plane operations: PutBlob, DeleteBlob, GetBlobMetadata, CPK errors
Identity operations: sign-ins, role assignments, MFA changes, federation
Enable diagnostic settings for Storage Account Logs and Key Vault Logs, sending to Log Analytics, Event Hubs, or storage accounts. We recommend that all log types should be enabled for critical resources.
Attack Prerequisites
For a successful ransomware attack, an attacker must either find resources with missing security controls or disable these controls themselves.
The table below consolidates preventive controls with their corresponding detection rules.
Control
Purpose
Objective
Panther Detection Rule
Resource Locks
CanNotDelete locks prevent deletion; ReadOnly locks prevent modification. Overrides all user permissions including Owner.
Attacker deletes storage accounts, backups, and key vaults
azure_resource_lock_deleted
Immutability Policies
Time-based retention or legal hold prevents blob modification/deletion. Once locked, cannot be removed or shortened.
Attacker modifies or deletes protected blobs
azure_storage_immutability_policy_deleted
Blob Soft Delete
Retains deleted blobs for configurable period (1-365 days).
Deleted data cannot be recovered
azure_storage_blob_soft_delete_disabled
Blob Versioning
Automatically retains previous blob versions.
Overwrites destroy data permanently
azure_storage_versioning_disabled
Recovery Services Vault Soft Delete
Default 14-day retention for deleted backup data.
Backup destruction is immediate and irreversible
azure_recovery_services_container_deleted
Key Vault Purge Protection
Enforces 7-90 day retention for deleted vaults and keys.
Encryption keys destroyed immediately
azure_keyvault_purge_protection_disabled
Diagnostic Settings
Captures activity logs for detection.
Attack activity goes undetected
azure_diagnostic_settings_deleted
Resource Lock Deletion
Storm-0501 systematically removes resource locks before destroying storage accounts and backups. Resource locks override user permissions, so their deletion is a critical pre-ransomware indicator.
Immutability policies implement Write-Once-Read-Many (WORM) protection. Storm-0501 specifically targets these for deletion before encrypting or destroying data.
Attackers disable recovery features before destruction operations to ensure complete data loss in the victim environment. We can track these suspicious operations with the following rules:
Before attackers can execute ransomware operations against Azure Storage, they typically need to escalate privileges. The following detections identify common privilege escalation techniques that precede storage attacks.
Elevate Access
The Microsoft.Authorization/elevateAccess/action operation grants the caller User Access Administrator role at the root scope (/), providing full control over all Azure subscriptions in the tenant. Storm-0501 leveraged this operation after compromising privileged accounts.
{"operationName": {"value": "Microsoft.Authorization/elevateAccess/action","localizedValue": "Assigns the caller to User Access Administrator role"},"status": {"value": "Succeeded"},"resourceId": "/providers/Microsoft.Authorization","callerIpAddress": "203.0.113.42"}
{"operationName": {"value": "Microsoft.Authorization/elevateAccess/action","localizedValue": "Assigns the caller to User Access Administrator role"},"status": {"value": "Succeeded"},"resourceId": "/providers/Microsoft.Authorization","callerIpAddress": "203.0.113.42"}
{"operationName": {"value": "Microsoft.Authorization/elevateAccess/action","localizedValue": "Assigns the caller to User Access Administrator role"},"status": {"value": "Succeeded"},"resourceId": "/providers/Microsoft.Authorization","callerIpAddress": "203.0.113.42"}
{"operationName": {"value": "Microsoft.Authorization/elevateAccess/action","localizedValue": "Assigns the caller to User Access Administrator role"},"status": {"value": "Succeeded"},"resourceId": "/providers/Microsoft.Authorization","callerIpAddress": "203.0.113.42"}
Attackers could also try to assign privileged roles such as Owner, Contributor, or User Access Administrator to compromised accounts or service principals.
The following section examines ransomware techniques documented in Storm-0501 campaigns and other Azure-targeting threat actors.
Customer-Provided Key (CPK) Encryption
In a technique mirroring the SSE-C Encryption attack documented for AWS S3 in the Codefinger campaign, an attacker generates an AES-256 encryption key locally and provides it to Azure Storage during blob upload or copy operations. Azure uses the key to encrypt the blob, then discards it. Azure only logs a hash of the key for request verification, but the hash cannot be used to recover the original key or decrypt the data.
This attack has the lowest barrier to entry among the encryption-based scenarios. It requires no Key Vault permissions and no attacker-side Azure infrastructure. The attacker only needs write access to the target storage account and a locally generated key. This makes CPK encryption particularly dangerous in environments where storage permissions are overly permissive or where compromised service principals have write access to production storage accounts.
From the logs generated by uploading a blob with CPK encryption:
Note that unlike AWS S3, Azure Storage logs do not explicitly indicate when CPK encryption is used during upload. The encryption is transparent in the write operation logs.
However, when victims attempt to access CPK-encrypted blobs without the key, they receive a BlobUsesCustomerSpecifiedEncryption error:
In this scenario, an attacker steals storage account keys or generates SAS tokens, then uses them to exfiltrate data to external storage before deletion. This mirrors the Exfiltration and Deletion technique documented by Palo Alto Unit 42 for AWS S3.
Storage Account Key Theft
Before generating SAS tokens for data exfiltration, attackers must obtain storage account access keys. The listKeys operation retrieves both primary and secondary keys, providing full account access equivalent to root credentials. Unlike Azure AD authentication, access keys enable persistent access that persists even after the attacker's compromised identity is revoked.
Storm-0501 systematically lists storage account keys after obtaining elevated privileges, then uses these keys to generate SAS tokens with arbitrary permissions and expiration dates from external infrastructure.
The authenticationtype field indicates SAS token authentication. The callerIpAddress field shows the source IP. The sp parameter in the URI indicates permissions (r=read, w=write, d=delete, l=list) and the sig parameter the presence of a SAS token. In Python, we can take advantage of the ipaddress library to determine whether the ip address that made the request is within a private range and to detect an external IP address performing storage operations using a SAS token:
defrule(event):
# Must be storage operationifevent.get("category")notin["StorageRead","StorageWrite","StorageDelete"]:
returnFalse# Must be successfulstatus_code = event.get("statusCode")ifstatus_codenotin[200,201,202,204]:
returnFalse# Check if SAS token was used (look for 'sig=' in URI)uri = event.get("uri","")ifnoturior"sig="notinuri:
returnFalse# Check if IP is external (not private/RFC1918)caller_ip = extract_caller_ip(event)ifnotcaller_iporis_private_ip(caller_ip):
returnFalsereturnTrue
defrule(event):
# Must be storage operationifevent.get("category")notin["StorageRead","StorageWrite","StorageDelete"]:
returnFalse# Must be successfulstatus_code = event.get("statusCode")ifstatus_codenotin[200,201,202,204]:
returnFalse# Check if SAS token was used (look for 'sig=' in URI)uri = event.get("uri","")ifnoturior"sig="notinuri:
returnFalse# Check if IP is external (not private/RFC1918)caller_ip = extract_caller_ip(event)ifnotcaller_iporis_private_ip(caller_ip):
returnFalsereturnTrue
defrule(event):
# Must be storage operationifevent.get("category")notin["StorageRead","StorageWrite","StorageDelete"]:
returnFalse# Must be successfulstatus_code = event.get("statusCode")ifstatus_codenotin[200,201,202,204]:
returnFalse# Check if SAS token was used (look for 'sig=' in URI)uri = event.get("uri","")ifnoturior"sig="notinuri:
returnFalse# Check if IP is external (not private/RFC1918)caller_ip = extract_caller_ip(event)ifnotcaller_iporis_private_ip(caller_ip):
returnFalsereturnTrue
defrule(event):
# Must be storage operationifevent.get("category")notin["StorageRead","StorageWrite","StorageDelete"]:
returnFalse# Must be successfulstatus_code = event.get("statusCode")ifstatus_codenotin[200,201,202,204]:
returnFalse# Check if SAS token was used (look for 'sig=' in URI)uri = event.get("uri","")ifnoturior"sig="notinuri:
returnFalse# Check if IP is external (not private/RFC1918)caller_ip = extract_caller_ip(event)ifnotcaller_iporis_private_ip(caller_ip):
returnFalsereturnTrue
Bulk Data Extraction
Mass blob read operations may indicate data staging for exfiltration. This threshold-based detection identifies unusual read volume from a single source. To detect bulk extraction, we monitor for high-volume read operations (50 operations within 15 minutes):
defrule(event):
# Must be GetBlob operation (actual data retrieval)operation = event.get("operationName","").upper()ifoperation != "GETBLOB":
returnFalse# Must be successfulreturnazure_resource_logs_success(event)
defrule(event):
# Must be GetBlob operation (actual data retrieval)operation = event.get("operationName","").upper()ifoperation != "GETBLOB":
returnFalse# Must be successfulreturnazure_resource_logs_success(event)
defrule(event):
# Must be GetBlob operation (actual data retrieval)operation = event.get("operationName","").upper()ifoperation != "GETBLOB":
returnFalse# Must be successfulreturnazure_resource_logs_success(event)
defrule(event):
# Must be GetBlob operation (actual data retrieval)operation = event.get("operationName","").upper()ifoperation != "GETBLOB":
returnFalse# Must be successfulreturnazure_resource_logs_success(event)
Bulk Data Deletion
After exfiltrating data, attackers execute mass blob deletion to maximize pressure on victims.
Unlike encryption-based ransomware, deletion is immediate and irreversible if soft delete is disabled. This makes bulk deletion particularly destructive when combined with the defense evasion techniques documented earlier.
After encrypting or destroying storage data, ransomware operators target Azure Key Vaults to eliminate recovery options and maximize impact. Key Vaults store encryption keys used for Azure Storage Service Encryption with customer-managed keys (SSE-CMK), equivalent to AWS KMS-based encryption. Destroying these keys renders encrypted data permanently inaccessible, even if backups exist.
Storm-0501 systematically targets Key Vaults in the final stages of attacks to:
Prevent victims from decrypting SSE-CMK encrypted storage accounts
Destroy cryptographic material needed for recovery operations
Eliminate forensic evidence stored as secrets (e.g., service principal credentials)
Azure implements a two-stage deletion model: soft delete (recoverable) followed by purge (irreversible). Attackers must wait out the soft delete retention period (7-90 days) or exploit vaults without purge protection enabled.
Key Vault Deletion
Soft-deleted Key Vaults can be recovered within the configured retention period (default: 90 days). Vault deletion initiates this countdown and immediately prevents access to all keys, secrets, and certificates.
The enablePurgeProtection property in the event indicates whether the vault can be immediately purged after deletion. Vaults without purge protection are at higher risk, as attackers can permanently destroy them without waiting for the soft delete period. We can monitor the general vault delete operation like so:
If the deleted vault contains encryption keys for storage accounts, those accounts become inaccessible immediately. Azure Storage returns 403 Forbidden errors when attempting to access the encrypted data.
Key Vault Purged
Purging permanently destroys the vault and all cryptographic material, keys, secrets, and certificates. This operation is irreversible and cannot be undone. Purging requires the vault to be in a soft-deleted state first.
The scheduledPurgeDate shows when automatic purge would have occurred. Manual purge operations override this schedule, indicating intentional destruction rather than policy-based cleanup. To detect Key Vault purge operations:
Attackers can also purge individual cryptographic keys while leaving the vault intact. This approach destroys specific encryption keys used for SSE-CMK encrypted storage accounts without raising alarms about vault deletion.
The key must be in a soft-deleted state before purging. Attackers typically delete the key, then immediately purge it to minimize recovery windows. To detect cryptographic key purge operations:
Several detection rules in this section identify external access or unusual patterns that may trigger during legitimate operations. To reduce false positives, you can apply inline filters.
For SAS token access from known partner IP ranges, you can apply this filter to the rule "Azure Storage SAS External Access":
callerIpAddress does not match <ALLOWED_IP_PATTERN>
For storage accounts intended for external access (e.g., CDN backends, public data), you can exclude them:
uri does not contain <ALLOWED_STORAGE_ACCOUNT>
To identify a baseline of legitimate operations, query your logs to extract which Key Vaults are used for encryption operations and which IP ranges access storage via SAS tokens.
Conclusion
Azure ransomware attacks follow predictable patterns: escalating privileges through compromised identities, systematically disabling recovery mechanisms (resource locks, immutability policies, soft delete), exfiltrating data via SAS tokens, and either encrypting data with customer-provided keys or destroying it entirely alongside backups and encryption keys. Storm-0501 and similar threat actors demonstrate that cloud-native ransomware only requires sufficient permissions and knowledge of native Azure capabilities.
The detection rules in this report provide comprehensive visibility across all seven attack stages, from initial privilege escalation through recovery prevention. However, Azure's logging model presents challenges: Customer-Provided Key (CPK) encryption is transparent in write operations and only becomes visible when victims attempt access, storage account key theft is logged but the keys themselves are not, and data plane operations require diagnostic settings enabled per storage account. Organizations without comprehensive logging enabled may detect ransomware only after irreversible destruction has occurred.
The most effective defense against cloud ransomware remains making the attack prerequisites impossible to achieve: if attackers cannot disable recovery mechanisms, cannot access data plane operations from external infrastructure, and cannot destroy encryption keys, ransomware impact is limited to the permissions granted to compromised identities.