LoFP LoFP / bulk provisioning workflows, autopilot/mdm rollouts, or device-management tooling that registers devices on behalf of users may generate multiple registrations across many users at once. suppress during planned rollout windows.

Techniques

Sample rules

Entra ID Multiple Device Registrations by a Single User

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.*