Entra Graph directory enumeration
Repeated Microsoft Graph reads of directory objects from one identity — the shape of a tenant being enumerated rather than used.
What it detects
Repeated Microsoft Graph reads of directory objects from one identity — the shape of a tenant being enumerated rather than used.
Directory enumeration leaves NO audit-log entry at all: reading Entra ID is not a change, so tools that map a tenant's users, groups, service principals, owners and role assignments to find an attack path (AzureHound, ROADrecon and friends) are invisible everywhere except Graph activity logs. What distinguishes them from an application doing its job is volume and breadth against directory endpoints in a short window, which is what this rule counts.
MITRE ATT&CK mapping
False positives and triage
Identity governance, HR sync, SIEM collectors and IAM tooling read these same endpoints constantly and will cross this threshold every run — baseline the app registrations that legitimately do so and treat them as expected. The signal is enumeration from an INTERACTIVE user identity rather than a service principal, from an IP the tenant does not normally serve, or paging with $top=999 across object types the caller has no functional reason to read. Note this counts reads and so measures reconnaissance, not compromise; pair it with what the identity did next.
The rule
Declarative YAML read by the detection engine — data, never executed. Confidence 60%. Source: rules/cloud/entra_graph_directory_enumeration.yaml, licensed under the Apache License 2.0.
id: cloud.identity.entra_graph_directory_enumeration
version: 1.0.0
status: stable
severity: medium
confidence: 0.6
platforms: [application]
mitre_techniques: [T1087.004, T1069.003]
description: |
Repeated Microsoft Graph reads of directory objects from one identity — the shape
of a tenant being enumerated rather than used.
Directory enumeration leaves NO audit-log entry at all: reading Entra ID is not a
change, so tools that map a tenant's users, groups, service principals, owners and
role assignments to find an attack path (AzureHound, ROADrecon and friends) are
invisible everywhere except Graph activity logs. What distinguishes them from an
application doing its job is volume and breadth against directory endpoints in a
short window, which is what this rule counts.
match:
provider: MicrosoftGraph
url_path_contains_any:
- "/servicePrincipals"
- "/directoryRoles"
- "/roleManagement"
- "/groups"
- "/users"
- "/applications"
- "/devices"
threshold:
count: 10
window_seconds: 600
group_by: [user_name]
correlation_keys: [user_name]
false_positive_guidance: |
Identity governance, HR sync, SIEM collectors and IAM tooling read these same
endpoints constantly and will cross this threshold every run — baseline the app
registrations that legitimately do so and treat them as expected. The signal is
enumeration from an INTERACTIVE user identity rather than a service principal,
from an IP the tenant does not normally serve, or paging with `$top=999` across
object types the caller has no functional reason to read. Note this counts reads
and so measures reconnaissance, not compromise; pair it with what the identity did
next.
Related detections
Run this rule on your own logs — offline
KIROSEC runs this rule and the rest of the library over Windows, Linux, macOS and cloud audit logs on the analyst's own machine. Every alert links to the events that raised it, and nothing leaves the device.
