Microsoft Entra ID Session Reuse with Suspicious Graph Access
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 within a short time window. This may indicate the use of a stolen refresh/access token or session cookie to impersonate the user and interact with Microsoft services.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2025/05/08"
3integration = ["azure"]
4maturity = "production"
5min_stack_comments = "Elastic ES|QL values aggregation is more performant in 8.16.5 and above."
6min_stack_version = "8.17.0"
7updated_date = "2025/05/08"
8
9[rule]
10author = ["Elastic"]
11description = """
12Identifies potential session hijacking or token replay in Microsoft Entra ID. This rule detects cases where a user signs
13in and subsequently accesses Microsoft Graph from a different IP address using the same session ID within a short time
14window. This may indicate the use of a stolen refresh/access token or session cookie to impersonate the user and
15interact with Microsoft services.
16"""
17false_positives = [
18 """
19 This pattern may occur during legitimate device switching or roaming between networks (e.g., corporate to mobile).
20 Developers or power users leveraging multiple environments may also trigger this detection if session persistence
21 spans IP ranges. Still, this behavior is rare and warrants investigation when rapid IP switching and Graph access
22 are involved.
23 """,
24]
25from = "now-1h"
26language = "esql"
27license = "Elastic License v2"
28name = "Microsoft Entra ID Session Reuse with Suspicious Graph Access"
29note = """## Triage and analysis
30
31### Investigating Microsoft Entra ID Session Reuse with Suspicious Graph Access
32
33This rule identifies when Microsoft Graph is accessed from a different IP than the one used for the original sign-in,
34but using the same session ID within 5 minutes. This may suggest an adversary has stolen a session cookie or refresh/access
35token and is impersonating the user from an alternate host or location.
36
37This rule uses ES|QL aggregations and thus has dynamically generated fields. Correlation of the values in the alert document may need to be
38performed to the original sign-in and Graph events for further context.
39
40### Investigation Steps
41
42- Review the `user_id`, `session_id`, and `source_ip_list`. Confirm whether both IPs belong to the same user and geography.
43- Check for inconsistencies in `client_id_list` (e.g., unknown apps) or user agents across correlated events.
44- Investigate recent phishing reports or device infections for the `user_id`.
45- Pivot to Entra ID `auditlogs` to see if a device was registered or privileges were modified.
46- Review `graph_time` to determine what action was taken after the sign-in.
47- Use the `session_id` to correlate with other logs in the same time window to identify any additional suspicious activity.
48
49### False Positive Analysis
50- This pattern may occur if the user is switching between networks (e.g., corporate to mobile) or using a VPN.
51- Developers or power users leveraging multiple environments may also trigger this detection if session persistence spans IP ranges.
52- However, this behavior is rare and warrants investigation when rapid IP switching and Graph access are involved.
53- If the user is a developer or automation engineer, validate if this behavior was for testing purposes.
54- If the user is a system administrator, validate if this behavior was for administrative purposes.
55
56### Response Recommendations
57
58- If confirmed malicious, revoke all refresh/access tokens for the `user_id`.
59- Block the source IP(s) involved in the Graph access.
60- Notify the user and reset credentials.
61- Review session control policies and conditional access enforcement.
62- Monitor for follow-on activity, such as lateral movement or privilege escalation.
63- Review conditional access policies to ensure they are enforced correctly.
64"""
65references = [
66 "https://www.volexity.com/blog/2025/04/22/phishing-for-codes-russian-threat-actors-target-microsoft-365-oauth-workflows/",
67 "https://github.com/dirkjanm/ROADtools",
68 "https://attack.mitre.org/techniques/T1078/004/",
69]
70risk_score = 73
71rule_id = "0d3d2254-2b4a-11f0-a019-f661ea17fbcc"
72setup = """#### Required Microsoft Entra ID Sign-In and Graph Activity Logs
73This 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.
74"""
75severity = "high"
76tags = [
77 "Domain: Cloud",
78 "Data Source: Azure",
79 "Data Source: Microsoft Entra ID",
80 "Data Source: Microsoft Entra ID Sign-In Logs",
81 "Data Source: Microsoft Graph",
82 "Data Source: Microsoft Graph Activity Logs",
83 "Use Case: Identity and Access Audit",
84 "Use Case: Threat Detection",
85 "Resources: Investigation Guide",
86 "Tactic: Defense Evasion",
87 "Tactic: Initial Access",
88]
89timestamp_override = "event.ingested"
90type = "esql"
91
92query = '''
93FROM logs-azure.*
94| WHERE
95 (event.dataset == "azure.signinlogs" AND source.`as`.organization.name != "MICROSOFT-CORP-MSN-AS-BLOCK" AND azure.signinlogs.properties.session_id IS NOT NULL)
96 OR
97 (event.dataset == "azure.graphactivitylogs" AND source.`as`.organization.name != "MICROSOFT-CORP-MSN-AS-BLOCK" AND azure.graphactivitylogs.properties.c_sid IS NOT NULL)
98| EVAL
99 session_id = COALESCE(azure.signinlogs.properties.session_id, azure.graphactivitylogs.properties.c_sid),
100 user_id = COALESCE(azure.signinlogs.properties.user_id, azure.graphactivitylogs.properties.user_principal_object_id),
101 client_id = COALESCE(azure.signinlogs.properties.app_id, azure.graphactivitylogs.properties.app_id),
102 source_ip = source.ip,
103 event_time = @timestamp,
104 event_type = CASE(
105 event.dataset == "azure.signinlogs", "signin",
106 event.dataset == "azure.graphactivitylogs", "graph",
107 "other"
108 ),
109 time_window = DATE_TRUNC(5 minutes, @timestamp)
110| KEEP session_id, source_ip, event_time, event_type, time_window, user_id, client_id
111| STATS
112 user_id = VALUES(user_id),
113 session_id = VALUES(session_id),
114 source_ip_list = VALUES(source_ip),
115 source_ip_count = COUNT_DISTINCT(source_ip),
116 client_id_list = VALUES(client_id),
117 application_count = COUNT_DISTINCT(client_id),
118 event_type_list = VALUES(event_type),
119 event_type_count = COUNT_DISTINCT(event_type),
120 event_start = MIN(event_time),
121 event_end = MAX(event_time),
122 signin_time = MIN(CASE(event_type == "signin", event_time, NULL)),
123 graph_time = MIN(CASE(event_type == "graph", event_time, NULL)),
124 document_count = COUNT()
125 BY session_id, time_window
126| EVAL
127 duration_minutes = DATE_DIFF("minutes", event_start, event_end),
128 signin_to_graph_delay_minutes = DATE_DIFF("minutes", signin_time, graph_time)
129| WHERE
130 event_type_count > 1 AND
131 source_ip_count > 1 AND
132 duration_minutes <= 5 AND
133 signin_time IS NOT NULL AND
134 graph_time IS NOT NULL AND
135 signin_to_graph_delay_minutes >= 0
136'''
137
138
139[[rule.threat]]
140framework = "MITRE ATT&CK"
141[[rule.threat.technique]]
142id = "T1078"
143name = "Valid Accounts"
144reference = "https://attack.mitre.org/techniques/T1078/"
145[[rule.threat.technique.subtechnique]]
146id = "T1078.004"
147name = "Cloud Accounts"
148reference = "https://attack.mitre.org/techniques/T1078/004/"
149
150
151
152[rule.threat.tactic]
153id = "TA0001"
154name = "Initial Access"
155reference = "https://attack.mitre.org/tactics/TA0001/"
156[[rule.threat]]
157framework = "MITRE ATT&CK"
158[[rule.threat.technique]]
159id = "T1550"
160name = "Use Alternate Authentication Material"
161reference = "https://attack.mitre.org/techniques/T1550/"
162[[rule.threat.technique.subtechnique]]
163id = "T1550.001"
164name = "Application Access Token"
165reference = "https://attack.mitre.org/techniques/T1550/001/"
166
167
168
169[rule.threat.tactic]
170id = "TA0005"
171name = "Defense Evasion"
172reference = "https://attack.mitre.org/tactics/TA0005/"
Triage and analysis
Investigating Microsoft Entra ID Session Reuse with Suspicious Graph Access
This rule identifies when Microsoft Graph is accessed from a different IP than the one used for the original sign-in, but using the same session ID within 5 minutes. This may suggest 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 ES|QL 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.
Investigation Steps
- Review the
user_id
,session_id
, andsource_ip_list
. Confirm whether both IPs belong to the same user and geography. - Check for inconsistencies in
client_id_list
(e.g., unknown apps) or user agents across correlated events. - Investigate recent phishing reports or device infections for the
user_id
. - Pivot to Entra ID
auditlogs
to see if a device was registered or privileges were modified. - Review
graph_time
to determine what action was taken after the sign-in. - Use the
session_id
to correlate with other logs in the same time window to identify any additional suspicious activity.
False Positive Analysis
- This pattern may occur if the user is switching between networks (e.g., corporate to mobile) or using a VPN.
- Developers or power users leveraging multiple environments may also trigger this detection if session persistence spans IP ranges.
- However, this behavior is rare and warrants investigation when rapid IP switching and Graph access are involved.
- If the user is a developer or automation engineer, validate if this behavior was for testing purposes.
- If the user is a system administrator, validate if this behavior was for administrative purposes.
Response Recommendations
- If confirmed malicious, revoke all refresh/access tokens for the
user_id
. - 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
- Microsoft Graph First Occurrence of Client Request
- Microsoft Entra ID Rare Authentication Requirement for Principal User
- Microsoft Azure or Mail Sign-in from a Suspicious Source
- Suspicious Activity via Auth Broker On-Behalf-of Principal User
- Multiple Microsoft Entra ID Protection Alerts by User Principal