-
Notifications
You must be signed in to change notification settings - Fork 664
[New Rule] Azure AD Graph Access with Unusual Client and User #6182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
terrancedejesus
wants to merge
8
commits into
main
Choose a base branch
from
new-rule/azure-ad-graph-unusual-client-and-user
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+161
−0
Open
Changes from 5 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
5d80866
[New Rule] Azure AD Graph Access with Unusual Client and User
terrancedejesus 4b73404
rule updates
terrancedejesus 32ef92a
adjusting description; adding min-stack
terrancedejesus 0c15c6c
Merge branch 'main' into new-rule/azure-ad-graph-unusual-client-and-user
terrancedejesus e7e7139
removing min-stack requirement
terrancedejesus 492a2b0
Merge branch 'main' into new-rule/azure-ad-graph-unusual-client-and-user
terrancedejesus ef0e11e
Merge branch 'main' into new-rule/azure-ad-graph-unusual-client-and-user
Mikaayenson 1a40600
Apply suggestion from @Mikaayenson
terrancedejesus File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
161 changes: 161 additions & 0 deletions
161
rules/integrations/azure/discovery_aad_graph_unusual_client_for_user.toml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,161 @@ | ||
| [metadata] | ||
| creation_date = "2026/05/22" | ||
| integration = ["azure"] | ||
| maturity = "production" | ||
| updated_date = "2026/05/2" | ||
|
|
||
| [rule] | ||
| author = ["Elastic"] | ||
| description = """ | ||
| Identifies Azure AD Graph (graph.windows.net) requests where the combination of calling OAuth client | ||
| ("azure.aadgraphactivitylogs.properties.app_id") and signed-in user ("user.id") has not been observed in the tenant in | ||
| a historical window. A user appearing against AAD Graph under an OAuth client that has not previously authenticated | ||
| that user is a sign of a FOCI swap, a phished refresh token being redeemed for a new client, or an adversary running | ||
| tooling under a client identity the user does not normally use. | ||
| """ | ||
| false_positives = [ | ||
| """ | ||
| First-time use of a legitimate first-party or sanctioned client by the user (newly installed app, first sign-in to a | ||
| workload, fresh PowerShell module install). Validate by `azure.aadgraphactivitylogs.properties.app_id` and the | ||
| user's history. | ||
| """, | ||
| " Authorized red team or audit activity. Add exceptions on the calling user after review.\n ", | ||
| ] | ||
| from = "now-9m" | ||
| index = ["logs-azure.aadgraphactivitylogs-*"] | ||
| language = "kuery" | ||
| license = "Elastic License v2" | ||
| name = "Azure AD Graph Access with Unusual Client and User" | ||
| note = """## Triage and analysis | ||
|
|
||
| ### Investigating Entra ID AAD Graph Access by Unusual Client and User | ||
|
|
||
| A (client, user) pair appearing on AAD Graph for the first time in 14 days is a high-signal indicator. Legacy | ||
| AAD Graph traffic is dominated by a small set of recognised first-party callers per user; new combinations | ||
| suggest one of: | ||
|
|
||
| - A FOCI refresh-token swap landed under a new client identity. | ||
| - The user newly consented to (or was phished into consenting to) an OAuth application. | ||
| - An adversary is using stolen tokens / credentials under a client identity the user does not normally use. | ||
|
|
||
| ### Possible investigation steps | ||
|
|
||
| - Identify the calling client and confirm whether the app is sanctioned. | ||
| - `azure.aadgraphactivitylogs.properties.app_id`. Pivot to Azure portal → Enterprise Applications to check whether it is first-party, sanctioned third-party, or unfamiliar. | ||
| - Identify the user and check the surrounding auth context. | ||
| - `user.id`, then pivot to sign-in logs (`logs-azure.signinlogs-*`) for the same user around the same time. Look for unusual sign-in geography, MFA bypass, or risky session signals. | ||
| - Review source posture. | ||
| - `user_agent.original`, `source.ip`, `source.as.organization.name`. Residential / VPS / anonymising-network egress raises priority. | ||
| - Review what was queried. | ||
| - `url.path`. Bulk recon or User-collection access via internal API versions raises triage priority. | ||
| - Check tenant-wide blast radius for the client. | ||
| - Is the same client ID hitting AAD Graph for many other users? That pattern points to large-scale consent abuse rather than a single account compromise. | ||
| - Confirm the activity is not attributable to authorized testing (red team engagement, penetration test, internal tooling validation) before treating as malicious. | ||
|
|
||
| ### Response and remediation | ||
|
|
||
| - Revoke refresh tokens and active sessions for the calling user. | ||
| - `POST /v1.0/users/{id}/revokeSignInSessions`. | ||
| - Temporarily disable the user if the alert is high-confidence or you need to halt further activity while investigation continues. | ||
| - `PATCH /v1.0/users/{id}` with body `{"accountEnabled": false}`. | ||
| - If the client is not a sanctioned application, revoke its OAuth consent. | ||
| - `GET /v1.0/oauth2PermissionGrants?$filter=clientId eq '{servicePrincipalId}'`, then `DELETE /v1.0/oauth2PermissionGrants/{grantId}`. | ||
| - Check for device registrations created by the user during or around the burst window and remove rogue devices. | ||
| - `GET /v1.0/users/{id}/registeredDevices` and `GET /v1.0/users/{id}/ownedDevices`, then `DELETE /v1.0/devices/{deviceObjectId}`. | ||
| - Do this BEFORE session revocation: device-bound PRTs survive `revokeSignInSessions`. | ||
| - If the calling application has no legitimate AAD Graph dependency, block further use by that app. | ||
| - `PATCH /beta/applications/{id}` with body `{"authenticationBehaviors": {"blockAzureADGraphAccess": true}}`. | ||
| - This property lives on the Graph beta endpoint, not v1.0. | ||
| """ | ||
| references = [ | ||
| "https://github.com/secureworks/family-of-client-ids-research", | ||
| "https://learn.microsoft.com/en-us/graph/migrate-azure-ad-graph-overview", | ||
| "https://dirkjanm.io/phishing-for-microsoft-entra-primary-refresh-tokens/", | ||
| ] | ||
| risk_score = 47 | ||
| rule_id = "fd9d2933-f0f9-4aac-810c-a31f6a4a7890" | ||
| setup = """#### Azure AD Graph Activity Logs | ||
| Requires Azure AD Graph Activity Logs ingested into `logs-azure.aadgraphactivitylogs-*` via the Elastic Azure | ||
| integration. Enable the `AzureADGraphActivityLogs` diagnostic-settings category on Entra ID. | ||
| """ | ||
| severity = "medium" | ||
| tags = [ | ||
| "Domain: Cloud", | ||
| "Data Source: Azure", | ||
| "Data Source: Azure AD Graph", | ||
| "Data Source: Azure AD Graph Activity Logs", | ||
| "Use Case: Threat Detection", | ||
| "Tactic: Defense Evasion", | ||
| "Tactic: Discovery", | ||
| "Resources: Investigation Guide", | ||
| ] | ||
| timestamp_override = "event.ingested" | ||
| type = "new_terms" | ||
|
|
||
| query = ''' | ||
| data_stream.dataset:"azure.aadgraphactivitylogs" and | ||
| azure.aadgraphactivitylogs.properties.actor_type : "User" and | ||
| azure.aadgraphactivitylogs.properties.app_id: (* and not ( | ||
| "74658136-14ec-4630-ad9b-26e160ff0fc6" or | ||
| "bb8f18b0-9c38-48c9-a847-e1ef3af0602d" or | ||
| "00000006-0000-0ff1-ce00-000000000000" or | ||
| "18ed3507-a475-4ccb-b669-d66bc9f2a36e") | ||
| ) and user.id:* | ||
| ''' | ||
|
|
||
|
|
||
| [[rule.threat]] | ||
| framework = "MITRE ATT&CK" | ||
| [[rule.threat.technique]] | ||
| id = "T1550" | ||
| name = "Use Alternate Authentication Material" | ||
| reference = "https://attack.mitre.org/techniques/T1550/" | ||
| [[rule.threat.technique.subtechnique]] | ||
| id = "T1550.001" | ||
| name = "Application Access Token" | ||
| reference = "https://attack.mitre.org/techniques/T1550/001/" | ||
|
|
||
|
|
||
|
|
||
| [rule.threat.tactic] | ||
| id = "TA0005" | ||
| name = "Defense Evasion" | ||
| reference = "https://attack.mitre.org/tactics/TA0005/" | ||
| [[rule.threat]] | ||
| framework = "MITRE ATT&CK" | ||
| [[rule.threat.technique]] | ||
| id = "T1087" | ||
| name = "Account Discovery" | ||
| reference = "https://attack.mitre.org/techniques/T1087/" | ||
| [[rule.threat.technique.subtechnique]] | ||
| id = "T1087.004" | ||
| name = "Cloud Account" | ||
| reference = "https://attack.mitre.org/techniques/T1087/004/" | ||
|
|
||
|
|
||
|
|
||
| [rule.threat.tactic] | ||
| id = "TA0007" | ||
| name = "Discovery" | ||
| reference = "https://attack.mitre.org/tactics/TA0007/" | ||
|
|
||
| [rule.investigation_fields] | ||
| field_names = [ | ||
| "user.id", | ||
| "source.ip", | ||
| "source.as.organization.name", | ||
| "user_agent.original", | ||
| "azure.aadgraphactivitylogs.properties.app_id", | ||
| "azure.aadgraphactivitylogs.properties.api_version", | ||
| "url.path", | ||
| "azure.tenant_id", | ||
| ] | ||
|
|
||
| [rule.new_terms] | ||
| field = "new_terms_fields" | ||
| value = ["azure.aadgraphactivitylogs.properties.app_id", "user.id"] | ||
| [[rule.new_terms.history_window_start]] | ||
| field = "history_window_start" | ||
| value = "now-7d" | ||
|
|
||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.