Detection rules › Kusto
Detect Custom Script or Run Command deployment by risky user
This detection rule flags when a user with risk events in Entra ID Identity Protection is deploying Custom Scripts or Run Commands on Azure or Azure Arc machines. This may indicate a compromised cloud user that is now performaring lateral movement from the Azure control plane to Virtual Machines in other environments.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Execution | |
| Lateral Movement |
References
Telemetry coverage
Rules detecting the same action
These rules filter on the same operation.
- Azure Active Directory Hybrid Health AD FS New Server (Sigma)
- Azure Active Directory Hybrid Health AD FS Service Delete (Sigma)
- Azure Subscription Permission Elevation Via AuditLogs (Sigma)
- Microsoft Entra ID Hybrid Health AD FS New Server (Kusto)
- Microsoft Entra ID Hybrid Health AD FS Service Delete (Kusto)
- Microsoft Entra ID Hybrid Health AD FS Suspicious Application (Kusto)
- NRT Microsoft Entra ID Hybrid Health AD FS New Server (Kusto)
Rule body
AzureActivity
| where TimeGenerated > ago(1h)
| where CategoryValue == "Administrative"
| where OperationNameValue =~ "Microsoft.Compute/virtualMachines/runCommand/action"
or OperationNameValue =~ "MICROSOFT.COMPUTE/VIRTUALMACHINES/EXTENSIONS/WRITE"
| extend VMName = tostring(todynamic(Properties).resource)
| summarize make_list(ActivityStatusValue), TimeGenerated = max(TimeGenerated) by CorrelationId, CallerIpAddress, Caller, ResourceGroup, VMName
| join kind=inner (AADUserRiskEvents | where TimeGenerated > ago(14d) ) on $left.Caller == $right.UserPrincipalName
Stages and Predicates
Stage 1: source
AzureActivity
Stage 2: where
| where TimeGenerated > ago(1h)
Stage 3: where
| where CategoryValue == "Administrative"
Stage 4: where
| where OperationNameValue =~ "Microsoft.Compute/virtualMachines/runCommand/action"
or OperationNameValue =~ "MICROSOFT.COMPUTE/VIRTUALMACHINES/EXTENSIONS/WRITE"
Stage 5: extend
| extend VMName = tostring(todynamic(Properties).resource)
Stage 6: summarize
| summarize make_list(ActivityStatusValue), TimeGenerated = max(TimeGenerated) by CorrelationId, CallerIpAddress, Caller, ResourceGroup, VMName
Stage 7: join
| join kind=inner (AADUserRiskEvents | where TimeGenerated > ago(14d) ) on $left.Caller == $right.UserPrincipalName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
CategoryValue | eq |
| field:"CategoryValue" kind:eq value:"Administrative" |
OperationNameValue | eq |
| field:"azure_ad::operation_name_value" kind:eq |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Caller | summarize |
CallerIpAddress | summarize |
CorrelationId | summarize |
ResourceGroup | summarize |
TimeGenerated | summarize |
VMName | summarize |