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" ]
