Detection rules › Kusto

[Entra ID] Domain Federation Trust Settings Modified

Status
available
Severity
high
Time window
1d
Source
github.com/Azure/Azure-Sentinel

Detects changes to domain federation trust settings or domain authentication mode. These changes can be used to redirect sign-in trust and should be reviewed immediately.

MITRE ATT&CK coverage

TacticTechniques
Persistence
Credential Access

Telemetry coverage

Rules detecting the same action

These rules filter on the same operation.

Rule body

id: 944d0ab5-b654-47f9-a398-2e77a0b7906e
name: "[Entra ID] Domain Federation Trust Settings Modified"
version: 1.0.0
kind: Scheduled
description: |
  Detects changes to domain federation trust settings or domain authentication mode. These changes can be used to redirect sign-in trust and should be reviewed immediately.
severity: High
status: Available
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
      - AuditLogs
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - CredentialAccess
  - Persistence
relevantTechniques:
  - T1555
  - T1098
query: |
  (union isfuzzy=true
      (
      AuditLogs
      | where OperationName =~ "Set federation settings on domain"
      //| where Result =~ "success"   // commenting out, as it may be interesting to capture failed attempts
      | mv-expand TargetResources
      | extend modifiedProperties = parse_json(TargetResources).modifiedProperties
      | mv-expand modifiedProperties
      | extend targetDisplayName = tostring(parse_json(modifiedProperties).displayName)
      ),
      (
      AuditLogs
      | where OperationName =~ "Set domain authentication"
      //| where Result =~ "success"   // commenting out, as it may be interesting to capture failed attempts
      | mv-expand TargetResources
      | extend modifiedProperties = parse_json(TargetResources).modifiedProperties
      | mv-expand modifiedProperties
      | mv-apply Property = modifiedProperties on
          (
          where Property.displayName =~ "LiveType"
          | extend
              targetDisplayName = tostring(Property.displayName),
              NewDomainValue = tostring(Property.newValue)
          )
      | where NewDomainValue has "Federated"
      )
  )
  | mv-apply AdditionalDetail = AdditionalDetails on
      (
      where AdditionalDetail.key =~ "User-Agent"
      | extend UserAgent = tostring(AdditionalDetail.value)
      )
  | extend InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))
  | extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
  | extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
  | extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
  | extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
  | extend InitiatingIpAddress = tostring(iff(isnotempty(InitiatedBy.user.ipAddress), InitiatedBy.user.ipAddress, InitiatedBy.app.ipAddress))
  | extend InitiatingAppServicePrincipalName = tostring(InitiatedBy.app.displayName)
  | extend
      InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]),
      InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
  | extend Source_Network_IPLocation = ""
  | project
      Alert_Time_TW = datetime_utc_to_local(TimeGenerated, 'Asia/Taipei'),
      Alert_Time_UTC0 = TimeGenerated,
          Alert_Category_en = "Entra ID",
      Alert_SubCategory_en = "Anomaly Config Modification",
      Alert_Name_en = "Domain Federation Trust Settings Modified",
      Alert_Description_en=strcat(
                           "At Taiwan time: ",
                           format_datetime(datetime_utc_to_local(TimeGenerated, "Asia/Taipei"), "yyyy-MM-dd HH:mm:ss"),
                           " in Entra ID:  ",
                           "",
                           ", detected that Entra ID domain authentication was set to Federated",
                           " operation action: ",
                           iff(isnotempty(OperationName), OperationName, "<NoOperationName>"),
                           ", changed property: ",
                           iff(isnotempty(targetDisplayName), targetDisplayName, "<NoProperty>"),
                           ", operator/application: ",
                           iff(isnotempty(InitiatingUserOrApp), InitiatingUserOrApp, "<NoInitiator>"),
                           ", source IP: ",
                           iff(isnotempty(InitiatingIpAddress), InitiatingIpAddress, "<NoIP>"),
                           ", location: ",
                           iff(isnotempty(Source_Network_IPLocation), Source_Network_IPLocation, "<NoLocation>"),
                           ", User-Agent:",
                           iff(isnotempty(UserAgent), UserAgent, "<NoUserAgent>"),
                           "This is a high-risk domain-level change that may allow the entire tenant identity to be taken over by external federation."
                       ),
      Alert_TriageStep_en=strcat(
                          "1. Confirm whether the change was authorized. Operation action: ",
                          iff(isnotempty(OperationName), OperationName, "<NoOperationName>"),
                          ", operator: ",
                          iff(isnotempty(InitiatingUserOrApp), InitiatingUserOrApp, "<NoInitiator>"),
                          "  has formal approval.",
                          "2. Check source risk. Source IP: ",
                          iff(isnotempty(InitiatingIpAddress), InitiatingIpAddress, "<NoIP>"),
                          ", location: ",
                          iff(isnotempty(Source_Network_IPLocation), Source_Network_IPLocation, "<NoLocation>"),
                          "  is a company named location or an abnormal country.",
                          "3. Check the operation tool User-Agent: ",
                          iff(isnotempty(UserAgent), UserAgent, "<NoUserAgent>"),
                          "  to determine whether it is an expected management entry point (Portal/PowerShell/Graph) or a suspicious script.",
                          "4. Immediately inventory the impact scope: confirm which domains were set to Federated and whether all user sign-in flows are affected."
                      ),
      Alert_Containment_en=strcat(
                           "1. If determined to be an unauthorized change, immediately change the affected domain authentication method back to Managed and remove any unauthorized Federation settings. ",
                           "2. Immediately revoke the operator's sign-in tokens and administrative permissions, and reset the password and re-register MFA if necessary. ",
                           "3. Block the source IP immediately or restrict management-plane access to prevent continued change attempts. ",
                           "4. Initiate tenant emergency response: check whether any accounts have successfully signed in through the Federated domain and performed administrative operations."
                       ),
      Alert_Remediation_en=strcat(
                           "1. Strengthen domain-level governance: limit the role scope that can execute Set federation / Set domain authentication, and enforce two-person review. ",
                           "2. Strengthen Conditional Access: allow management-plane operations only from named locations, compliant devices, and MFA, and directly block abnormal countries or new User-Agents. ",
                           "3. Automated detection and response: establish SOAR for related events (notification, account suspension, source IP blocking). ",
                           "4. Regularly audit domain and federation settings: inventory all domain authentication modes and remove unnecessary or unused Federation and trust relationships."
                       ),
              //Event_Code = AliveTime,
      Event_Action = OperationName,
      //Event_Description = Role ,
      Event_TimeRange_Start_TW = datetime_utc_to_local(TimeGenerated, 'Asia/Taipei'),
      Event_TimeRange_End_TW = datetime_utc_to_local(TimeGenerated, 'Asia/Taipei'),
      Source_Identity_FullName = InitiatingUserOrApp,
      Source_Identity_Type = iff(isnotempty(InitiatingUserPrincipalName), "User", "Service"),
      Source_Network_IPAddress = InitiatingIpAddress,
      Source_Network_IPLocation = Source_Network_IPLocation,
      Source_Identity_DomainType = iff(InitiatingUserPrincipalName contains "EXT", 'External', 'Internal'),
      Source_Resource_Name = UserAgent,
      Target_Identity_ID = targetDisplayName,
      //Target_Identity_Type = "Service",
      Target_Resource_ID = "",
      Target_Resource_Name = "Microsoft Entra ID",
      Target_Resource_Type = "Microsoft Entra ID"
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: Source_Identity_FullName
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: Source_Network_IPAddress

Stages and Predicates

Stage 1: union

union of 2 branches

Stage 2: source

AuditLogs

Stage 3: where

| where OperationName =~ "Set federation settings on domain"

Stage 4: mv-expand

| mv-expand TargetResources

Stage 5: extend

| extend modifiedProperties = parse_json(TargetResources).modifiedProperties

Stage 6: mv-expand

| mv-expand modifiedProperties

Stage 7: extend

| extend targetDisplayName = tostring(parse_json(modifiedProperties).displayName)

Stage 8: source

AuditLogs

Stage 9: where

| where OperationName =~ "Set domain authentication"

Stage 10: mv-expand

| mv-expand TargetResources

Stage 11: extend

| extend modifiedProperties = parse_json(TargetResources).modifiedProperties

Stage 12: mv-expand

| mv-expand modifiedProperties

Stage 13: kusto:mv-apply

| mv-apply Property = modifiedProperties on
        (
        where Property.displayName =~ "LiveType"
        | extend
            targetDisplayName = tostring(Property.displayName),
            NewDomainValue = tostring(Property.newValue)
        )

Stage 14: where

| where NewDomainValue has "Federated"

Stage 15: kusto:mv-apply

kusto:mv-apply key =~ "User-Agent"

Stage 16: extend (9 consecutive steps)

extend InitiatingAadUserId, InitiatingAccountName, InitiatingAccountUPNSuffix, InitiatingAppName, InitiatingAppServicePrincipalId, InitiatingAppServicePrincipalName, InitiatingIpAddress, InitiatingUserOrApp, InitiatingUserPrincipalName, Source_Network_IPLocation
InitiatingUserOrApp =
ifisnotempty(userPrincipalName)tostring(InitiatedBy.user.userPrincipalName)
elsetostring(InitiatedBy.app.displayName)

Stage 17: project

project Alert_Category_en, Alert_Containment_en, Alert_Description_en, Alert_Name_en, Alert_Remediation_en, Alert_SubCategory_en, Alert_Time_TW, Alert_Time_UTC0, Alert_TriageStep_en, Event_Action, Event_TimeRange_End_TW, Event_TimeRange_Start_TW, Source_Identity_DomainType, Source_Identity_FullName, Source_Identity_Type, Source_Network_IPAddress, Source_Network_IPLocation, Source_Resource_Name, Target_Identity_ID, Target_Resource_ID, Target_Resource_Name, Target_Resource_Type

Indicators

These rows show field, operator, and value matches.

Output fields

These fields are emitted when the rule matches.

FieldSource
Alert_Category_enproject
Alert_Containment_enproject
Alert_Description_enproject
Alert_Name_enproject
Alert_Remediation_enproject
Alert_SubCategory_enproject
Alert_Time_TWproject
Alert_Time_UTC0project
Alert_TriageStep_enproject
Event_Actionproject
Event_TimeRange_End_TWproject
Event_TimeRange_Start_TWproject
Source_Identity_DomainTypeproject
Source_Identity_FullNameproject
Source_Identity_Typeproject
Source_Network_IPAddressproject
Source_Network_IPLocationproject
Source_Resource_Nameproject
Target_Identity_IDproject
Target_Resource_IDproject
Target_Resource_Nameproject
Target_Resource_Typeproject