Skip to content

Commit 909ff9c

Browse files
new hunt 'Microsoft Entra Infrequent Suspicious OData Client Requests' (#4708)
Co-authored-by: Colson Wilhoit <[email protected]>
1 parent 8f27c24 commit 909ff9c

File tree

4 files changed

+155
-0
lines changed

4 files changed

+155
-0
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Microsoft Entra Infrequent Suspicious OData Client Requests
2+
3+
---
4+
5+
## Metadata
6+
7+
- **Author:** Elastic
8+
- **Description:** Identifies infrequent OData client requests in Microsoft Entra ID. This behavior may indicate an adversary using a custom or Azure-managed app ID to authenticate on behalf of a user. This is a rare event and may indicate an attempt to bypass conditional access policies (CAP) and multi-factor authentication (MFA) requirements. The app ID specified may not be commonly used by the user based on their historical sign-in activity. The OData client is used in ROADTools, a toolset leveraged by threat actors to automate OAuth and OIDC workflows in Microsoft Entra ID following phishing or token theft.
9+
10+
- **UUID:** `0d3d2254-2b4a-11f0-a019-f661ea17fbcc`
11+
- **Integration:** [azure](https://docs.elastic.co/integrations/azure)
12+
- **Language:** `[ES|QL]`
13+
- **Source File:** [Microsoft Entra Infrequent Suspicious OData Client Requests](../queries/entra_suspicious_odata_client_requests.toml)
14+
15+
## Query
16+
17+
```sql
18+
FROM logs-azure.auditlogs* METADATA _id, _index
19+
20+
// Only Microsoft Entra ID audit logs
21+
| WHERE event.dataset == "azure.auditlogs"
22+
23+
// Identify logs with the known suspicious OData user agent
24+
AND azure.auditlogs.properties.additional_details.value LIKE "Microsoft.OData.Client/*"
25+
AND azure.auditlogs.identity != "Device Registration Service"
26+
27+
// Extract time window for pattern analysis
28+
| EVAL time_window = DATE_TRUNC(1d, @timestamp)
29+
30+
// Normalize actor: prefer user UPN if available, else fallback to app name
31+
| EVAL actor = COALESCE(
32+
azure.auditlogs.properties.initiated_by.user.userPrincipalName,
33+
azure.auditlogs.properties.initiated_by.app.displayName,
34+
"unknown"
35+
)
36+
37+
// Keep core fields
38+
| KEEP @timestamp, actor, source.ip, azure.auditlogs.operation_name, azure.auditlogs.properties.activity_display_name, azure.auditlogs.identity, azure.auditlogs.properties.tenantId, azure.auditlogs.properties.initiated_by.app.servicePrincipalId, azure.auditlogs.properties.category, azure.auditlogs.properties.additional_details.value, time_window
39+
40+
// Group by actor per day
41+
| STATS
42+
count = COUNT(),
43+
unique_ips = COUNT_DISTINCT(source.ip),
44+
operations = VALUES(azure.auditlogs.operation_name),
45+
identities = VALUES(azure.auditlogs.identity),
46+
ips = VALUES(source.ip),
47+
categories = VALUES(azure.auditlogs.properties.category),
48+
clients = VALUES(azure.auditlogs.properties.additional_details.value)
49+
BY actor, time_window
50+
51+
// Optional: prioritize less frequent actors
52+
| SORT count ASC
53+
```
54+
55+
## Notes
56+
57+
- Review `azure.auditlogs.properties.additional_details.value` for `Microsoft.OData.Client/*` User-Agent strings. This is uncommon for legitimate first-party Microsoft applications and may indicate use of ROADTools or custom automation to register a device and obtain a PRT.
58+
- Check `azure.auditlogs.properties.initiated_by` for both `user` and `app` fields. The presence of both may suggest an OAuth on-behalf-of (OBO) flow, where the app is acting with delegated permissions from a phished user token.
59+
- Review `azure.auditlogs.properties.activity_display_name` and `operation_name` for device registration operations like `Add device` or `Add registered owner to device`. When combined with suspicious user-agents, this may indicate unauthorized device registration.
60+
- Review `azure.auditlogs.identity` for operations performed by `Device Registration Service`. This service name is commonly associated with device join flows that, if abused, may enable persistence via PRT acquisition.
61+
- Correlate with `azure.signinlogs` for sign-ins using the same `correlation_id` or `userPrincipalName`. Look for signs of previous OAuth token issuance or multi-geo IP behavior surrounding the device registration.
62+
- Investigate whether the device registered (under `azure.auditlogs.properties.target_resources`) corresponds to known or authorized endpoints. Devices with names like `DESKTOP-ATTACKER1` or unexpected OS versions may indicate rogue joins.
63+
- The source IP is likely to be Microsoft-managed infrastructure as requests are proxied through Azure services. Pivoting into which user principal the request is targeting and events leading up to the request may provide additional context.
64+
65+
## MITRE ATT&CK Techniques
66+
67+
- [T1078.004](https://attack.mitre.org/techniques/T1078/004)
68+
- [T1550.001](https://attack.mitre.org/techniques/T1550/001)
69+
- [T1098.005](https://attack.mitre.org/techniques/T1098/005)
70+
- [T1071.001](https://attack.mitre.org/techniques/T1071/001)
71+
- [T1556.006](https://attack.mitre.org/techniques/T1556/006)
72+
73+
## References
74+
75+
- https://www.volexity.com/blog/2025/04/22/phishing-for-codes-russian-threat-actors-target-microsoft-365-oauth-workflows/
76+
77+
## License
78+
79+
- `Elastic License v2`
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
[hunt]
2+
author = "Elastic"
3+
description = """
4+
Identifies infrequent OData client requests in Microsoft Entra ID. This behavior may indicate an adversary using a custom or Azure-managed app ID to authenticate on behalf of a user. This is a rare event and may indicate an attempt to bypass conditional access policies (CAP) and multi-factor authentication (MFA) requirements. The app ID specified may not be commonly used by the user based on their historical sign-in activity. The OData client is used in ROADTools, a toolset leveraged by threat actors to automate OAuth and OIDC workflows in Microsoft Entra ID following phishing or token theft.
5+
"""
6+
integration = ["azure"]
7+
uuid = "0d3d2254-2b4a-11f0-a019-f661ea17fbcc"
8+
name = "Microsoft Entra Infrequent Suspicious OData Client Requests"
9+
language = ["ES|QL"]
10+
license = "Elastic License v2"
11+
notes = [
12+
"Review `azure.auditlogs.properties.additional_details.value` for `Microsoft.OData.Client/*` User-Agent strings. This is uncommon for legitimate first-party Microsoft applications and may indicate use of ROADTools or custom automation to register a device and obtain a PRT.",
13+
"Check `azure.auditlogs.properties.initiated_by` for both `user` and `app` fields. The presence of both may suggest an OAuth on-behalf-of (OBO) flow, where the app is acting with delegated permissions from a phished user token.",
14+
"Review `azure.auditlogs.properties.activity_display_name` and `operation_name` for device registration operations like `Add device` or `Add registered owner to device`. When combined with suspicious user-agents, this may indicate unauthorized device registration.",
15+
"Review `azure.auditlogs.identity` for operations performed by `Device Registration Service`. This service name is commonly associated with device join flows that, if abused, may enable persistence via PRT acquisition.",
16+
"Correlate with `azure.signinlogs` for sign-ins using the same `correlation_id` or `userPrincipalName`. Look for signs of previous OAuth token issuance or multi-geo IP behavior surrounding the device registration.",
17+
"Investigate whether the device registered (under `azure.auditlogs.properties.target_resources`) corresponds to known or authorized endpoints. Devices with names like `DESKTOP-ATTACKER1` or unexpected OS versions may indicate rogue joins.",
18+
"The source IP is likely to be Microsoft-managed infrastructure as requests are proxied through Azure services. Pivoting into which user principal the request is targeting and events leading up to the request may provide additional context."
19+
]
20+
mitre = [
21+
"T1078.004",
22+
"T1550.001",
23+
"T1098.005",
24+
"T1071.001",
25+
"T1556.006",
26+
]
27+
references = ["https://www.volexity.com/blog/2025/04/22/phishing-for-codes-russian-threat-actors-target-microsoft-365-oauth-workflows/"]
28+
query = [
29+
'''
30+
FROM logs-azure.auditlogs* METADATA _id, _index
31+
32+
// Only Microsoft Entra ID audit logs
33+
| WHERE event.dataset == "azure.auditlogs"
34+
35+
// Identify logs with the known suspicious OData user agent
36+
AND azure.auditlogs.properties.additional_details.value LIKE "Microsoft.OData.Client/*"
37+
AND azure.auditlogs.identity != "Device Registration Service"
38+
39+
// Extract time window for pattern analysis
40+
| EVAL time_window = DATE_TRUNC(1d, @timestamp)
41+
42+
// Normalize actor: prefer user UPN if available, else fallback to app name
43+
| EVAL actor = COALESCE(
44+
azure.auditlogs.properties.initiated_by.user.userPrincipalName,
45+
azure.auditlogs.properties.initiated_by.app.displayName,
46+
"unknown"
47+
)
48+
49+
// Keep core fields
50+
| KEEP @timestamp, actor, source.ip, azure.auditlogs.operation_name, azure.auditlogs.properties.activity_display_name, azure.auditlogs.identity, azure.auditlogs.properties.tenantId, azure.auditlogs.properties.initiated_by.app.servicePrincipalId, azure.auditlogs.properties.category, azure.auditlogs.properties.additional_details.value, time_window
51+
52+
// Group by actor per day
53+
| STATS
54+
count = COUNT(),
55+
unique_ips = COUNT_DISTINCT(source.ip),
56+
operations = VALUES(azure.auditlogs.operation_name),
57+
identities = VALUES(azure.auditlogs.identity),
58+
ips = VALUES(source.ip),
59+
categories = VALUES(azure.auditlogs.properties.category),
60+
clients = VALUES(azure.auditlogs.properties.additional_details.value)
61+
BY actor, time_window
62+
63+
// Optional: prioritize less frequent actors
64+
| SORT count ASC
65+
'''
66+
]

hunting/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ Here are the queries currently available:
3737
- [Azure Entra Unusual Client App Authentication Requests on Behalf of Principal Users](./azure/docs/entra_unusual_client_app_auth_request_on_behalf_of_user.md) (ES|QL)
3838
- [Azure Entra Unusual Failed Authentication Attempts Behind Rare User Agents](./azure/docs/entra_authentication_attempts_behind_rare_user_agents.md) (ES|QL)
3939
- [Microsoft Entra ID Credentials Added to Rare Service Principal](./azure/docs/entra_service_principal_credentials_added_to_rare_app.md) (ES|QL)
40+
- [Microsoft Entra Infrequent Suspicious OData Client Requests](./azure/docs/entra_suspicious_odata_client_requests.md) (ES|QL)
4041

4142

4243
## linux

hunting/index.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,3 +757,12 @@ azure:
757757
path: ./azure/queries/entra_service_principal_credentials_added_to_rare_app.toml
758758
mitre:
759759
- T1098.001
760+
0d3d2254-2b4a-11f0-a019-f661ea17fbcc:
761+
name: Microsoft Entra Infrequent Suspicious OData Client Requests
762+
path: ./azure/queries/entra_suspicious_odata_client_requests.toml
763+
mitre:
764+
- T1078.004
765+
- T1550.001
766+
- T1098.005
767+
- T1071.001
768+
- T1556.006

0 commit comments

Comments
 (0)