Entra ID Device-Bound PRT from Unusual Device IP

Detects a first-party FOCI tooling client (Azure CLI, PowerShell, VS Code, Graph CLI, Azure AD PowerShell, or Visual Studio) redeeming a device-bound Primary Refresh Token (PRT) for Microsoft Graph, SharePoint/OneDrive, or Exchange Online from a source IP that has not been seen with that deviceid. Replay events are limited to compliant or Intune-managed devices. Adversaries who steal a WAM PRT SSO cookie replay it off-box; the token keeps the workstation deviceid, so this pair is new even when Windows Sign-In for that device is outside a correlation window.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2026/08/28"
  3integration = ["azure"]
  4maturity = "production"
  5updated_date = "2026/08/28"
  6
  7[rule]
  8author = ["Elastic"]
  9description = """
 10Detects a first-party FOCI tooling client (Azure CLI, PowerShell, VS Code, Graph CLI, Azure AD PowerShell, or Visual
 11Studio) redeeming a device-bound Primary Refresh Token (PRT) for Microsoft Graph, SharePoint/OneDrive, or Exchange
 12Online from a source IP that has not been seen with that deviceid. Replay events are limited to compliant or
 13Intune-managed devices. Adversaries who steal a WAM PRT SSO cookie replay it off-box; the token keeps the workstation
 14deviceid, so this pair is new even when Windows Sign-In for that device is outside a correlation window.
 15"""
 16false_positives = [
 17    """
 18    A user who runs Azure CLI, Azure PowerShell, VS Code, Graph CLI, or Visual Studio from a new egress (VPN, hotel,
 19    Cloud Shell, jump host) while WAM still attaches a compliant or managed workstation deviceid will match on first
 20    sight of that IP. Exception: add known developer and Cloud Shell ranges after confirming the client ran there.
 21    """,
 22    """
 23    Split-tunnel or dual-homed devices can present a new Microsoft 365 egress for tooling clients. Confirm the IP
 24    belongs to the enrolled device before treating the event as cookie theft.
 25    """,
 26    """
 27    Microsoft Teams, Office, OneDrive SyncEngine, Authentication Broker, Outlook Mobile, Bing, Azure Portal, and Office
 28    365 Management are omitted because first sight of a mobile or M365 egress IP for those clients is routine.
 29    """,
 30]
 31from = "now-9m"
 32index = ["filebeat-*", "logs-azure.signinlogs-*"]
 33language = "kuery"
 34license = "Elastic License v2"
 35name = "Entra ID Device-Bound PRT from Unusual Device IP"
 36note = """## Triage and analysis
 37
 38### Investigating Entra ID Device-Bound PRT from Unusual Device IP
 39
 40This rule fires when a tooling FOCI client redeems a device-bound PRT from a `source.ip` that has not appeared with that `device_id` in the prior 5 days. Unlike **Entra ID Device-Bound PRT Replay via First-Party App from Unusual IP**, it does not need a Windows Sign-In or WAM event in the same window — so a workstation that last signed in yesterday still alerts when the cookie is redeemed from a new address.
 41
 42PRTremote and similar harvest tools steal a WAM PRT SSO cookie and POST it from attacker infrastructure. The issued token keeps the *workstation* deviceid, so Conditional Access that requires a compliant device can succeed. Replay events must be `is_compliant` or `is_managed`. The stolen cookie nonce is typically valid for about five minutes; that is the attacker’s redeem window, not this rule’s history.
 43
 44This is not ConsentFix / OAuth-code phishing. Those flows show `OAuth2:Authorize` with `Redirect` and often lack a bound compliant device.
 45
 46### Possible investigation steps
 47
 48- Review `azure.signinlogs.properties.user_principal_name`, `azure.signinlogs.properties.device_detail.device_id`, `azure.signinlogs.properties.device_detail.display_name`, and `source.ip`. Confirm `incoming_token_type` is `primaryRefreshToken` and `device_detail.is_compliant` / `is_managed` are true.
 49- Compare `azure.signinlogs.properties.app_display_name` and `user_agent.original` with the resource (`resource_display_name`). A cookie POST through WAM can show a Trident/MSIE user agent on the Azure CLI client ID; that is the same IE stack legitimate Windows `az login` uses when it brokers through WAM, so it is triage context, not a detection key. TokenTactics commonly presents as Microsoft Office (that client is omitted here; hunt it separately if harvest is already confirmed).
 50- Hunt prior Windows Sign-In / `Windows-AzureAD-Authentication-Provider/1.0` events for the same deviceid. If those IPs differ from `source.ip`, treat this as the same story as the ES|QL companion. A Microsoft-owned ASN (including 8075) does not clear the alert.
 51- Hunt endpoint telemetry for the same user or device display name as `host.name`: InteractiveToken scheduled tasks, `svchost.exe` (Schedule) → `cmd.exe` → `BrowserCore.exe`, or files `formatted_nonce.txt` / `prt_cookie.txt`.
 52- Review Graph, SharePoint, and mailbox activity after the sign-in for directory, file, or mail enumeration.
 53
 54### False positive analysis
 55
 56- Developers who run Azure CLI, Graph CLI, or VS Code from a new network while WAM still attaches the workstation deviceid. Exception known Cloud Shell / jump-host IPs after confirming the client actually ran there.
 57- First use of a tooling client on a new device, or the first time a laptop appears on a new ISP, will fire once per `(device_id, source.ip)` pair and then age out of novelty.
 58- Hybrid-joined workstations that report both `is_compliant` and `is_managed` as false (no Intune) will not match. Hunt those deviceids separately if harvest is already confirmed.
 59- Microsoft Teams, Office, OneDrive SyncEngine, Authentication Broker, Outlook Mobile, Bing, Azure Portal, and Office 365 Management are excluded. Do not treat their absence as a miss.
 60
 61### Response and remediation
 62
 63- Contact the user to confirm whether they ran the first-party client from `source.ip`.
 64- If unauthorized, revoke refresh tokens and primary refresh tokens for the user. The deviceid on the token is often the *legitimate* workstation — do not delete that device as if it were a ROADtx registration until you confirm otherwise.
 65- Isolate the workstation, hunt for InteractiveToken scheduled tasks and BrowserCore harvest, and treat the admin identity that registered the task as a second compromised principal.
 66"""
 67references = [
 68    "https://www.armadin.com/blog-posts/prtremote-extract-prt-cookies-remotely-with-interactivetoken-scheduled-task",
 69    "https://github.com/armadin-public/PRTremote",
 70    "https://github.com/dmcxblue/ANIMO/blob/master/helpers/scripts/GrabTokenAzureAD/PrtExtractor.cs",
 71    "https://github.com/rvrsh3ll/TokenTactics",
 72    "https://github.com/Gerenios/AADInternals",
 73]
 74risk_score = 73
 75rule_id = "9e8d9bb5-6d3a-4431-a0d0-8d0475e726a4"
 76setup = """The Azure Fleet integration (or Filebeat Azure module) with Microsoft Entra ID sign-in logs is required. Ingest `SignInLogs` and `NonInteractiveUserSignInLogs` into `logs-azure.signinlogs-*`.
 77
 78See [Microsoft Entra ID sign-in logs](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-ins) and the [Azure integration](https://docs.elastic.co/integrations/azure).
 79"""
 80severity = "high"
 81tags = [
 82    "Domain: Cloud",
 83    "Domain: Identity",
 84    "Use Case: Threat Detection",
 85    "Use Case: Identity and Access Audit",
 86    "Data Source: Azure",
 87    "Data Source: Microsoft Entra ID",
 88    "Data Source: Microsoft Entra ID Sign-in Logs",
 89    "Platform: Entra ID",
 90    "Tactic: Credential Access",
 91    "Tactic: Defense Evasion",
 92    "Resources: Investigation Guide",
 93    "Rule Type: New Terms",
 94]
 95timestamp_override = "event.ingested"
 96type = "new_terms"
 97
 98query = '''
 99data_stream.dataset: azure.signinlogs and
100    event.outcome: success and
101    azure.signinlogs.properties.status.error_code: 0 and
102    azure.signinlogs.properties.incoming_token_type: "primaryRefreshToken" and
103    azure.signinlogs.properties.device_detail.device_id: * and
104    source.ip: * and
105    (
106        azure.signinlogs.properties.device_detail.is_compliant: true or
107        azure.signinlogs.properties.device_detail.is_managed: true
108    ) and azure.signinlogs.properties.app_id: (
109        "04b07795-8ddb-461a-bbee-02f9e1bf7b46" or
110        "1950a258-227b-4e31-a9cf-717495945fc2" or
111        "aebc6443-996d-45c2-90f0-388ff96faa56" or
112        "14d82eec-204b-4c2f-b7e8-296a70dab67e" or
113        "1b730954-1685-4b74-9bfd-dac224a7b894" or
114        "872cd9fa-d31f-45e0-9eab-6e460a02d1f1"
115    ) and azure.signinlogs.properties.resource_id: (
116        "00000003-0000-0000-c000-000000000000" or
117        "00000003-0000-0ff1-ce00-000000000000" or
118        "6a9b9266-8161-4a7b-913a-a9eda19da220" or
119        "00000002-0000-0ff1-ce00-000000000000"
120    )
121'''
122
123
124[[rule.threat]]
125framework = "MITRE ATT&CK"
126[[rule.threat.technique]]
127id = "T1528"
128name = "Steal Application Access Token"
129reference = "https://attack.mitre.org/techniques/T1528/"
130
131[[rule.threat.technique]]
132id = "T1539"
133name = "Steal Web Session Cookie"
134reference = "https://attack.mitre.org/techniques/T1539/"
135
136
137[rule.threat.tactic]
138id = "TA0006"
139name = "Credential Access"
140reference = "https://attack.mitre.org/tactics/TA0006/"
141[[rule.threat]]
142framework = "MITRE ATT&CK"
143[[rule.threat.technique]]
144id = "T1550"
145name = "Use Alternate Authentication Material"
146reference = "https://attack.mitre.org/techniques/T1550/"
147[[rule.threat.technique.subtechnique]]
148id = "T1550.001"
149name = "Application Access Token"
150reference = "https://attack.mitre.org/techniques/T1550/001/"
151
152
153
154[rule.threat.tactic]
155id = "TA0005"
156name = "Defense Evasion"
157reference = "https://attack.mitre.org/tactics/TA0005/"
158[[rule.threat]]
159framework = "MITRE ATT&CK"
160[[rule.threat.technique]]
161id = "T1078"
162name = "Valid Accounts"
163reference = "https://attack.mitre.org/techniques/T1078/"
164[[rule.threat.technique.subtechnique]]
165id = "T1078.004"
166name = "Cloud Accounts"
167reference = "https://attack.mitre.org/techniques/T1078/004/"
168
169
170
171[rule.threat.tactic]
172id = "TA0001"
173name = "Initial Access"
174reference = "https://attack.mitre.org/tactics/TA0001/"
175
176[rule.investigation_fields]
177field_names = [
178    "azure.signinlogs.properties.user_principal_name",
179    "azure.signinlogs.properties.user_id",
180    "azure.signinlogs.properties.device_detail.device_id",
181    "azure.signinlogs.properties.device_detail.display_name",
182    "azure.signinlogs.properties.app_id",
183    "azure.signinlogs.properties.app_display_name",
184    "azure.signinlogs.properties.resource_id",
185    "azure.signinlogs.properties.resource_display_name",
186    "azure.signinlogs.properties.incoming_token_type",
187    "azure.signinlogs.properties.device_detail.is_compliant",
188    "azure.signinlogs.properties.device_detail.is_managed",
189    "azure.signinlogs.properties.authentication_requirement",
190    "azure.signinlogs.properties.conditional_access_status",
191    "source.ip",
192    "source.geo.country_name",
193    "user_agent.original",
194]
195
196[rule.new_terms]
197field = "new_terms_fields"
198value = ["azure.signinlogs.properties.device_detail.device_id", "source.ip"]
199[[rule.new_terms.history_window_start]]
200field = "history_window_start"
201value = "now-5d"

Triage and analysis

Investigating Entra ID Device-Bound PRT from Unusual Device IP

This rule fires when a tooling FOCI client redeems a device-bound PRT from a source.ip that has not appeared with that device_id in the prior 5 days. Unlike Entra ID Device-Bound PRT Replay via First-Party App from Unusual IP, it does not need a Windows Sign-In or WAM event in the same window — so a workstation that last signed in yesterday still alerts when the cookie is redeemed from a new address.

PRTremote and similar harvest tools steal a WAM PRT SSO cookie and POST it from attacker infrastructure. The issued token keeps the workstation deviceid, so Conditional Access that requires a compliant device can succeed. Replay events must be is_compliant or is_managed. The stolen cookie nonce is typically valid for about five minutes; that is the attacker’s redeem window, not this rule’s history.

This is not ConsentFix / OAuth-code phishing. Those flows show OAuth2:Authorize with Redirect and often lack a bound compliant device.

Possible investigation steps

  • Review azure.signinlogs.properties.user_principal_name, azure.signinlogs.properties.device_detail.device_id, azure.signinlogs.properties.device_detail.display_name, and source.ip. Confirm incoming_token_type is primaryRefreshToken and device_detail.is_compliant / is_managed are true.
  • Compare azure.signinlogs.properties.app_display_name and user_agent.original with the resource (resource_display_name). A cookie POST through WAM can show a Trident/MSIE user agent on the Azure CLI client ID; that is the same IE stack legitimate Windows az login uses when it brokers through WAM, so it is triage context, not a detection key. TokenTactics commonly presents as Microsoft Office (that client is omitted here; hunt it separately if harvest is already confirmed).
  • Hunt prior Windows Sign-In / Windows-AzureAD-Authentication-Provider/1.0 events for the same deviceid. If those IPs differ from source.ip, treat this as the same story as the ES|QL companion. A Microsoft-owned ASN (including 8075) does not clear the alert.
  • Hunt endpoint telemetry for the same user or device display name as host.name: InteractiveToken scheduled tasks, svchost.exe (Schedule) → cmd.exeBrowserCore.exe, or files formatted_nonce.txt / prt_cookie.txt.
  • Review Graph, SharePoint, and mailbox activity after the sign-in for directory, file, or mail enumeration.

False positive analysis

  • Developers who run Azure CLI, Graph CLI, or VS Code from a new network while WAM still attaches the workstation deviceid. Exception known Cloud Shell / jump-host IPs after confirming the client actually ran there.
  • First use of a tooling client on a new device, or the first time a laptop appears on a new ISP, will fire once per (device_id, source.ip) pair and then age out of novelty.
  • Hybrid-joined workstations that report both is_compliant and is_managed as false (no Intune) will not match. Hunt those deviceids separately if harvest is already confirmed.
  • Microsoft Teams, Office, OneDrive SyncEngine, Authentication Broker, Outlook Mobile, Bing, Azure Portal, and Office 365 Management are excluded. Do not treat their absence as a miss.

Response and remediation

  • Contact the user to confirm whether they ran the first-party client from source.ip.
  • If unauthorized, revoke refresh tokens and primary refresh tokens for the user. The deviceid on the token is often the legitimate workstation — do not delete that device as if it were a ROADtx registration until you confirm otherwise.
  • Isolate the workstation, hunt for InteractiveToken scheduled tasks and BrowserCore harvest, and treat the admin identity that registered the task as a second compromised principal.

References

Related rules

to-top