Detection rules › Kusto

Azure VM Run Command operation executed during suspicious login window

Severity
high
Time window
2d
Group by
Authorization, Caller, CorrelationId, joinkey
Author
Microsoft Security Rearch
Source
github.com/Azure/Azure-Sentinel

Identifies when the Azure Run Command operation is executed by a UserPrincipalName and IP Address that has resulted in a recent user entity behaviour alert.

MITRE ATT&CK coverage

TacticTechniques
Credential Access
Lateral Movement

Telemetry coverage

Rule body

id: 11bda520-a965-4654-9a45-d09f372f71aa
name: Azure VM Run Command operation executed during suspicious login window
description: |
  'Identifies when the Azure Run Command operation is executed by a UserPrincipalName and IP Address that has resulted in a recent user entity behaviour alert.'
severity: High
requiredDataConnectors:
  - connectorId: AzureActivity
    dataTypes:
      - AzureActivity
  - connectorId: BehaviorAnalytics
    dataTypes:
      - BehaviorAnalytics
queryFrequency: 1d
queryPeriod: 2d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - LateralMovement
  - CredentialAccess
relevantTechniques:
  - T1570
  - T1212
query: |
  AzureActivity
  // Isolate run command actions
  | where OperationNameValue =~ "MICROSOFT.COMPUTE/VIRTUALMACHINES/RUNCOMMAND/ACTION"
  // Confirm that the operation impacted a virtual machine
  | where Authorization has "virtualMachines"
  // Each runcommand operation consists of three events when successful, Started, Accepted (or Rejected), Successful (or Failed).
  | summarize StartTime=min(TimeGenerated), EndTime=max(TimeGenerated), max(CallerIpAddress), make_list(ActivityStatusValue) by CorrelationId, Authorization, Caller
  // Limit to Run Command executions that Succeeded
  | where list_ActivityStatusValue has_any ("Success", "Succeeded")
  // Extract data from the Authorization field
  | extend Authorization_d = parse_json(Authorization)
  | extend Scope = Authorization_d.scope
  | extend Scope_s = split(Scope, "/")
  | extend Subscription = tostring(Scope_s[2])
  | extend VirtualMachineName = tostring(Scope_s[-1])
  | project StartTime, EndTime, Subscription, VirtualMachineName, CorrelationId, Caller, CallerIpAddress=max_CallerIpAddress
  // Create a join key using  the Caller (UPN)
  | extend joinkey = tolower(Caller)
  // Join the Run Command actions to UEBA data
  | join kind = inner (
      BehaviorAnalytics
      // We are specifically interested in unusual logins
      | where EventSource == "Azure AD" and ActivityInsights.ActionUncommonlyPerformedByUser == "True"
      | project UEBAEventTime=TimeGenerated, UEBAActionType=ActionType, UserPrincipalName, UEBASourceIPLocation=SourceIPLocation, UEBAActivityInsights=ActivityInsights, UEBAUsersInsights=UsersInsights
      | where isnotempty(UserPrincipalName) and isnotempty(UEBASourceIPLocation)
      | extend joinkey = tolower(UserPrincipalName)
  ) on joinkey
  // Create a window around the UEBA event times, check to see if the Run Command action was performed within them
  | extend UEBAWindowStart = UEBAEventTime - 1h, UEBAWindowEnd = UEBAEventTime + 6h
  | where StartTime between (UEBAWindowStart .. UEBAWindowEnd)
  | project StartTime, EndTime, Subscription, VirtualMachineName, Caller, CallerIpAddress, UEBAEventTime, UEBAActionType, UEBASourceIPLocation, UEBAActivityInsights, UEBAUsersInsights
  | extend AccountName = tostring(split(Caller, "@")[0]), AccountUPNSuffix = tostring(split(Caller, "@")[1])
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: Caller
      - identifier: Name
        columnName: AccountName
      - identifier: UPNSuffix
        columnName: AccountUPNSuffix
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: CallerIpAddress
version: 1.0.10
kind: Scheduled
metadata:
    source:
        kind: Community
    author:
        name: Microsoft Security Rearch
    support:
        tier: Community
    categories:
        domains: [ "Security - Others", "Platform" ]

Stages and Predicates

Stage 1: source

AzureActivity

Stage 2: where

| where OperationNameValue =~ "MICROSOFT.COMPUTE/VIRTUALMACHINES/RUNCOMMAND/ACTION"

Stage 3: where

| where Authorization has "virtualMachines"

Stage 4: summarize

| summarize StartTime=min(TimeGenerated), EndTime=max(TimeGenerated), max(CallerIpAddress), make_list(ActivityStatusValue) by CorrelationId, Authorization, Caller

Stage 5: where

| where list_ActivityStatusValue has_any ("Success", "Succeeded")

Stage 6: extend (5 consecutive steps)

| extend Authorization_d = parse_json(Authorization)
| extend Scope = Authorization_d.scope
| extend Scope_s = split(Scope, "/")
| extend Subscription = tostring(Scope_s[2])
| extend VirtualMachineName = tostring(Scope_s[-1])

Stage 7: project

| project StartTime, EndTime, Subscription, VirtualMachineName, CorrelationId, Caller, CallerIpAddress=max_CallerIpAddress

Stage 8: extend

| extend joinkey = tolower(Caller)

Stage 9: join

| join kind = inner (
    BehaviorAnalytics
    | where EventSource == "Azure AD" and ActivityInsights.ActionUncommonlyPerformedByUser == "True"
    | project UEBAEventTime=TimeGenerated, UEBAActionType=ActionType, UserPrincipalName, UEBASourceIPLocation=SourceIPLocation, UEBAActivityInsights=ActivityInsights, UEBAUsersInsights=UsersInsights
    | where isnotempty(UserPrincipalName) and isnotempty(UEBASourceIPLocation)
    | extend joinkey = tolower(UserPrincipalName)
) on joinkey

Stage 10: extend

| extend UEBAWindowStart = UEBAEventTime - 1h, UEBAWindowEnd = UEBAEventTime + 6h

Stage 11: where

| where StartTime between (UEBAWindowStart .. UEBAWindowEnd)

Stage 12: project

| project StartTime, EndTime, Subscription, VirtualMachineName, Caller, CallerIpAddress, UEBAEventTime, UEBAActionType, UEBASourceIPLocation, UEBAActivityInsights, UEBAUsersInsights

Stage 13: extend

| extend AccountName = tostring(split(Caller, "@")[0]), AccountUPNSuffix = tostring(split(Caller, "@")[1])

Indicators

These rows show field, operator, and value matches.

Output fields

These fields are emitted when the rule matches.

FieldSource
Callerproject
CallerIpAddressproject
EndTimeproject
StartTimeproject
Subscriptionproject
UEBAActionTypeproject
UEBAActivityInsightsproject
UEBAEventTimeproject
UEBASourceIPLocationproject
UEBAUsersInsightsproject
VirtualMachineNameproject
AccountNameextend
AccountUPNSuffixextend