Techniques
Sample rules
Entra ID Multiple Device Registrations by a Single User
- source: elastic
- technicques:
- T1078
- T1098
- T1557
Description
Detects multiple Microsoft Entra ID device registrations by a single user, where three or more distinct devices are registered within a 15-minute window. A legitimate user enrolling a device produces a single “Register device” event; registering multiple distinct devices in quick succession is uncommon and is the fingerprint behavior of adversary-in-the-middle (AiTM) phishing kits and stolen-token replay tooling (for example Kali365), which mint a new Azure AD-joined device, and therefore a new Primary Refresh Token (PRT), per relay or replay attempt. Each registered device is a separate certificate-bound principal whose PRT survives user-level session revocation and password resets, so multiple registrations on a single low-privilege identity establish device-bound persistence at scale.
Detection logic
from logs-azure.auditlogs-*
| where data_stream.dataset == "azure.auditlogs"
and azure.auditlogs.operation_name == "Register device"
and azure.auditlogs.properties.initiated_by.user.userPrincipalName is not null
// For "Register device" the registered device is the primary target resource (index 0);
// target_resources is a numeric-indexed object array in this integration, so wildcard/name-based matching is not available.
and `azure.auditlogs.properties.target_resources.0.display_name` is not null
| eval Esql.bucket_window = date_trunc(15 minutes, @timestamp)
| stats
Esql.count_distinct_devices = count_distinct(`azure.auditlogs.properties.target_resources.0.display_name`),
Esql.device_name_values = values(`azure.auditlogs.properties.target_resources.0.display_name`),
Esql.user_agent_values = values(azure.auditlogs.properties.userAgent),
Esql.source_ip_values = values(source.ip),
Esql.source_as_number_values = values(source.`as`.number),
Esql.source_as_organization_values = values(source.`as`.organization.name),
Esql.source_country_values = values(source.geo.country_name),
Esql.source_city_values = values(source.geo.city_name),
Esql.source_region_values = values(source.geo.region_name),
Esql.correlation_id_values = values(azure.correlation_id),
Esql.timestamp_first_seen = min(@timestamp),
Esql.timestamp_last_seen = max(@timestamp),
Esql.event_count = count(*)
by azure.auditlogs.properties.initiated_by.user.userPrincipalName, Esql.bucket_window
| where Esql.count_distinct_devices >= 3
| keep azure.auditlogs.properties.initiated_by.user.userPrincipalName, Esql.*