Query Details

Unusual AAD Conditional Access Failures After Policy Change

Query

id: dfe51b81-efb9-45bd-abbc-ee8ee34d15b1
name: Unusual Azure AD Conditional Access Failures after Policy Change
description: |
  'Uses Behaviour Analytics (UEBA) information and Azure AD Audit Log in Microsoft Sentinel and correlates unusual numbers of Conditional Access failures with sign-in logs. The result will be used for correlation to detect CA policy changes in AuditLogs within the time range.'
severity: Medium
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
      - SigninLogs
      - BehaviorAnalytics
      - AuditLogs
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - InitialAccess
  - Persistence
relevantTechniques:
  - T1078
  - T1098
query: |
  BehaviorAnalytics
  | where ActivityInsights.UnusualNumberOfAADConditionalAccessFailures == "True"
  | extend UserPrincipalName = tolower(UserPrincipalName)
  | join kind=inner (
      union SigninLogs, AADNonInteractiveUserSignInLogs
      | where ConditionalAccessStatus == "failure"
      | mv-expand ConditionalAccessPolicies_dynamic
      | extend ConditionalAccessResult = parse_json(ConditionalAccessPolicies_dynamic.result)
      | extend ConditionalAccessName = parse_json(ConditionalAccessPolicies_dynamic.displayName)
      | extend ConditionalAccessId = parse_json(ConditionalAccessPolicies_dynamic.id)
      | extend ConditionalAccessEnforcedControl = parse_json(tostring(ConditionalAccessPolicies_dynamic.enforcedGrantControls))
      | extend SourceIPAddress = IPAddress
      | extend UserPrincipalName = tolower(UserPrincipalName)
      | where ConditionalAccessResult == "failure"
      | distinct CorrelationId, UserDisplayName, UserPrincipalName, SourceIPAddress, tostring(ConditionalAccessName), tostring(ConditionalAccessId), tostring(ConditionalAccessResult), tostring(ConditionalAccessEnforcedControl), ResultType, AADTenantId
  ) on UserPrincipalName, SourceIPAddress
  | summarize count() by ConditionalAccessName, ConditionalAccessId, ResultType, AADTenantId
  | join kind=inner (
      AuditLogs
      | where OperationName == "Update conditional access policy"
      | extend ConditionalAccessId = tostring(TargetResources[0].id)
  ) on ConditionalAccessId
  | extend Actor = parse_json(tostring(InitiatedBy.user)).userPrincipalName
  | project TimeGenerated, OperationName, Actor, ConditionalAccessName, CorrelationId, ResultType, count_
  | extend AccountCustomEntity = Actor
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: AccountCustomEntity
version: 1.1.0

Explanation

This query is designed to detect unusual numbers of Azure AD Conditional Access failures after a policy change. It uses Behavior Analytics and Azure AD Audit Log data in Microsoft Sentinel to correlate the failures with sign-in logs. The query checks for any unusual number of failures and then joins the relevant information from the sign-in logs and audit logs. The result is a summary of the count of failures for each conditional access policy that has been updated. The query is run once a day and has a medium severity level. The relevant techniques for this query are Initial Access and Persistence.

Details

Thomas Naunheim profile picture

Thomas Naunheim

Released: August 23, 2023

Tables

BehaviorAnalyticsSigninLogsAADNonInteractiveUserSignInLogsAuditLogs

Keywords

BehaviorAnalytics,SigninLogs,AADNonInteractiveUserSignInLogs,AuditLogs,UserPrincipalName,IPAddress,ConditionalAccessStatus,ConditionalAccessPolicies_dynamic,ConditionalAccessResult,ConditionalAccessName,ConditionalAccessId,ConditionalAccessEnforcedControl,SourceIPAddress,CorrelationId,UserDisplayName,ResultType,AADTenantId,OperationName,TargetResources,InitiatedBy.user,TimeGenerated,Actor,count_,AccountCustomEntity,FullName

Operators

whereextendjoinunionmv-expandparse_jsontolowerdistinctsummarizeproject

Actions