Entra ID OAuth User Impersonation to Microsoft Graph
Identifies potential session hijacking or token replay in Microsoft Entra ID. This rule detects cases where a user signs in and subsequently accesses Microsoft Graph from a different IP address using the same session ID. This may indicate a successful OAuth phishing attack, session hijacking, or token replay attack, where an adversary has stolen a session cookie or refresh/access token and is impersonating the user from an alternate host or location.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2025/05/08"
3integration = ["azure"]
4maturity = "production"
5updated_date = "2025/12/17"
6
7[rule]
8author = ["Elastic"]
9description = """
10Identifies potential session hijacking or token replay in Microsoft Entra ID. This rule detects cases where a user signs
11in and subsequently accesses Microsoft Graph from a different IP address using the same session ID. This may indicate a
12successful OAuth phishing attack, session hijacking, or token replay attack, where an adversary has stolen a session
13cookie or refresh/access token and is impersonating the user from an alternate host or location.
14"""
15false_positives = [
16 """
17 This pattern may occur during legitimate device switching or roaming between networks (e.g., corporate to mobile).
18 Developers or power users leveraging multiple environments may also trigger this detection if session persistence
19 spans IP ranges. Still, this behavior is rare and warrants investigation when rapid IP switching and Graph access
20 are involved.
21 """,
22]
23from = "now-31m"
24interval = "30m"
25language = "esql"
26license = "Elastic License v2"
27name = "Entra ID OAuth User Impersonation to Microsoft Graph"
28note = """## Triage and analysis
29
30### Investigating Entra ID OAuth User Impersonation to Microsoft Graph
31
32Identifies potential phishing, session hijacking or token replay in Microsoft Entra ID. This rule detects cases where a user signs in and subsequently accesses Microsoft Graph from a different IP address using the same session ID and client application. This may indicate a successful OAuth phishing attack, session hijacking, or token replay attack, where an adversary has stolen a session cookie or refresh/access token and is impersonating the user from an alternate host or location.
33
34This rule uses ESQL aggregations and thus has dynamically generated fields. Correlation of the values in the alert document may need to be
35performed to the original sign-in and Graph events for further context.
36
37### Possible investigation steps
38
39- This rule relies on an aggregation-based ESQL query, therefore the alert document will contain dynamically generated fields.
40 - To pivot into the original events, it is recommended to use the values captured to filter in timeline or discovery for the original sign-in and Graph events.
41- Review the session ID and user ID to identify the user account involved in the suspicious activity.
42- Check the source addresses involved in the sign-in and Graph access to determine if they are known or expected locations for the user.
43 - The sign-in source addresses should be two, one for the initial phishing sign-in and the other when exchanging the auth code for a token by the adversary.
44 - The Graph API source address should identify the IP address used by the adversary to access Microsoft Graph.
45- Review the user agent strings for the sign-in and Graph access events to identify any anomalies or indicators of compromise.
46- Analyze the Graph permission scopes to identify what resources were accessed and whether they align with the user's expected behavior.
47- Check the timestamp difference between the sign-in and Graph access events to determine if they occurred within a reasonable time frame that would suggest successful phishing to token issuance and then Graph access.
48- Identify the original sign-in event to investigation if conditional access policies were applied, such as requiring multi-factor authentication or blocking access from risky locations. In phishing scenarios, these policies likely were applied as the victim user would have been prompted to authenticate.
49
50### False positive analysis
51- This pattern may occur during legitimate device switching or roaming between networks (e.g., corporate to mobile).
52- Developers or power users leveraging multiple environments may also trigger this detection if session persistence spans IP ranges. Still, this behavior is rare and warrants investigation when rapid IP switching and Graph access are involved.
53
54### Response and remediation
55
56- If confirmed malicious, revoke all refresh/access tokens for the user principal.
57- Block the source IP(s) involved in the Graph access.
58- Notify the user and reset credentials.
59- Review session control policies and conditional access enforcement.
60- Monitor for follow-on activity, such as lateral movement or privilege escalation.
61- Review conditional access policies to ensure they are enforced correctly.
62"""
63references = [
64 "https://www.volexity.com/blog/2025/04/22/phishing-for-codes-russian-threat-actors-target-microsoft-365-oauth-workflows/",
65 "https://github.com/dirkjanm/ROADtools",
66 "https://attack.mitre.org/techniques/T1078/004/",
67 "https://pushsecurity.com/blog/consentfix",
68]
69risk_score = 47
70rule_id = "0d3d2254-2b4a-11f0-a019-f661ea17fbcc"
71setup = """#### Required Microsoft Entra ID Sign-In and Graph Activity Logs
72This rule requires the Microsoft Entra ID Sign-In Logs and Microsoft Graph Activity Logs integration to be enabled and configured to collect audit and activity logs via Azure Event Hub.
73"""
74severity = "medium"
75tags = [
76 "Domain: Cloud",
77 "Domain: Identity",
78 "Domain: API",
79 "Data Source: Azure",
80 "Data Source: Microsoft Entra ID",
81 "Data Source: Microsoft Entra ID Sign-In Logs",
82 "Data Source: Microsoft Graph",
83 "Data Source: Microsoft Graph Activity Logs",
84 "Use Case: Identity and Access Audit",
85 "Use Case: Threat Detection",
86 "Resources: Investigation Guide",
87 "Tactic: Defense Evasion",
88 "Tactic: Initial Access",
89]
90timestamp_override = "event.ingested"
91type = "esql"
92
93query = '''
94from logs-azure.signinlogs-*, logs-azure.graphactivitylogs-* metadata _id, _version, _index
95| where
96 (event.dataset == "azure.signinlogs"
97 and source.`as`.organization.name != "MICROSOFT-CORP-MSN-AS-BLOCK"
98 and azure.signinlogs.properties.session_id is not null)
99 or
100 (event.dataset == "azure.graphactivitylogs"
101 and source.`as`.organization.name != "MICROSOFT-CORP-MSN-AS-BLOCK"
102 and azure.graphactivitylogs.properties.c_sid is not null)
103
104| eval
105 Esql.azure_signinlogs_properties_session_id_coalesce = coalesce(azure.signinlogs.properties.session_id, azure.graphactivitylogs.properties.c_sid),
106 Esql.azure_signinlogs_properties_user_id_coalesce = coalesce(azure.signinlogs.properties.user_id, azure.graphactivitylogs.properties.user_principal_object_id),
107 Esql.azure_signinlogs_properties_app_id_coalesce = coalesce(azure.signinlogs.properties.app_id, azure.graphactivitylogs.properties.app_id),
108 Esql.source_ip = source.ip,
109 Esql.@timestamp = @timestamp,
110 Esql.event_type_case = case(
111 event.dataset == "azure.signinlogs", "signin",
112 event.dataset == "azure.graphactivitylogs", "graph",
113 "other"
114 )
115
116| where Esql.azure_signinlogs_properties_app_id_coalesce not in (
117 "4354e225-50c9-4423-9ece-2d5afd904870", // Augmentation Loop
118 "cc15fd57-2c6c-4117-a88c-83b1d56b4bbe", // Microsoft Teams Services
119 "ecd6b820-32c2-49b6-98a6-444530e5a77a", // Microsoft Edge [Community Contributed]
120 "e8be65d6-d430-4289-a665-51bf2a194bda", // Microsoft 365 App Catalog Services
121 "ab9b8c07-8f02-4f72-87fa-80105867a763", // OneDrive SyncEngine
122 "394866fc-eedb-4f01-8536-3ff84b16be2a", // Microsoft People Cards Service
123 "66a88757-258c-4c72-893c-3e8bed4d6899", // Office 365 Search Service
124 "9ea1ad79-fdb6-4f9a-8bc3-2b70f96e34c7", // Bing
125 "d7b530a4-7680-4c23-a8bf-c52c121d2e87", // Microsoft Edge Enterprise New Tab Page [Community Contributed]
126 "6f7e0f60-9401-4f5b-98e2-cf15bd5fd5e3", // Microsoft Application Command Service [Community Contributed]
127 "52c2e0b5-c7b6-4d11-a89c-21e42bcec444", // Graph Files Manager
128 "27922004-5251-4030-b22d-91ecd9a37ea4", // Outlook Mobile
129 "bb893c22-978d-4cd4-a6f7-bb6cc0d6e6ce", // Olympus [Community Contributed]
130 "26a7ee05-5602-4d76-a7ba-eae8b7b67941", // Windows Search
131 "66a88757-258c-4c72-893c-3e8bed4d6899", // Office 365 Search Service
132 "9ea1ad79-fdb6-4f9a-8bc3-2b70f96e34c7", // Bing
133 "d7b530a4-7680-4c23-a8bf-c52c121d2e87", // Microsoft Edge Enterprise New Tab Page [Community Contributed]
134 "00000007-0000-0000-c000-000000000000", // Dataverse
135 "6bc3b958-689b-49f5-9006-36d165f30e00", // Teams CMD Services Artifacts
136 "0ec893e0-5785-4de6-99da-4ed124e5296c", // Office UWP PWA [Community Contributed]
137 "fc108d3f-543d-4374-bbff-c7c51f651fe5", // Zoom
138 "01fc33a7-78ba-4d2f-a4b7-768e336e890e" // MS PIM
139 )
140
141| keep
142 Esql.azure_signinlogs_properties_session_id_coalesce,
143 Esql.source_ip,
144 Esql.@timestamp,
145 Esql.event_type_case,
146 Esql.azure_signinlogs_properties_user_id_coalesce,
147 Esql.azure_signinlogs_properties_app_id_coalesce,
148 source.`as`.organization.name,
149 user_agent.original,
150 url.original,
151 azure.graphactivitylogs.properties.scopes,
152 azure.signinlogs.properties.user_principal_name
153
154| stats
155 Esql.azure_signinlogs_properties_user_id_coalesce_values = values(Esql.azure_signinlogs_properties_user_id_coalesce),
156 Esql.azure_signinlogs_properties_session_id_coalesce_values = values(Esql.azure_signinlogs_properties_session_id_coalesce),
157 Esql_priv.azure_signinlogs_properties_user_principal_name_values = values(azure.signinlogs.properties.user_principal_name),
158 Esql.source_ip_values = values(Esql.source_ip),
159 Esql.source_ip_count_distinct = count_distinct(Esql.source_ip),
160 Esql.source_as_organization_name_values = values(source.`as`.organization.name),
161 Esql.user_agent_original_values = values(user_agent.original),
162 Esql.azure_signinlogs_properties_app_id_coalesce_values = values(Esql.azure_signinlogs_properties_app_id_coalesce),
163 Esql.azure_signinlogs_properties_app_id_coalesce_count_distinct = count_distinct(Esql.azure_signinlogs_properties_app_id_coalesce),
164 Esql.event_type_case_values = values(Esql.event_type_case),
165 Esql.event_type_case_count_distinct = count_distinct(Esql.event_type_case),
166 Esql.signin_time_min = min(case(Esql.event_type_case == "signin", Esql.@timestamp, null)),
167 Esql.graph_time_min = min(case(Esql.event_type_case == "graph", Esql.@timestamp, null)),
168 Esql.url_original_values = values(url.original),
169 Esql.azure_graphactivitylogs_properties_scopes_values = values(azure.graphactivitylogs.properties.scopes),
170 Esql.event_count = count()
171 by
172 Esql.azure_signinlogs_properties_session_id_coalesce,
173 Esql.azure_signinlogs_properties_app_id_coalesce,
174 Esql.azure_signinlogs_properties_user_id_coalesce
175
176| eval
177 Esql.event_signin_to_graph_delay_minutes_date_diff = date_diff("minutes", Esql.signin_time_min, Esql.graph_time_min),
178 Esql.event_signin_to_graph_delay_days_date_diff = date_diff("days", Esql.signin_time_min, Esql.graph_time_min)
179
180| where
181 Esql.event_type_case_count_distinct > 1 and
182 Esql.source_ip_count_distinct > 1 and
183 Esql.azure_signinlogs_properties_app_id_coalesce_count_distinct == 1 and
184 Esql.signin_time_min is not null and
185 Esql.graph_time_min is not null and
186 Esql.event_signin_to_graph_delay_minutes_date_diff >= 0 and
187 Esql.event_signin_to_graph_delay_days_date_diff == 0
188'''
189
190
191[[rule.threat]]
192framework = "MITRE ATT&CK"
193[[rule.threat.technique]]
194id = "T1078"
195name = "Valid Accounts"
196reference = "https://attack.mitre.org/techniques/T1078/"
197[[rule.threat.technique.subtechnique]]
198id = "T1078.004"
199name = "Cloud Accounts"
200reference = "https://attack.mitre.org/techniques/T1078/004/"
201
202
203
204[rule.threat.tactic]
205id = "TA0001"
206name = "Initial Access"
207reference = "https://attack.mitre.org/tactics/TA0001/"
208[[rule.threat]]
209framework = "MITRE ATT&CK"
210[[rule.threat.technique]]
211id = "T1550"
212name = "Use Alternate Authentication Material"
213reference = "https://attack.mitre.org/techniques/T1550/"
214[[rule.threat.technique.subtechnique]]
215id = "T1550.001"
216name = "Application Access Token"
217reference = "https://attack.mitre.org/techniques/T1550/001/"
218
219
220
221[rule.threat.tactic]
222id = "TA0005"
223name = "Defense Evasion"
224reference = "https://attack.mitre.org/tactics/TA0005/"
Triage and analysis
Investigating Entra ID OAuth User Impersonation to Microsoft Graph
Identifies potential phishing, session hijacking or token replay in Microsoft Entra ID. This rule detects cases where a user signs in and subsequently accesses Microsoft Graph from a different IP address using the same session ID and client application. This may indicate a successful OAuth phishing attack, session hijacking, or token replay attack, where an adversary has stolen a session cookie or refresh/access token and is impersonating the user from an alternate host or location.
This rule uses ESQL aggregations and thus has dynamically generated fields. Correlation of the values in the alert document may need to be performed to the original sign-in and Graph events for further context.
Possible investigation steps
- This rule relies on an aggregation-based ESQL query, therefore the alert document will contain dynamically generated fields.
- To pivot into the original events, it is recommended to use the values captured to filter in timeline or discovery for the original sign-in and Graph events.
- Review the session ID and user ID to identify the user account involved in the suspicious activity.
- Check the source addresses involved in the sign-in and Graph access to determine if they are known or expected locations for the user.
- The sign-in source addresses should be two, one for the initial phishing sign-in and the other when exchanging the auth code for a token by the adversary.
- The Graph API source address should identify the IP address used by the adversary to access Microsoft Graph.
- Review the user agent strings for the sign-in and Graph access events to identify any anomalies or indicators of compromise.
- Analyze the Graph permission scopes to identify what resources were accessed and whether they align with the user's expected behavior.
- Check the timestamp difference between the sign-in and Graph access events to determine if they occurred within a reasonable time frame that would suggest successful phishing to token issuance and then Graph access.
- Identify the original sign-in event to investigation if conditional access policies were applied, such as requiring multi-factor authentication or blocking access from risky locations. In phishing scenarios, these policies likely were applied as the victim user would have been prompted to authenticate.
False positive analysis
- This pattern may occur during legitimate device switching or roaming between networks (e.g., corporate to mobile).
- Developers or power users leveraging multiple environments may also trigger this detection if session persistence spans IP ranges. Still, this behavior is rare and warrants investigation when rapid IP switching and Graph access are involved.
Response and remediation
- If confirmed malicious, revoke all refresh/access tokens for the user principal.
- Block the source IP(s) involved in the Graph access.
- Notify the user and reset credentials.
- Review session control policies and conditional access enforcement.
- Monitor for follow-on activity, such as lateral movement or privilege escalation.
- Review conditional access policies to ensure they are enforced correctly.
References
Related rules
- Entra ID OAuth PRT Issuance to Non-Managed Device Detected
- Entra ID OAuth user_impersonation Scope for Unusual User and Client
- Entra ID OAuth ROPC Grant Login Detected
- Microsoft Graph Request User Impersonation by Unusual Client
- Entra ID Protection - Risk Detection - Sign-in Risk