Detection rules › Kusto
[Entra ID] Authentication Method Changed for Privileged Account
Detects changes to authentication methods on privileged accounts. This may indicate an attacker added a new method to maintain access.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Persistence |
Telemetry coverage
Rules detecting the same action
These rules filter on the same operation.
- Account Created and Deleted in Short Timeframe (Kusto)
- Account Created And Deleted Within A Close Time Frame (Sigma)
- Account created from non-approved sources (Kusto)
- Account created or deleted by non-approved user (Kusto)
- Addition of a Temporary Access Pass to a Privileged Account (Kusto)
- Authentication Method Changed for Privileged Account (Kusto)
- Authentication Methods Changed for Privileged Account (Kusto)
- Azure AD External Guest User Invited (Splunk)
Rule body
id: 9f7197b6-eeb2-46f3-83b1-a2c4dfca46a0
name: "[Entra ID] Authentication Method Changed for Privileged Account"
version: 1.0.0
kind: Scheduled
description: |
Detects changes to authentication methods on privileged accounts. This may indicate an attacker added a new method to maintain access.
severity: High
status: Available
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AuditLogs
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
relevantTechniques:
- T1098
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
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: Source_Identity_FullName
- entityType: Account
fieldMappings:
- identifier: Name
columnName: Target_Identity_FullName
- entityType: IP
fieldMappings:
- identifier: Address
columnName: Source_Network_IPAddress
Stages and Predicates
Parameters
let queryperiod = 1d;
let queryfrequency = 1d;
Let binding: security_info_actions
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 binding: VIPUsers
let VIPUsers = (
IdentityInfo
| where TimeGenerated > ago(queryperiod)
| mv-expand AssignedRoles
| where AssignedRoles contains 'Admin'
| summarize by AccountUPN);
Stage 1: source
let VIPUsers
Stage 2: source
AuditLogs
Stage 3: where
where TimeGenerated > ago(86400s)
Stage 4: where
where Category =~ "UserManagement"
Stage 5: where
where ActivityDisplayName in~ ("Admin deleted security info", "Admin registered security info", "Admin updated security info", "User changed default security info", "User deleted security info", "User registered security info")
Stage 6: extend (4 consecutive steps)
extend IP, InitiatingAppServicePrincipalId, InitiatingAppServicePrincipalName, Initiator
Stage 7: kusto:mv-apply
kusto:mv-apply type =~ "User"
Stage 8: where
where Target =~ "VIPUsers"
Stage 9: summarize
summarize Actions, End, Start, Target_ResourceName, Targets by Initiator, IP, Result, Targets, InitiatingAppServicePrincipalId, InitiatingAppServicePrincipalName
Stage 10: mv-expand
mv-expand Actions
Stage 11: extend
extend Action, InitiatorName, InitiatorUPNSuffix, TargetUPNSuffix
TargetUPNSuffix =if
Targets has "["""else
tostring(split(Targets, '@', 1)[0])Stage 12: extend
extend Source_Network_IPLocation
Stage 13: 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_Status, Source_Identity_FullName, Source_Identity_Type, Source_Network_IPAddress, Source_Network_IPLocation, Source_Resource_Name, Target_Identity_FullName, Target_Identity_Type, Target_Resource_Type
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ActivityDisplayName | in |
| field:"azure_ad::activity_display_name" kind:in |
Category | eq |
| field:"Category" kind:eq value:"UserManagement" |
Target | in |
| field:"Target" kind:in value:"VIPUsers" |
type | eq |
| field:"type" kind:eq value:"User" |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Alert_Category_en | project |
Alert_Containment_en | project |
Alert_Description_en | project |
Alert_Name_en | project |
Alert_Remediation_en | project |
Alert_SubCategory_en | project |
Alert_Time_TW | project |
Alert_Time_UTC0 | project |
Alert_TriageStep_en | project |
Event_Action | project |
Event_Status | project |
Source_Identity_FullName | project |
Source_Identity_Type | project |
Source_Network_IPAddress | project |
Source_Network_IPLocation | project |
Source_Resource_Name | project |
Target_Identity_FullName | project |
Target_Identity_Type | project |
Target_Resource_Type | project |