Detection rules › Elastic

Entra ID AiTM Phishing-Kit Chain Detected

Status
production
Severity
high
Time window
3m
Sequence by
azure.auditlogs.properties.initiated_by.user.id, azure.signinlogs.properties.user_id
Author
Elastic
Source
github.com/elastic/detection-rules

Identifies a Microsoft Entra ID identity-compromise chain in which a single user, within a 10-minute window, authenticates to the Device Registration Service through the Microsoft Authentication Broker (MAB) client, registers a device, and then uses the resulting Primary Refresh Token (PRT) to access a resource other than the Device Registration Service. This sequence is the core post-adversary-in-the-middle (AiTM) persistence pattern used by phishing kits such as Tycoon2FA and Kali365: after capturing a victim session, the kit registers an Azure AD-joined device to obtain a device-bound PRT, which survives user-level session revocation and password resets and grants trusted, MFA-free access. Correlating the broker sign-in, the device-registration audit event, and the follow-on PRT sign-in for the same user within a short window is a high-fidelity indicator of active account takeover.

Known false positives

  • Legitimate device onboarding (for example a user enrolling a new corporate device through Azure AD join) can produce a broker authentication to the Device Registration Service followed by PRT issuance. Validate that the device, source IP/ASN, and user agent are expected, and that the device is managed/compliant.
  • Authorized red team or penetration testing engagements that register devices and exercise PRTs will match this sequence. Document the engagement and add scoped exceptions for the involved principals or source addresses.

MITRE ATT&CK coverage

Telemetry coverage

Rules detecting the same action

These rules filter on the same operation.

Rule body

[metadata]
creation_date = "2026/06/29"
integration = ["azure"]
maturity = "production"
updated_date = "2026/06/29"

[rule]
author = ["Elastic"]
description = """
Identifies a Microsoft Entra ID identity-compromise chain in which a single user, within a 10-minute window,
authenticates to the Device Registration Service through the Microsoft Authentication Broker (MAB) client, registers a
device, and then uses the resulting Primary Refresh Token (PRT) to access a resource other than the Device Registration
Service. This sequence is the core post-adversary-in-the-middle (AiTM) persistence pattern used by phishing kits such as
Tycoon2FA and Kali365: after capturing a victim session, the kit registers an Azure AD-joined device to obtain a
device-bound PRT, which survives user-level session revocation and password resets and grants trusted, MFA-free access.
Correlating the broker sign-in, the device-registration audit event, and the follow-on PRT sign-in for the same user
within a short window is a high-fidelity indicator of active account takeover.
"""
false_positives = [
    """
    Legitimate device onboarding (for example a user enrolling a new corporate device through Azure AD join) can produce
    a broker authentication to the Device Registration Service followed by PRT issuance. Validate that the device,
    source IP/ASN, and user agent are expected, and that the device is managed/compliant.
    """,
    """
    Authorized red team or penetration testing engagements that register devices and exercise PRTs will match this
    sequence. Document the engagement and add scoped exceptions for the involved principals or source addresses.
    """,
]
from = "now-15m"
index = ["logs-azure.signinlogs-*", "logs-azure.auditlogs-*"]
language = "eql"
license = "Elastic License v2"
name = "Entra ID AiTM Phishing-Kit Chain Detected"
note = """## Triage and analysis

### Investigating Entra ID AiTM Phishing-Kit Chain Detected

This rule correlates three events for the same user within a 10-minute window that together represent the canonical post-AiTM identity-compromise chain:

1. A non-interactive sign-in through the Microsoft Authentication Broker (MAB) client (`app_id` `29d9ed98-a469-4536-ade2-f981bc1d605e`) to the `Device Registration Service` resource, with an `unbound` session token (`token_protection_status_details.sign_in_session_status`).
2. A successful `Register device` audit event initiated by the same user for a target device named `DESKTOP-*`.
3. An interactive sign-in using a `primaryRefreshToken` (PRT) to a resource other than the Device Registration Service, from an unmanaged device.

After an AiTM kit captures a victim session, it registers an Azure AD-joined device to obtain a device-bound PRT. Because the PRT is bound to the device rather than the user session, it survives `revokeSignInSessions` and password resets, providing durable, MFA-free access. Observing the broker-to-DRS auth, the registration, and the first PRT use in quick succession is strong evidence of active account takeover rather than benign onboarding.

### Possible investigation steps

- Identify the user via `azure.signinlogs.properties.user_principal_name` / `azure.signinlogs.properties.user_id` and the registered device via the `Register device` event (`azure.auditlogs.properties.target_resources.0.display_name`). Default `DESKTOP-<random>` names that do not match your convention are suspicious.
- Review the source of each step: `source.ip`, `source.as.organization.name`, and `source.geo.*`. Hosting/VPS ASNs (for example Tencent or Alibaba) and unexpected geographies, or a single source driving all three steps, are high-fidelity suspicious.
- Inspect the registration user agent on the `Register device` event (`azure.auditlogs.properties.userAgent`); a spoofed `Dsreg/10.0 (Windows <build>)` string or a raw HTTP client such as `axios/*` or `python-requests/*` indicates tooling.
- Confirm the PRT step: `azure.signinlogs.properties.incoming_token_type` is `primaryRefreshToken`, the device `trust_type` is `Azure AD joined`, and `device_detail.is_managed` is false (unmanaged), and the `resource_display_name` is a real resource (Microsoft Graph, Office 365 Exchange Online, etc.) rather than the Device Registration Service.
- Check for additional persistence established in the same window: an attacker-registered MFA method (`User registered security info`), multiple device registrations by the same user, or broker tokens minted for other resources.
- Review Conditional Access outcomes to determine whether device compliance or MFA was bypassed.

### False positive analysis

- Legitimate Azure AD join / device onboarding can produce a broker-to-DRS auth followed by PRT issuance. Validate the device against inventory and confirm it is managed/compliant and registered from an expected source.
- Authorized security assessments that register devices and exercise PRTs will match. Document and add scoped exceptions.

### Response and remediation

- Treat as likely account takeover. Remove the rogue device registration BEFORE revoking sessions, because device-bound PRTs survive `revokeSignInSessions` and a device left in place re-establishes access.
    - `GET /v1.0/users/{id}/registeredDevices` and `/ownedDevices`, then `DELETE /v1.0/devices/{deviceObjectId}` for unrecognized devices.
- Revoke refresh tokens and sessions, then reset credentials and re-register MFA.
    - `POST /v1.0/users/{id}/revokeSignInSessions`.
- Temporarily disable the account if activity must be halted during investigation.
    - `PATCH /v1.0/users/{id}` with body `{"accountEnabled": false}`.
- Remove other attacker persistence: attacker-registered MFA methods, malicious inbox/forwarding rules, and OAuth consents.
- Tighten device registration and join controls via Conditional Access (restrict who can register/join devices, require MFA for registration, and require a compliant/managed device for resource access).
"""
references = [
    "https://any.run/malware-trends/tycoon/",
    "https://www.huntress.com/blog/kali365-device-code-phishing-kit",
    "https://any.run/malware-trends/kali365/",
    "https://arcticwolf.com/resources/blog/token-bingo-dont-let-your-code-be-the-winner/",
    "https://www.elastic.co/security-labs/tycoon-2fa-aitm-detection-engineering"
]
risk_score = 73
rule_id = "d2c02b2b-bd01-4d4a-a17a-8df8f357b015"
severity = "high"
tags = [
    "Domain: Cloud",
    "Domain: Identity",
    "Data Source: Azure",
    "Data Source: Microsoft Entra ID",
    "Data Source: Microsoft Entra ID Sign-In Logs",
    "Data Source: Microsoft Entra ID Audit Logs",
    "Use Case: Identity and Access Audit",
    "Use Case: Threat Detection",
    "Tactic: Persistence",
    "Tactic: Credential Access",
    "Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "eql"

query = '''
sequence with maxspan=3m
  [authentication where
    data_stream.dataset == "azure.signinlogs" and
    azure.signinlogs.category == "NonInteractiveUserSignInLogs" and
    azure.signinlogs.properties.app_id == "29d9ed98-a469-4536-ade2-f981bc1d605e" and
    azure.signinlogs.properties.resource_display_name == "Device Registration Service" and
    azure.signinlogs.properties.incoming_token_type == "refreshToken" and
    azure.signinlogs.properties.token_protection_status_details.sign_in_session_status == "unbound" and
    azure.signinlogs.properties.user_type == "Member" and
    azure.signinlogs.result_signature == "SUCCESS"
  ] by azure.signinlogs.properties.user_id
  [any where
    data_stream.dataset == "azure.auditlogs" and
    azure.auditlogs.operation_name == "Register device" and
    azure.auditlogs.properties.initiated_by.user.id != null and
    azure.auditlogs.properties.target_resources.`0`.display_name like "DESKTOP-*" and
    event.outcome == "success"
  ] by azure.auditlogs.properties.initiated_by.user.id
  [authentication where
    data_stream.dataset == "azure.signinlogs" and
    azure.signinlogs.properties.incoming_token_type == "primaryRefreshToken" and
    azure.signinlogs.properties.original_transfer_method == "deviceCodeFlow" and
    azure.signinlogs.properties.is_interactive == true and
    azure.signinlogs.properties.resource_display_name != "Device Registration Service" and
    azure.signinlogs.properties.device_detail.is_managed != true and
    azure.signinlogs.result_signature == "SUCCESS"
  ] by azure.signinlogs.properties.user_id
'''


[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1078"
name = "Valid Accounts"
reference = "https://attack.mitre.org/techniques/T1078/"
[[rule.threat.technique.subtechnique]]
id = "T1078.004"
name = "Cloud Accounts"
reference = "https://attack.mitre.org/techniques/T1078/004/"


[[rule.threat.technique]]
id = "T1098"
name = "Account Manipulation"
reference = "https://attack.mitre.org/techniques/T1098/"
[[rule.threat.technique.subtechnique]]
id = "T1098.005"
name = "Device Registration"
reference = "https://attack.mitre.org/techniques/T1098/005/"



[rule.threat.tactic]
id = "TA0003"
name = "Persistence"
reference = "https://attack.mitre.org/tactics/TA0003/"
[[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 = "T1528"
name = "Steal Application Access Token"
reference = "https://attack.mitre.org/techniques/T1528/"


[rule.threat.tactic]
id = "TA0006"
name = "Credential Access"
reference = "https://attack.mitre.org/tactics/TA0006/"

[rule.investigation_fields]
field_names = [
    "@timestamp",
    "azure.signinlogs.properties.user_principal_name",
    "azure.signinlogs.properties.user_id",
    "azure.signinlogs.properties.app_id",
    "azure.signinlogs.properties.resource_display_name",
    "azure.signinlogs.properties.incoming_token_type",
    "azure.signinlogs.properties.device_detail.trust_type",
    "azure.signinlogs.properties.device_detail.is_managed",
    "azure.auditlogs.operation_name",
    "azure.auditlogs.properties.target_resources.0.display_name",
    "source.ip",
    "source.as.organization.name",
    "source.geo.country_name",
]

Stages and Predicates

Ordered sequence: each step below must occur in order within 3m, correlated by azure.auditlogs.properties.initiated_by.user.id, azure.signinlogs.properties.user_id.

Stage 1: authentication

[authentication where
    data_stream.dataset == "azure.signinlogs" and
    azure.signinlogs.category == "NonInteractiveUserSignInLogs" and
    azure.signinlogs.properties.app_id == "29d9ed98-a469-4536-ade2-f981bc1d605e" and
    azure.signinlogs.properties.resource_display_name == "Device Registration Service" and
    azure.signinlogs.properties.incoming_token_type == "refreshToken" and
    azure.signinlogs.properties.token_protection_status_details.sign_in_session_status == "unbound" and
    azure.signinlogs.properties.user_type == "Member" and
    azure.signinlogs.result_signature == "SUCCESS"
  ] by azure.signinlogs.properties.user_id

Stage 2: any

[any where
    data_stream.dataset == "azure.auditlogs" and
    azure.auditlogs.operation_name == "Register device" and
    azure.auditlogs.properties.initiated_by.user.id != null and
    azure.auditlogs.properties.target_resources.`0`.display_name like "DESKTOP-*" and
    event.outcome == "success"
  ] by azure.auditlogs.properties.initiated_by.user.id

Stage 3: authentication

[authentication where
    data_stream.dataset == "azure.signinlogs" and
    azure.signinlogs.properties.incoming_token_type == "primaryRefreshToken" and
    azure.signinlogs.properties.original_transfer_method == "deviceCodeFlow" and
    azure.signinlogs.properties.is_interactive == true and
    azure.signinlogs.properties.resource_display_name != "Device Registration Service" and
    azure.signinlogs.properties.device_detail.is_managed != true and
    azure.signinlogs.result_signature == "SUCCESS"
  ] by azure.signinlogs.properties.user_id

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
azure.auditlogs.operation_nameeq
  • Register device
field:"azure_ad::activity_display_name" kind:eq value:"Register device"
azure.auditlogs.properties.initiated_by.user.idis_not_null
  • (no value, null check)
field:"azure.auditlogs.properties.initiated_by.user.id" kind:is_not_null
azure.auditlogs.properties.target_resources.0.display_namewildcard
  • DESKTOP-*
field:"azure.auditlogs.properties.target_resources.0.display_name" kind:wildcard value:"DESKTOP-*"
azure.signinlogs.categoryeq
  • NonInteractiveUserSignInLogs
field:"azure_ad::signin_category" kind:eq value:"NonInteractiveUserSignInLogs"
azure.signinlogs.properties.app_ideq
  • 29d9ed98-a469-4536-ade2-f981bc1d605e
field:"azure_ad::app_id" kind:eq value:"29d9ed98-a469-4536-ade2-f981bc1d605e"
azure.signinlogs.properties.device_detail.is_managedne
  • true transforms: boolean
field:"azure.signinlogs.properties.device_detail.is_managed" kind:ne value:"true"
azure.signinlogs.properties.incoming_token_typeeq
  • primaryRefreshToken
  • refreshToken
field:"azure.signinlogs.properties.incoming_token_type" kind:eq
azure.signinlogs.properties.is_interactiveeq
  • true transforms: boolean
field:"azure.signinlogs.properties.is_interactive" kind:eq value:"true"
azure.signinlogs.properties.original_transfer_methodeq
  • deviceCodeFlow
field:"azure.signinlogs.properties.original_transfer_method" kind:eq value:"deviceCodeFlow"
azure.signinlogs.properties.resource_display_nameeq
  • Device Registration Service
field:"azure_ad::resource_display_name" kind:eq value:"Device Registration Service"
azure.signinlogs.properties.resource_display_namene
  • Device Registration Service
field:"azure_ad::resource_display_name" kind:ne value:"Device Registration Service"
azure.signinlogs.properties.token_protection_status_details.sign_in_session_statuseq
  • unbound
field:"azure.signinlogs.properties.token_protection_status_details.sign_in_session_status" kind:eq value:"unbound"
azure.signinlogs.properties.user_typeeq
  • Member
field:"azure_ad::user_type" kind:eq value:"Member"
azure.signinlogs.result_signatureeq
  • SUCCESS
field:"azure.signinlogs.result_signature" kind:eq value:"SUCCESS"
data_stream.dataseteq
  • azure.auditlogs
  • azure.signinlogs
field:"data_stream.dataset" kind:eq
event.outcomeeq
  • success
field:"event.outcome" kind:eq value:"success"