Query Details

Token Replay From Workload Identity With Privileges In Microsoft 365 Workload Identity Info

Query

id: 92824ea9-7f37-4bf9-b4bf-45e7c82a6b46
name: Token Replay from workload identity with privileges in Microsoft Entra or Microsoft 365 (WorkloadIdentityInfo)
version: 1.0.0
kind: Scheduled
description: Detected indicator of token replay attack by using the following pattern. A token has been used for activity on Microsoft Graph API from a different IP address than during the sign-in process. Severity is set to "high" if workload identity has privileges on Control Plane.
severity: Medium
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- CredentialAccess
relevantTechniques:
- T1528
query: |-
  let azure_ranges = externaldata(changeNumber: string, cloud: string, values: dynamic)
  ["https://raw.githubusercontent.com/microsoft/mstic/master/PublicFeeds/MSFTIPRanges/ServiceTags_Public.json"] with(format='multijson')
  | mv-expand values
  | mv-expand values.properties.addressPrefixes
  | mv-expand values_properties_addressPrefixes
  | summarize by tostring(values_properties_addressPrefixes)
  | extend isipv4 = parse_ipv4(values_properties_addressPrefixes)
  | extend isipv6 = parse_ipv6(values_properties_addressPrefixes)
  | extend ip_type = case(isnotnull(isipv4), "v4", "v6")
  | summarize make_list(values_properties_addressPrefixes) by ip_type;
  MicrosoftGraphActivityLogs
  | project TimeGenerated, RequestId, ApiVersion, RequestMethod, ResponseStatusCode, ActivityIpAddress = IPAddress, UserAgent, RequestUri, Roles, AppId, Wids, SignInActivityId, ApplicationId = AppId, Scopes, Location
  | join kind=inner (union AADServicePrincipalSignInLogs, AADManagedIdentitySignInLogs
    | project ConditionalAccessPolicies, ConditionalAccessStatus, ServicePrincipalCredentialKeyId, SignInIpAddress = IPAddress, UniqueTokenIdentifier, Type
    // Correlation between Activity and Sign-in based on Unique Token Identifier
  ) on $left.SignInActivityId == $right.UniqueTokenIdentifier
  // AADManagedIdentitySignInLogs does not include SignInIpAddress
  | where ActivityIpAddress != SignInIpAddress and isnotempty(SignInIpAddress)
  | extend isipv4 = parse_ipv4(ActivityIpAddress)
  | extend ip_type = case(isnotnull(isipv4), "v4", "v6")
  | join kind=fullouter (azure_ranges) on ip_type
  | extend ipv6_match = ipv6_is_in_any_range(ActivityIpAddress, list_values_properties_addressPrefixes)
  | extend ipv4_match = ipv4_is_in_any_range(ActivityIpAddress, list_values_properties_addressPrefixes)
  | extend IpAddressType = iff(ipv4_match or ipv6_match, "Azure Public IP", "None Azure IP")
  | where isnotempty(ApplicationId)
  | join kind=leftouter(
      PrivilegedWorkloadIdentityInfo
      | project
          WorkloadIdentityName,
          WorkloadIdentityType,
          ApplicationObjectId,
          ServicePrincipalObjectId,
          ApplicationId,
          IsFirstPartyApp,
          EntraIdRoles,
          AppRolePermissions,
          WorkloadIdClassification = EnterpriseAccessModelTiering
      )
      on ApplicationId
  | extend Severity = iff(WorkloadIdClassification contains "ControlPlane", "High", "Medium")
suppressionEnabled: false
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: false
    lookbackDuration: 5h
    matchingMethod: Selected
    groupByEntities:
    - CloudApplication
    groupByAlertDetails: []
    groupByCustomDetails: []
eventGroupingSettings:
  aggregationKind: AlertPerResult
alertDetailsOverride:
  alertDisplayNameFormat: Token Replay from workload identity with {{WorkloadIdClassification}} privileges in Microsoft Entra or Microsoft 365
  alertDescriptionFormat: Activity of {{WorkloadIdentityName}} from IPAddress ({{ActivityIpAddress}}) to Microsoft Graph API with privileges on {{WorkloadIdClassification}} has been detected which is different than the IP address from sign-in event.
  alertSeverityColumnName: Severity
  alertDynamicProperties: []
customDetails:
  WorkloadIdentityName: WorkloadIdentityName
  WorkloadIdentityType: WorkloadIdentityType
  ServicePrincipalId: ServicePrincipalObjectId
  ApplicationId: ApplicationId
  CredentialKeyId: ServicePrincipalCredentialKeyId
  IsFirstPartyApp: IsFirstPartyApp
  PrivilegedAccess: WorkloadIdClassification
  EntraDirectoryRoles: EntraIdRoles
  MSGraphRoles: AppRolePermissions
  ConditionalAccess: ConditionalAccessStatus
  MSGraphUri: RequestUri
  MSGraphMethod: RequestMethod
  UserAgent: UserAgent
  Location: Location
entityMappings:
- entityType: CloudApplication
  fieldMappings:
  - identifier: Name
    columnName: WorkloadIdentityName
- entityType: CloudApplication
  fieldMappings:
  - identifier: AppId
    columnName: ApplicationId
- entityType: IP
  fieldMappings:
  - identifier: Address
    columnName: ActivityIpAddress
- entityType: IP
  fieldMappings:
  - identifier: Address
    columnName: SignInIpAddress
suppressionDuration: 5h

Explanation

This query detects a token replay attack on Microsoft Graph API. It checks if a token has been used from a different IP address than during the sign-in process. The severity is set to medium, but it can be high if the workload identity has privileges on the Control Plane. The query frequency and period are both set to 1 hour. The query retrieves Azure IP ranges and then joins the MicrosoftGraphActivityLogs with AADServicePrincipalSignInLogs and AADManagedIdentitySignInLogs to correlate activity and sign-in based on a unique token identifier. It filters out activity with different IP addresses and joins with PrivilegedWorkloadIdentityInfo to get additional information. The query also includes incident configuration and alert details override.

Details

Thomas Naunheim profile picture

Thomas Naunheim

Released: November 20, 2023

Tables

MicrosoftGraphActivityLogs AADServicePrincipalSignInLogs AADManagedIdentitySignInLogs PrivilegedWorkloadIdentityInfo

Keywords

Devices,Intune,User,MicrosoftGraphAPI,IPAddress,Sign-in,AzurePublicIP,PrivilegedWorkloadIdentity,ControlPlane,MicrosoftEntra,Microsoft365

Operators

letexternaldatawithmv-expandsummarizeextendcasejoinonwhereiffcontainsproject

Actions