Skip to content

Commit 4fb8483

Browse files
[Rule Tuning] Suspicious Activity via Auth Broker On-Behalf-of Principal User (#4793)
* rule tuning Suspicious Activity via Auth Broker On-Behalf-of Principal User * adjusted investigation guide * adjusted time
1 parent 1f71191 commit 4fb8483

File tree

2 files changed

+203
-155
lines changed

2 files changed

+203
-155
lines changed

rules/integrations/azure/defense_evasion_entra_suspicious_auth_broker_activity_on_behalf_of_principal_user.toml

Lines changed: 0 additions & 155 deletions
This file was deleted.
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
[metadata]
2+
creation_date = "2025/04/30"
3+
integration = ["azure"]
4+
maturity = "production"
5+
min_stack_comments = "Elastic ES|QL values aggregation is more performant in 8.16.5 and above."
6+
min_stack_version = "8.17.0"
7+
updated_date = "2025/06/11"
8+
9+
[rule]
10+
author = ["Elastic"]
11+
description = """
12+
Identifies separate OAuth authorization flows in Microsoft Entra ID where the same user principal and session ID are
13+
observed across multiple IP addresses within a 5-minute window. These flows involve the Microsoft Authentication Broker
14+
(MAB) as the client application and the Device Registration Service (DRS) as the target resource. This pattern is highly
15+
indicative of OAuth phishing activity, where an adversary crafts a legitimate Microsoft login URL to trick a user into
16+
completing authentication and sharing the resulting authorization code, which is then exchanged for an access and
17+
refresh token by the attacker.
18+
"""
19+
false_positives = [
20+
"""
21+
Legitimate device registrations using Microsoft Authentication Broker may occur during corporate enrollment
22+
scenarios or bulk provisioning, but it is uncommon for multiple source IPs to register the same identity across
23+
Microsoft Graph, Device Registration Service (DRS), and Azure Active Directory (AAD) in a short time span.
24+
""",
25+
]
26+
from = "now-61m"
27+
interval = "60m"
28+
language = "esql"
29+
license = "Elastic License v2"
30+
name = "Suspicious Microsoft OAuth Flow via Auth Broker to DRS"
31+
note = """## Triage and analysis
32+
33+
### Investigating Suspicious Microsoft OAuth Flow via Auth Broker to DRS
34+
35+
This rule identifies potential OAuth phishing behavior in Microsoft Entra ID where two OAuth authorization flows are observed in quick succession, sharing the same user principal and session ID but originating from different IP addresses. The client application is the Microsoft Authentication Broker, and the target resource is the Device Registration Service (DRS). This pattern is indicative of adversaries attempting to phish targets for OAuth sessions by tricking users into authenticating through a crafted URL, which then allows the attacker to obtain an authorization code and exchange it for access and refresh tokens.
36+
37+
### Possible Investigation Steps:
38+
39+
- `target`: The user principal name targeted by the authentication broker. Investigate whether this user has recently registered a device, signed in from new IPs, or had password resets or MFA changes.
40+
- `session_id`: Used to correlate all events in the OAuth flow. All sign-ins in the alert share the same session, suggesting shared or hijacked state.
41+
- `unique_token_id`: Lists tokens generated in the flow. If multiple IDs exist in the same session, this indicates token issuance from different locations.
42+
- `source_ip`, `city_name`, `country_name`, `region_name`: Review the IPs and geolocations involved. A mismatch in geographic origin within minutes can signal adversary involvement.
43+
- `user_agent`: Conflicting user agents (e.g., `python-requests` and `Chrome`) suggest one leg of the session was scripted or automated.
44+
- `os`: If multiple operating systems are observed in the same short session (e.g., macOS and Windows), this may suggest activity from different environments.
45+
- `incoming_token_type`: Look for values like `"none"` or `"refreshToken"` that can indicate abnormal or re-authenticated activity.
46+
- `token_session_status`: A value of `"unbound"` means the issued token is not tied to a device or CAE session, making it reusable from another IP.
47+
- `conditional_access_status`: If this is `"notApplied"`, it may indicate that expected access policies were not enforced.
48+
- `auth_count`: Number of events in the session. More than one indicates the session was reused within the time window.
49+
- `target_time_window`: Use this to pivot into raw sign-in logs to review the exact sequence and timing of the activity.
50+
- Search `azure.auditlogs` for any device join or registration activity around the `target_time_window`.
51+
- Review `azure.identityprotection` logs for anonymized IPs, impossible travel, or token replay alerts.
52+
- Search for other activity from the same IPs across all users to identify horizontal movement.
53+
54+
### False Positive Analysis
55+
56+
- A legitimate device join from a user switching networks (e.g., mobile hotspot to Wi-Fi) could explain multi-IP usage.
57+
- Some identity management agents or EDR tools may use MAB for background device registration flows.
58+
- Developers or IT administrators may access DRS across environments when testing.
59+
60+
### Response and Remediation
61+
62+
- If confirmed unauthorized, revoke all refresh tokens for the user and disable any suspicious registered devices.
63+
- Notify the user and verify if the authentication or device join was expected.
64+
- Review Conditional Access policies for the Microsoft Authentication Broker (`29d9ed98-a469-4536-ade2-f981bc1d605e`) to ensure enforcement of MFA and device trust.
65+
- Consider restricting token-based reauthentication from anonymized infrastructure or unusual user agents.
66+
- Continue monitoring for follow-on activity, such as privilege escalation, token misuse, or lateral movement.
67+
"""
68+
references = [
69+
"https://www.volexity.com/blog/2025/04/22/phishing-for-codes-russian-threat-actors-target-microsoft-365-oauth-workflows/",
70+
"https://github.com/dirkjanm/ROADtools",
71+
"https://dirkjanm.io/phishing-for-microsoft-entra-primary-refresh-tokens/",
72+
]
73+
risk_score = 73
74+
rule_id = "375132c6-25d5-11f0-8745-f661ea17fbcd"
75+
setup = """#### Required Microsoft Entra ID Sign-In Logs
76+
This rule requires the Microsoft Entra ID Sign-In Logs integration be enabled and configured to collect sign-in logs. In Entra ID, sign-in logs must be enabled and streaming to the Event Hub used for the Azure integration.
77+
"""
78+
severity = "high"
79+
tags = [
80+
"Domain: Cloud",
81+
"Domain: Identity",
82+
"Data Source: Azure",
83+
"Data Source: Entra ID",
84+
"Data Source: Entra ID Sign-in Logs",
85+
"Use Case: Identity and Access Audit",
86+
"Use Case: Threat Detection",
87+
"Resources: Investigation Guide",
88+
"Tactic: Initial Access",
89+
]
90+
timestamp_override = "event.ingested"
91+
type = "esql"
92+
93+
query = '''
94+
FROM logs-azure.signinlogs* metadata _id, _version, _index
95+
96+
// Filter for Microsoft Entra ID sign-in logs
97+
| WHERE event.dataset == "azure.signinlogs"
98+
AND event.outcome == "success"
99+
AND azure.signinlogs.properties.user_type == "Member"
100+
AND azure.signinlogs.identity IS NOT NULL
101+
AND azure.signinlogs.properties.user_principal_name IS NOT NULL
102+
AND source.address IS NOT NULL
103+
104+
// Filter for MAB as client (app_id) and DRS as resource (resource_id)
105+
AND azure.signinlogs.properties.app_id == "29d9ed98-a469-4536-ade2-f981bc1d605e" // MAB
106+
AND azure.signinlogs.properties.resource_id == "01cb2876-7ebd-4aa4-9cc9-d28bd4d359a9" // DRS
107+
108+
// Normalize timestamps into 30-minute detection windows
109+
| EVAL target_time_window = DATE_TRUNC(30 minutes, @timestamp)
110+
111+
// Tag browser-based requests and extract session ID
112+
| EVAL
113+
session_id = azure.signinlogs.properties.session_id,
114+
is_browser = CASE(
115+
TO_LOWER(azure.signinlogs.properties.device_detail.browser) RLIKE "(chrome|firefox|edge|safari).*", 1, 0
116+
)
117+
118+
| STATS
119+
// user & session identity
120+
user_display_name = VALUES(azure.signinlogs.properties.user_display_name),
121+
user_principal_name = VALUES(azure.signinlogs.properties.user_principal_name),
122+
session_id = VALUES(azure.signinlogs.properties.session_id),
123+
unique_token_id = VALUES(azure.signinlogs.properties.unique_token_identifier),
124+
125+
// geolocation
126+
city_name = VALUES(source.geo.city_name),
127+
country_name = VALUES(source.geo.country_name),
128+
region_name = VALUES(source.geo.region_name),
129+
source_ip = VALUES(source.address),
130+
ip_count = COUNT_DISTINCT(source.address),
131+
autonomous_system = VALUES(source.`as`.organization.name),
132+
133+
// authentication context
134+
auth_protocol = VALUES(azure.signinlogs.properties.authentication_protocol),
135+
auth_requirement = VALUES(azure.signinlogs.properties.authentication_requirement),
136+
is_interactive = VALUES(azure.signinlogs.properties.is_interactive),
137+
138+
// token & app context
139+
token_type = VALUES(azure.signinlogs.properties.incoming_token_type),
140+
token_session_status = VALUES(azure.signinlogs.properties.token_protection_status_details.sign_in_session_status),
141+
session_id_count = COUNT_DISTINCT(session_id),
142+
client_app_display_name = VALUES(azure.signinlogs.properties.app_display_name),
143+
client_app_ids = VALUES(azure.signinlogs.properties.app_id),
144+
target_resource_ids = VALUES(azure.signinlogs.properties.resource_id),
145+
target_resource_display_name = VALUES(azure.signinlogs.properties.resource_display_name),
146+
147+
// tenant details
148+
app_owner_tenant_id = VALUES(azure.signinlogs.properties.app_owner_tenant_id),
149+
resource_owner_tenant_id = VALUES(azure.signinlogs.properties.resource_owner_tenant_id),
150+
151+
// conditional access & risk signals
152+
conditional_access_status = VALUES(azure.signinlogs.properties.conditional_access_status),
153+
risk_state = VALUES(azure.signinlogs.properties.risk_state),
154+
risk_level_aggregated = VALUES(azure.signinlogs.properties.risk_level_aggregated),
155+
156+
// user agent & device
157+
browser = VALUES(azure.signinlogs.properties.device_detail.browser),
158+
os = VALUES(azure.signinlogs.properties.device_detail.operating_system),
159+
user_agent = VALUES(user_agent.original),
160+
has_browser = MAX(is_browser),
161+
162+
auth_count = COUNT(*)
163+
BY
164+
target_time_window,
165+
azure.signinlogs.properties.user_principal_name,
166+
session_id
167+
168+
| KEEP
169+
target_time_window, user_display_name, user_principal_name, session_id, unique_token_id,
170+
city_name, country_name, region_name, source_ip, ip_count, autonomous_system,
171+
auth_protocol, auth_requirement, is_interactive,
172+
token_type, token_session_status, session_id_count, client_app_display_name,
173+
client_app_ids, target_resource_ids, target_resource_display_name,
174+
app_owner_tenant_id, resource_owner_tenant_id,
175+
conditional_access_status, risk_state, risk_level_aggregated,
176+
browser, os, user_agent, has_browser, auth_count
177+
178+
| WHERE
179+
ip_count >= 2 AND
180+
session_id_count == 1 AND
181+
has_browser >= 1 AND
182+
auth_count >= 2
183+
'''
184+
185+
186+
[[rule.threat]]
187+
framework = "MITRE ATT&CK"
188+
[[rule.threat.technique]]
189+
id = "T1566"
190+
name = "Phishing"
191+
reference = "https://attack.mitre.org/techniques/T1566/"
192+
[[rule.threat.technique.subtechnique]]
193+
id = "T1566.002"
194+
name = "Spearphishing Link"
195+
reference = "https://attack.mitre.org/techniques/T1566/002/"
196+
197+
198+
199+
[rule.threat.tactic]
200+
id = "TA0001"
201+
name = "Initial Access"
202+
reference = "https://attack.mitre.org/tactics/TA0001/"
203+

0 commit comments

Comments
 (0)