Back
Id9f7197b6-eeb2-46f3-83b1-a2c4dfca46a0
Rulename[Entra ID] Authentication Method Changed for Privileged Account
DescriptionDetects changes to authentication methods on privileged accounts. This may indicate an attacker added a new method to maintain access.
SeverityHigh
TacticsPersistence
TechniquesT1098
Required data connectorsAzureActiveDirectory
KindScheduled
Query frequency1d
Query period1d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/eDCRule/Analytic%20Rules/%5BEntra%20ID%5D%20Authentication%20Method%20Changed%20for%20Privileged%20Account.yaml
Version1.0.0
Arm template9f7197b6-eeb2-46f3-83b1-a2c4dfca46a0.json
Deploy To Azure
let queryperiod = 1d;
let queryfrequency = 1d;
let security_info_actions = dynamic(["User registered security info", "User changed default security info", "User deleted security info", "Admin updated security info", "Admin deleted security info", "Admin registered security info"]);
let VIPUsers = (
    IdentityInfo
    | where TimeGenerated > ago(queryperiod)
    | mv-expand AssignedRoles
    | where AssignedRoles contains 'Admin'
    | summarize by AccountUPN);
AuditLogs
| where TimeGenerated > ago(queryperiod)
| where Category =~ "UserManagement"
| where ActivityDisplayName in (security_info_actions)
| extend Initiator = tostring(InitiatedBy.user.userPrincipalName)
| extend IP = tostring(InitiatedBy.user.ipAddress)
| extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
| extend InitiatingAppServicePrincipalName = tostring(InitiatedBy.app.servicePrincipalName)
| mv-apply TargetResource = TargetResources on
    (
    where TargetResource.type =~ "User"
    | extend Target = tostring(TargetResource.userPrincipalName)
    )
| where Target in~ (VIPUsers)
// Uncomment the line below if you are experiencing high volumes of Target entities. If this is uncommented, the Target column will not be mapped to an entity.
//| summarize Start=min(TimeGenerated), End=max(TimeGenerated), Actions = make_set(ResultReason, MaxSize=8), Targets=make_set(Target, MaxSize=256) by Initiator, IP, Result
// Comment out this line below, if line above is used.
| summarize
    Start=min(TimeGenerated),
    End=max(TimeGenerated),
    Actions = make_set(ResultReason, MaxSize=8),
    Target_ResourceName = make_set(TargetResources)
    by
    Initiator,
    IP,
    Result,
    Targets = Target,
    InitiatingAppServicePrincipalId,
    InitiatingAppServicePrincipalName,
    bin(TimeGenerated, 1h)
| mv-expand Actions
| extend
    Action = tostring(Actions),
    InitiatorName = tostring(split(Initiator, '@', 0)[0]),
    InitiatorUPNSuffix = tostring(split(Initiator, '@', 1)[0]),
    //TargetName = iff(tostring(Targets) has "[", "", tostring(split(Targets, '@', 0)[0])),
    TargetUPNSuffix = iff(tostring(Targets) has "[", "", tostring(split(Targets, '@', 1)[0]))
| extend Source_Network_IPLocation = ""
| project
        Alert_Category_en = "Entra ID",
    Alert_SubCategory_en = "Anomaly Identity Privilege Modification",
    Alert_Name_en = "Authentication Method Changed for Privileged Account",
    Alert_Description_en =  strcat(
                            "At Taiwan time: ",
                            format_datetime(datetime_utc_to_local(TimeGenerated, "Asia/Taipei"), "yyyy-MM-dd HH:mm:ss"),
                            "in the Microsoft Entra ID tenant"
    ", user:  ",
                            iff(isnotempty(Initiator), Initiator, ""),
                            " at IP: ",
                            IP,
                            ", performed an authentication method change"
                        ),
    Alert_TriageStep_en = strcat(
                          "1. Check whether there are successful records for the authentication method change."
    "2. Confirm with user: ",
                          iff(isnotempty(Initiator), Initiator, ""),
                          " whether the change was performed."
                      ),
    Alert_Containment_en = strcat(
                           "1. Immediately revoke all existing sign-in tokens and sessions (sign-in session / refresh token) for the account, and force password and MFA reset.  ",
                           "2. Immediately disable the account."
                       ),
    Alert_Remediation_en = strcat(
                           "1. Strengthen security info governance for Admin/VIP accounts and require additional verification or manual review for security info changes.",
                           "2. Enforce advanced Conditional Access policies for high-privilege accounts, including MFA/compliant devices/risk-based sign-in policies, and block change activity from unknown locations or new devices.  ",
                           "3. Establish and optimize real-time alerts and automated response SOAR for security info changes, such as automatically blocking accounts/notifying SOC/requesting user confirmation.  "
                       ),
            Alert_Time_TW = datetime_utc_to_local(TimeGenerated, "Asia/Taipei"),
    Alert_Time_UTC0 = TimeGenerated,
    Event_Action = Actions,
    Event_Status = Result,
    //Event_Description = ActivityDisplayName,
    Source_Identity_FullName = Initiator,
    //Source_Identity_ID = ActorID,
    Source_Identity_Type = iff(isnotempty(Initiator), "User", "Service"),
    Source_Network_IPAddress = IP,
    Source_Network_IPLocation = Source_Network_IPLocation,
    Source_Resource_Name = InitiatingAppServicePrincipalName,
    Target_Identity_FullName = Targets,
    Target_Identity_Type = "User",
    Target_Resource_Type = "Entra ID"
//CreateTime:2025/1/5
//EditTime:
//Editor:Lancy
//Version v1.0
entityMappings:
- entityType: Account
  fieldMappings:
  - columnName: Source_Identity_FullName
    identifier: Name
- entityType: Account
  fieldMappings:
  - columnName: Target_Identity_FullName
    identifier: Name
- entityType: IP
  fieldMappings:
  - columnName: Source_Network_IPAddress
    identifier: Address
query: |
  let queryperiod = 1d;
  let queryfrequency = 1d;
  let security_info_actions = dynamic(["User registered security info", "User changed default security info", "User deleted security info", "Admin updated security info", "Admin deleted security info", "Admin registered security info"]);
  let VIPUsers = (
      IdentityInfo
      | where TimeGenerated > ago(queryperiod)
      | mv-expand AssignedRoles
      | where AssignedRoles contains 'Admin'
      | summarize by AccountUPN);
  AuditLogs
  | where TimeGenerated > ago(queryperiod)
  | where Category =~ "UserManagement"
  | where ActivityDisplayName in (security_info_actions)
  | extend Initiator = tostring(InitiatedBy.user.userPrincipalName)
  | extend IP = tostring(InitiatedBy.user.ipAddress)
  | extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
  | extend InitiatingAppServicePrincipalName = tostring(InitiatedBy.app.servicePrincipalName)
  | mv-apply TargetResource = TargetResources on
      (
      where TargetResource.type =~ "User"
      | extend Target = tostring(TargetResource.userPrincipalName)
      )
  | where Target in~ (VIPUsers)
  // Uncomment the line below if you are experiencing high volumes of Target entities. If this is uncommented, the Target column will not be mapped to an entity.
  //| summarize Start=min(TimeGenerated), End=max(TimeGenerated), Actions = make_set(ResultReason, MaxSize=8), Targets=make_set(Target, MaxSize=256) by Initiator, IP, Result
  // Comment out this line below, if line above is used.
  | summarize
      Start=min(TimeGenerated),
      End=max(TimeGenerated),
      Actions = make_set(ResultReason, MaxSize=8),
      Target_ResourceName = make_set(TargetResources)
      by
      Initiator,
      IP,
      Result,
      Targets = Target,
      InitiatingAppServicePrincipalId,
      InitiatingAppServicePrincipalName,
      bin(TimeGenerated, 1h)
  | mv-expand Actions
  | extend
      Action = tostring(Actions),
      InitiatorName = tostring(split(Initiator, '@', 0)[0]),
      InitiatorUPNSuffix = tostring(split(Initiator, '@', 1)[0]),
      //TargetName = iff(tostring(Targets) has "[", "", tostring(split(Targets, '@', 0)[0])),
      TargetUPNSuffix = iff(tostring(Targets) has "[", "", tostring(split(Targets, '@', 1)[0]))
  | extend Source_Network_IPLocation = ""
  | project
          Alert_Category_en = "Entra ID",
      Alert_SubCategory_en = "Anomaly Identity Privilege Modification",
      Alert_Name_en = "Authentication Method Changed for Privileged Account",
      Alert_Description_en =  strcat(
                              "At Taiwan time: ",
                              format_datetime(datetime_utc_to_local(TimeGenerated, "Asia/Taipei"), "yyyy-MM-dd HH:mm:ss"),
                              "in the Microsoft Entra ID tenant"
      ", user:  ",
                              iff(isnotempty(Initiator), Initiator, ""),
                              " at IP: ",
                              IP,
                              ", performed an authentication method change"
                          ),
      Alert_TriageStep_en = strcat(
                            "1. Check whether there are successful records for the authentication method change."
      "2. Confirm with user: ",
                            iff(isnotempty(Initiator), Initiator, ""),
                            " whether the change was performed."
                        ),
      Alert_Containment_en = strcat(
                             "1. Immediately revoke all existing sign-in tokens and sessions (sign-in session / refresh token) for the account, and force password and MFA reset.  ",
                             "2. Immediately disable the account."
                         ),
      Alert_Remediation_en = strcat(
                             "1. Strengthen security info governance for Admin/VIP accounts and require additional verification or manual review for security info changes.",
                             "2. Enforce advanced Conditional Access policies for high-privilege accounts, including MFA/compliant devices/risk-based sign-in policies, and block change activity from unknown locations or new devices.  ",
                             "3. Establish and optimize real-time alerts and automated response SOAR for security info changes, such as automatically blocking accounts/notifying SOC/requesting user confirmation.  "
                         ),
              Alert_Time_TW = datetime_utc_to_local(TimeGenerated, "Asia/Taipei"),
      Alert_Time_UTC0 = TimeGenerated,
      Event_Action = Actions,
      Event_Status = Result,
      //Event_Description = ActivityDisplayName,
      Source_Identity_FullName = Initiator,
      //Source_Identity_ID = ActorID,
      Source_Identity_Type = iff(isnotempty(Initiator), "User", "Service"),
      Source_Network_IPAddress = IP,
      Source_Network_IPLocation = Source_Network_IPLocation,
      Source_Resource_Name = InitiatingAppServicePrincipalName,
      Target_Identity_FullName = Targets,
      Target_Identity_Type = "User",
      Target_Resource_Type = "Entra ID"
  //CreateTime:2025/1/5
  //EditTime:
  //Editor:Lancy
  //Version v1.0
id: 9f7197b6-eeb2-46f3-83b1-a2c4dfca46a0
queryFrequency: 1d
status: Available
severity: High
relevantTechniques:
- T1098
version: 1.0.0
kind: Scheduled
tactics:
- Persistence
requiredDataConnectors:
- dataTypes:
  - AuditLogs
  connectorId: AzureActiveDirectory
description: |
  Detects changes to authentication methods on privileged accounts. This may indicate an attacker added a new method to maintain access.
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/eDCRule/Analytic%20Rules/%5BEntra%20ID%5D%20Authentication%20Method%20Changed%20for%20Privileged%20Account.yaml
triggerOperator: gt
name: '[Entra ID] Authentication Method Changed for Privileged Account'
triggerThreshold: 0
queryPeriod: 1d
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "workspace": {
      "type": "String"
    }
  },
  "resources": [
    {
      "apiVersion": "2024-01-01-preview",
      "id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/9f7197b6-eeb2-46f3-83b1-a2c4dfca46a0')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/9f7197b6-eeb2-46f3-83b1-a2c4dfca46a0')]",
      "properties": {
        "alertRuleTemplateName": "9f7197b6-eeb2-46f3-83b1-a2c4dfca46a0",
        "customDetails": null,
        "description": "Detects changes to authentication methods on privileged accounts. This may indicate an attacker added a new method to maintain access.\n",
        "displayName": "[Entra ID] Authentication Method Changed for Privileged Account",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "Source_Identity_FullName",
                "identifier": "Name"
              }
            ]
          },
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "Target_Identity_FullName",
                "identifier": "Name"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "Source_Network_IPAddress",
                "identifier": "Address"
              }
            ]
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/eDCRule/Analytic%20Rules/%5BEntra%20ID%5D%20Authentication%20Method%20Changed%20for%20Privileged%20Account.yaml",
        "query": "let queryperiod = 1d;\nlet queryfrequency = 1d;\nlet security_info_actions = dynamic([\"User registered security info\", \"User changed default security info\", \"User deleted security info\", \"Admin updated security info\", \"Admin deleted security info\", \"Admin registered security info\"]);\nlet VIPUsers = (\n    IdentityInfo\n    | where TimeGenerated > ago(queryperiod)\n    | mv-expand AssignedRoles\n    | where AssignedRoles contains 'Admin'\n    | summarize by AccountUPN);\nAuditLogs\n| where TimeGenerated > ago(queryperiod)\n| where Category =~ \"UserManagement\"\n| where ActivityDisplayName in (security_info_actions)\n| extend Initiator = tostring(InitiatedBy.user.userPrincipalName)\n| extend IP = tostring(InitiatedBy.user.ipAddress)\n| extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)\n| extend InitiatingAppServicePrincipalName = tostring(InitiatedBy.app.servicePrincipalName)\n| mv-apply TargetResource = TargetResources on\n    (\n    where TargetResource.type =~ \"User\"\n    | extend Target = tostring(TargetResource.userPrincipalName)\n    )\n| where Target in~ (VIPUsers)\n// Uncomment the line below if you are experiencing high volumes of Target entities. If this is uncommented, the Target column will not be mapped to an entity.\n//| summarize Start=min(TimeGenerated), End=max(TimeGenerated), Actions = make_set(ResultReason, MaxSize=8), Targets=make_set(Target, MaxSize=256) by Initiator, IP, Result\n// Comment out this line below, if line above is used.\n| summarize\n    Start=min(TimeGenerated),\n    End=max(TimeGenerated),\n    Actions = make_set(ResultReason, MaxSize=8),\n    Target_ResourceName = make_set(TargetResources)\n    by\n    Initiator,\n    IP,\n    Result,\n    Targets = Target,\n    InitiatingAppServicePrincipalId,\n    InitiatingAppServicePrincipalName,\n    bin(TimeGenerated, 1h)\n| mv-expand Actions\n| extend\n    Action = tostring(Actions),\n    InitiatorName = tostring(split(Initiator, '@', 0)[0]),\n    InitiatorUPNSuffix = tostring(split(Initiator, '@', 1)[0]),\n    //TargetName = iff(tostring(Targets) has \"[\", \"\", tostring(split(Targets, '@', 0)[0])),\n    TargetUPNSuffix = iff(tostring(Targets) has \"[\", \"\", tostring(split(Targets, '@', 1)[0]))\n| extend Source_Network_IPLocation = \"\"\n| project\n        Alert_Category_en = \"Entra ID\",\n    Alert_SubCategory_en = \"Anomaly Identity Privilege Modification\",\n    Alert_Name_en = \"Authentication Method Changed for Privileged Account\",\n    Alert_Description_en =  strcat(\n                            \"At Taiwan time: \",\n                            format_datetime(datetime_utc_to_local(TimeGenerated, \"Asia/Taipei\"), \"yyyy-MM-dd HH:mm:ss\"),\n                            \"in the Microsoft Entra ID tenant\"\n    \", user:  \",\n                            iff(isnotempty(Initiator), Initiator, \"\"),\n                            \" at IP: \",\n                            IP,\n                            \", performed an authentication method change\"\n                        ),\n    Alert_TriageStep_en = strcat(\n                          \"1. Check whether there are successful records for the authentication method change.\"\n    \"2. Confirm with user: \",\n                          iff(isnotempty(Initiator), Initiator, \"\"),\n                          \" whether the change was performed.\"\n                      ),\n    Alert_Containment_en = strcat(\n                           \"1. Immediately revoke all existing sign-in tokens and sessions (sign-in session / refresh token) for the account, and force password and MFA reset.  \",\n                           \"2. Immediately disable the account.\"\n                       ),\n    Alert_Remediation_en = strcat(\n                           \"1. Strengthen security info governance for Admin/VIP accounts and require additional verification or manual review for security info changes.\",\n                           \"2. Enforce advanced Conditional Access policies for high-privilege accounts, including MFA/compliant devices/risk-based sign-in policies, and block change activity from unknown locations or new devices.  \",\n                           \"3. Establish and optimize real-time alerts and automated response SOAR for security info changes, such as automatically blocking accounts/notifying SOC/requesting user confirmation.  \"\n                       ),\n            Alert_Time_TW = datetime_utc_to_local(TimeGenerated, \"Asia/Taipei\"),\n    Alert_Time_UTC0 = TimeGenerated,\n    Event_Action = Actions,\n    Event_Status = Result,\n    //Event_Description = ActivityDisplayName,\n    Source_Identity_FullName = Initiator,\n    //Source_Identity_ID = ActorID,\n    Source_Identity_Type = iff(isnotempty(Initiator), \"User\", \"Service\"),\n    Source_Network_IPAddress = IP,\n    Source_Network_IPLocation = Source_Network_IPLocation,\n    Source_Resource_Name = InitiatingAppServicePrincipalName,\n    Target_Identity_FullName = Targets,\n    Target_Identity_Type = \"User\",\n    Target_Resource_Type = \"Entra ID\"\n//CreateTime:2025/1/5\n//EditTime:\n//Editor:Lancy\n//Version v1.0\n",
        "queryFrequency": "P1D",
        "queryPeriod": "P1D",
        "severity": "High",
        "status": "Available",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "Persistence"
        ],
        "techniques": [
          "T1098"
        ],
        "templateVersion": "1.0.0",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}