Azure AD Graph Access with Unusual User and ASN

Identifies Azure AD Graph (graph.windows.net) requests originating from network sources outside the major public-cloud and Microsoft ASNs that legitimate first-party callers normally come from. Adversary tooling typically rides on commodity hosting (residential ISPs, VPS providers, anonymisers) which produces an ASN distribution very different from the Microsoft / AWS / GCP / Akamai / Cloudflare ranges that dominate legitimate AAD Graph traffic.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2026/05/20"
  3integration = ["azure"]
  4maturity = "production"
  5updated_date = "2026/05/20"
  6
  7[rule]
  8author = ["Elastic"]
  9description = """
 10Identifies Azure AD Graph (graph.windows.net) requests originating from network sources outside the major
 11public-cloud and Microsoft ASNs that legitimate first-party callers normally come from. Adversary tooling
 12typically rides on commodity hosting (residential ISPs, VPS providers, anonymisers) which produces an ASN
 13distribution very different from the Microsoft / AWS / GCP / Akamai / Cloudflare ranges that dominate
 14legitimate AAD Graph traffic.
 15"""
 16false_positives = [
 17    """
 18    Users calling AAD Graph from corporate office networks or home ISPs with custom tooling. Tune the
 19    excluded ASN organisation list to your environment.
 20    """,
 21    """
 22    Cloud-hosted internal automation running outside the major providers (smaller cloud or colo). Add
 23    exceptions on the calling user or app ID after validation.
 24    """,
 25]
 26from = "now-9m"
 27index = ["logs-azure.aadgraphactivitylogs-*"]
 28language = "kuery"
 29license = "Elastic License v2"
 30name = "Azure AD Graph Access with Unusual User and ASN"
 31note = """## Triage and analysis
 32
 33### Investigating Azure AD Graph Access with Unusual User and ASN
 34
 35Legitimate AAD Graph callers in most tenants come from a small set of ASNs: Microsoft itself, the major
 36hyperscalers (AWS, GCP), and a handful of CDN / edge -networks that proxy first-party traffic. AAD Graph
 37traffic originating from outside that set, especially from residential ISPs, generic VPS providers, or
 38anonymising networks, is a signal worth a closer look. This rule excludes the common Microsoft / AWS /
 39GCP / Akamai / Cloudflare ASN organisations and surfaces everything else.
 40
 41### Possible investigation steps
 42
 43- Identify the ASN and the geographic context.
 44    - `source.as.organization.name`, `source.as.number`, `source.geo.country_name`, `source.geo.city_name`.
 45- Identify the user and whether the source matches normal behavior.
 46    - `user.id` and recent legitimate sign-in geo / network for the same user.
 47- Cross-check user-agent and calling client for known offensive tooling fingerprints.
 48    - `user_agent.original` (`aiohttp`, `AADInternals`, `curl`, etc.) and `azure.aadgraphactivitylogs.properties.app_id` (FOCI / first-party client IDs).
 49- Pivot to sign-in logs (`logs-azure.signinlogs-*`) for the same user / source IP to understand how the calling token was obtained.
 50- Check tenant-wide blast radius.
 51    - Are other users in the tenant calling from the same ASN within the window? If so, treat as a systematic intrusion rather than a single account compromise.
 52- Confirm the activity is not attributable to authorized testing (red team engagement, penetration test, internal tooling validation) before treating as malicious.
 53
 54### Response and remediation
 55
 56- Revoke refresh tokens and active sessions for the calling user.
 57    - `POST /v1.0/users/{id}/revokeSignInSessions`.
 58- Temporarily disable the user if the alert is high-confidence or you need to halt further activity while investigation continues.
 59    - `PATCH /v1.0/users/{id}` with body `{"accountEnabled": false}`.
 60- Check for device registrations created by the user during or around the burst window and remove rogue devices.
 61    - `GET /v1.0/users/{id}/registeredDevices` and `GET /v1.0/users/{id}/ownedDevices`, then `DELETE /v1.0/devices/{deviceObjectId}`.
 62    - Do this BEFORE session revocation: device-bound PRTs survive `revokeSignInSessions`.
 63- Apply Conditional Access requiring compliant device or trusted network for AAD Graph access for the affected user population.
 64- If the ASN belongs to known abusive infrastructure, add it to a tenant block list (Named Locations / CA policy).
 65"""
 66references = [
 67    "https://learn.microsoft.com/en-us/graph/migrate-azure-ad-graph-overview",
 68    "https://github.com/dirkjanm/ROADtools",
 69]
 70risk_score = 47
 71rule_id = "fb935960-d132-4bb5-853d-62f86cccc250"
 72setup = """#### Azure AD Graph Activity Logs
 73Requires Azure AD Graph Activity Logs ingested into `logs-azure.aadgraphactivitylogs-*` via the Elastic Azure
 74integration. Enable the `AzureADGraphActivityLogs` diagnostic-settings category on Entra ID. ASN enrichment
 75depends on the geoip / ASN ingest pipelines applied during integration ingestion.
 76"""
 77severity = "medium"
 78tags = [
 79    "Domain: Cloud",
 80    "Data Source: Azure",
 81    "Data Source: Azure AD Graph",
 82    "Data Source: Azure AD Graph Activity Logs",
 83    "Use Case: Identity and Access Audit",
 84    "Use Case: Threat Detection",
 85    "Tactic: Initial Access",
 86    "Resources: Investigation Guide",
 87]
 88timestamp_override = "event.ingested"
 89type = "new_terms"
 90
 91query = '''
 92data_stream.dataset:azure.aadgraphactivitylogs and
 93    user.id:* and source.as.number:(* and
 94        not (
 95            3598 or 7224 or 8068 or 8069 or 8070 or
 96            8071 or 8072 or 8073 or 8074 or 8075 or
 97            8987 or 12076 or 14618 or 15169 or 16509 or
 98            19527 or 36040 or 36384 or 36385 or 36492 or
 99            39111 or 394089 or 396982
100        )
101    )
102'''
103
104[rule.investigation_fields]
105field_names = [
106    "user.id",
107    "source.ip",
108    "source.as.number",
109    "source.as.organization.name",
110    "source.geo.country_name",
111    "source.geo.city_name",
112    "user_agent.original",
113    "azure.aadgraphactivitylogs.properties.app_id",
114    "azure.aadgraphactivitylogs.properties.api_version",
115    "azure.tenant_id",
116]
117
118[[rule.threat]]
119framework = "MITRE ATT&CK"
120
121[[rule.threat.technique]]
122id = "T1078"
123name = "Valid Accounts"
124reference = "https://attack.mitre.org/techniques/T1078/"
125[[rule.threat.technique.subtechnique]]
126id = "T1078.004"
127name = "Cloud Accounts"
128reference = "https://attack.mitre.org/techniques/T1078/004/"
129
130
131[rule.threat.tactic]
132id = "TA0001"
133name = "Initial Access"
134reference = "https://attack.mitre.org/tactics/TA0001/"
135
136
137[rule.new_terms]
138field = "new_terms_fields"
139value = ["user.id", "source.as.number"]
140
141[[rule.new_terms.history_window_start]]
142field = "history_window_start"
143value = "now-7d"```

Triage and analysis

Investigating Azure AD Graph Access with Unusual User and ASN

Legitimate AAD Graph callers in most tenants come from a small set of ASNs: Microsoft itself, the major hyperscalers (AWS, GCP), and a handful of CDN / edge -networks that proxy first-party traffic. AAD Graph traffic originating from outside that set, especially from residential ISPs, generic VPS providers, or anonymising networks, is a signal worth a closer look. This rule excludes the common Microsoft / AWS / GCP / Akamai / Cloudflare ASN organisations and surfaces everything else.

Possible investigation steps

  • Identify the ASN and the geographic context.
    • source.as.organization.name, source.as.number, source.geo.country_name, source.geo.city_name.
  • Identify the user and whether the source matches normal behavior.
    • user.id and recent legitimate sign-in geo / network for the same user.
  • Cross-check user-agent and calling client for known offensive tooling fingerprints.
    • user_agent.original (aiohttp, AADInternals, curl, etc.) and azure.aadgraphactivitylogs.properties.app_id (FOCI / first-party client IDs).
  • Pivot to sign-in logs (logs-azure.signinlogs-*) for the same user / source IP to understand how the calling token was obtained.
  • Check tenant-wide blast radius.
    • Are other users in the tenant calling from the same ASN within the window? If so, treat as a systematic intrusion 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}.
  • 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.
  • Apply Conditional Access requiring compliant device or trusted network for AAD Graph access for the affected user population.
  • If the ASN belongs to known abusive infrastructure, add it to a tenant block list (Named Locations / CA policy).

References

Related rules

to-top