Attackers may delete Azure workspaces from infected devices to eliminate forensic evidence and disrupt monitoring capabilities. SOC teams should proactively hunt for this behavior to identify and mitigate advanced threats that seek to erase their presence in the environment.
KQL Query
SecurityAlert
| where TimeGenerated > ago(1d)
| where ProductName == "Azure Active Directory Identity Protection"
| where AlertName == "Sign-in from an infected device"
| mv-apply EntityAccount=todynamic(Entities) on
(
where EntityAccount.Type == "account"
| extend AadTenantId = tostring(EntityAccount.AadTenantId), AadUserId = tostring(EntityAccount.AadUserId)
)
| mv-apply EntityIp=todynamic(Entities) on
(
where EntityIp.Type == "ip"
| extend IpAddress = tostring(EntityIp.Address)
)
| join kind=inner (
IdentityInfo
| distinct AccountTenantId, AccountObjectId, AccountUPN, AccountDisplayName
| extend UserAccount = AccountUPN
| extend UserName = AccountDisplayName
| where isnotempty(AccountDisplayName) and isnotempty(UserAccount)
| project AccountTenantId, AccountObjectId, UserAccount, UserName
)
on
$left.AadTenantId == $right.AccountTenantId,
$left.AadUserId == $right.AccountObjectId
| extend CompromisedEntity = iff(CompromisedEntity == "N/A" or isempty(CompromisedEntity), UserAccount, CompromisedEntity)
| project AlertName, AlertSeverity, CompromisedEntity, UserAccount, IpAddress, TimeGenerated, UserName
| join kind=inner
(
AzureActivity
| where OperationNameValue has_any ("/workspaces/computes/delete", "workspaces/delete")
| where ActivityStatusValue has_any ("Succeeded", "Success")
| project TimeGenerated, ResourceProviderValue, _ResourceId, SubscriptionId, UserAccount=Caller, IpAddress=CallerIpAddress, CorrelationId, OperationId, ResourceGroup, TenantId
) on IpAddress, UserAccount
| extend AccountName = tostring(split(UserAccount, "@")[0]), AccountUPNSuffix = tostring(split(UserAccount, "@")[1])
id: a5b3429d-f1da-42b9-883c-327ecb7b91ff
name: Workspace deletion activity from an infected device
description: |
'This query will alert on any sign-ins from devices infected with malware in correlation with workspace deletion activity.
Attackers may attempt to delete workspaces containing compute instances after successful compromise to cause service unavailability to regular business operation.'
severity: Medium
requiredDataConnectors:
- connectorId: AzureActiveDirectoryIdentityProtection
dataTypes:
- SecurityAlert (IPC)
- connectorId: AzureActivity
dataTypes:
- AzureActivity
- connectorId: BehaviorAnalytics
dataTypes:
- IdentityInfo
queryFrequency: 1d
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
- Impact
relevantTechniques:
- T1078
- T1489
query: |
SecurityAlert
| where TimeGenerated > ago(1d)
| where ProductName == "Azure Active Directory Identity Protection"
| where AlertName == "Sign-in from an infected device"
| mv-apply EntityAccount=todynamic(Entities) on
(
where EntityAccount.Type == "account"
| extend AadTenantId = tostring(EntityAccount.AadTenantId), AadUserId = tostring(EntityAccount.AadUserId)
)
| mv-apply EntityIp=todynamic(Entities) on
(
where EntityIp.Type == "ip"
| extend IpAddress = tostring(EntityIp.Address)
)
| join kind=inner (
IdentityInfo
| distinct AccountTenantId, AccountObjectId, AccountUPN, AccountDisplayName
| extend UserAccount = AccountUPN
| extend UserName = AccountDisplayName
| where isnotempty(AccountDisplayName) and isnotempty(UserAccount)
| project AccountTenantId, AccountObjectId, UserAccount, UserName
)
on
$left.AadTenantId == $right.AccountTenantId,
$left.AadUserId == $right.AccountObjectId
| extend CompromisedEntity = iff(CompromisedEntity == "N/A" or isempty(CompromisedEntity), UserAccount, CompromisedEntity)
| project AlertName, AlertSeverity, CompromisedEntity, UserAccount, IpAddress, TimeGenerated, UserName
| join kind=inner
(
AzureActivity
| where OperationNameValue has_any ("/workspaces/computes/delete", "workspaces/delete")
| where ActivityStatusValue has_any ("Succeeded", "Success")
| project TimeGenerated, ResourceProviderValue, _ResourceId, SubscriptionId, UserAccount=Caller, IpAddress=CallerIpAddress, CorrelationId, OperationId, ResourceGroup, TenantId
) on IpAddress, UserAccount
| extend AccountName = tostring(split(UserAccount, "@")[0]), AccountUPNSuffix = tostring(split(UserAccount, "@")[1])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: UserAccount
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: AccountUPNSuffix
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IpAddress
- entityType: AzureResource
fieldMappi
| Sentinel Table | Notes |
|---|---|
AzureActivity | Ensure this data connector is enabled |
IdentityInfo | Ensure this data connector is enabled |
SecurityAlert | Ensure this data connector is enabled |
Scenario: Scheduled Backup Job Deletes Workspace
Description: A legitimate scheduled backup job runs and deletes a workspace as part of its cleanup process.
Filter/Exclusion: Exclude activity associated with known backup tools (e.g., Veeam, Commvault) or tasks with specific job names containing keywords like “backup” or “cleanup”.
Scenario: Admin Performing Workspace Deletion for Maintenance
Description: An administrator deletes a workspace to reconfigure or decommission a service.
Filter/Exclusion: Exclude activity from admin accounts with elevated privileges (e.g., [email protected]) or tasks associated with maintenance windows.
Scenario: CI/CD Pipeline Cleanup Task
Description: A CI/CD pipeline (e.g., Jenkins, GitLab CI) runs a cleanup task that deletes workspaces or environments.
Filter/Exclusion: Exclude activity originating from CI/CD tools or IP addresses associated with known CI/CD infrastructure (e.g., 192.168.1.100 or ci.example.com).
Scenario: User Error During Workspace Management
Description: A user accidentally deletes a workspace while performing routine management tasks (e.g., renaming or reorganizing).
Filter/Exclusion: Exclude activity from users with low-risk roles or actions that occur during known user training periods.
Scenario: Log Rotation or Archive Process
Description: A log rotation or archive process deletes workspace data as part of its operation.
Filter/Exclusion: Exclude activity related to log management tools (e.g., Splunk, ELK Stack) or processes with names containing “rotate” or “archive”.