From f9a2d801c741b50e30f738eb44903ce987b5e9ae Mon Sep 17 00:00:00 2001 From: Terrance DeJesus Date: Fri, 28 Aug 2026 12:25:32 -0400 Subject: [PATCH 1/7] [New Rule] Entra ID device-bound PRT cookie replay from unusual IP Detect FOCI tooling clients redeeming a stolen workstation PRT off-box, where the token keeps the original deviceid so compliant-device CA can still succeed. Co-authored-by: Cursor --- ...entra_id_prt_cookie_replay_unusual_ip.toml | 254 ++++++++++++++++++ ...s_entra_id_prt_from_unusual_device_ip.toml | 203 ++++++++++++++ 2 files changed, 457 insertions(+) create mode 100644 rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml create mode 100644 rules/integrations/azure/credential_access_entra_id_prt_from_unusual_device_ip.toml diff --git a/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml b/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml new file mode 100644 index 00000000000..010c34f47a1 --- /dev/null +++ b/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml @@ -0,0 +1,254 @@ +[metadata] +creation_date = "2026/08/27" +integration = ["azure"] +maturity = "production" +min_stack_comments = "Changing min stack to 9.3.0, the latest minimum supported version for 9.X releases." +min_stack_version = "9.3.0" +updated_date = "2026/08/28" + +[rule] +author = ["Elastic"] +description = """ +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 an IP that is not among that user and device's Windows Sign-In or WAM addresses. Replay events are limited +to compliant or Intune-managed devices: the stolen cookie keeps the workstation deviceid, so compliant-device +Conditional Access can succeed off-box. +""" +false_positives = [ + """ + A user running Azure CLI, Azure PowerShell, VS Code, Graph CLI, or Visual Studio on a jump host, Cloud Shell, or VPN + egress that differs from the workstation's Windows Sign-In IP can match if that activity still presents a compliant + or managed workstation deviceid. Validate whether the Graph client ran on the enrolled device before treating the + event as cookie theft. + """, + """ + Split-tunnel or dual-homed devices may present different egress IPs for WAM versus Azure CLI. Confirm both IPs + belong to the same physical device before raising severity. + """, + """ + Microsoft Teams, Microsoft Office, OneDrive SyncEngine, Microsoft Authentication Broker, Outlook Mobile, Bing, Azure + Portal, ADIbizaUX, and Office 365 Management are omitted. The rest of the Secureworks known-foci-clients.csv family + (Edge, OneDrive, Intune Company Portal, Windows Search, Authenticator, SharePoint, Planner, Power BI, and similar) + is omitted for the same reason: routine workstation or mobile Graph whose Microsoft 365 egress often differs from + the Windows Sign-In IP without cookie theft. Hunt those app_ids separately if harvest is already confirmed. + """, +] +from = "now-24h" +interval = "1h" +language = "esql" +license = "Elastic License v2" +name = "Entra ID Device-Bound PRT Replay via First-Party App from Unusual IP" +note = """## Triage and analysis + +### Investigating Entra ID Device-Bound PRT Replay via First-Party App from Unusual IP + +Adversaries who steal a WAM PRT SSO cookie (BrowserCore / InteractiveToken harvest) redeem it off-box for Microsoft Graph, SharePoint/OneDrive, or Exchange Online using a first-party FOCI client. PRTremote uses Azure CLI (`04b07795-8ddb-461a-bbee-02f9e1bf7b46`); TokenTactics and AADInternals can use Azure AD PowerShell (`1b730954-1685-4b74-9bfd-dac224a7b894`) or Microsoft Office (`d3590ed6-52b3-4102-aeff-aad2292ab01c`) when refreshing a PRT into a Graph, Outlook, or SharePoint token. This rule keys on CLI / PowerShell / VS Code / Visual Studio, not Teams, Office, OneDrive SyncEngine, Authentication Broker, Outlook Mobile, Bing, or Azure Portal — those clients routinely egress on a different IP than Windows Sign-In. Hunt Office-client PRT separately if harvest is already confirmed. The issued access token carries the *workstation* `deviceid`, so Conditional Access policies that require a compliant device can succeed even though the redeeming IP is not the device. Replay events must be `is_compliant` or `is_managed` so the join tracks a stolen enrolled workstation PRT, not an unmanaged ROADtx device. + +This is not ConsentFix / OAuth-code phishing. Those flows show `OAuth2:Authorize` with `Redirect` and often lack a bound compliant device on the Graph token. Do not close this alert by following the first-party OAuth phishing playbook alone. + +Companion coverage: **Entra ID Device-Bound PRT from Unusual Device IP** (new terms on `device_id` + `source.ip`, no in-window Windows Sign-In required). Endpoint: SIEM **Potential Entra ID PRT Harvest via BrowserCore** and [endpoint-rules#6661](https://github.com/elastic/endpoint-rules/pull/6661). + +### Possible investigation steps + +- Review `azure.signinlogs.properties.user_principal_name`, `azure.signinlogs.properties.device_detail.device_id`, and `source.ip`. Confirm `incoming_token_type` on the replay events is `primaryRefreshToken` and `device_detail.is_compliant` / `is_managed` are true. `Esql.resource_display_name_values` should be Microsoft Graph, Office 365 SharePoint Online, OneDrive for Business, and/or Office 365 Exchange Online. +- Treat `Esql.source_ip_device_values` as the workstation (Windows Sign-In / `Windows-AzureAD-Authentication-Provider/1.0`) — the device the PRT was bound to, and the likely theft origin. Treat `source.ip` / `Esql.source_ip_replay_values` as Graph / SharePoint / Exchange PRT IPs that are not in that device-session set (the replay actor). On-box FOCI from the workstation IP is excluded from the replay set. The harvest emulation showed workstation public IP versus attacker SNAT — including Azure ASN 8075, so a Microsoft-owned ASN does not clear the alert. The stolen PRT cookie nonce is typically valid for about five minutes; that is the attacker’s redeem window, not this rule’s lookback. The workstation may have signed in hours earlier, so the query correlates 24 hours of Windows Sign-In / WAM IPs with the replay. +- Inspect `Esql.app_display_name_values` and `Esql.user_agent_original_values`. 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 Graph refresh commonly presents as Microsoft Office (omitted here). A follow-on `python-requests/*` Graph token from the same session is tooling, not the first-party binary on the workstation. +- Hunt endpoint telemetry for the same user or `device_detail.display_name` as `host.name`: `svchost.exe` (Schedule) → `cmd.exe` → `BrowserCore.exe` with `<` / `>` redirection, or files `formatted_nonce.txt` / `prt_cookie.txt`. +- Intune audit (`create-clientcertificate`) is enrollment context only; it will not fire on the harvest. Use it as optional join on user OID, not as coverage. +- Review Graph, SharePoint, and mailbox activity after the replay for directory, file, or mail enumeration. + +### False positive analysis + +- Developers who run Azure CLI, Graph CLI, or VS Code from a different egress than Windows Sign-In while WAM still attaches the workstation deviceid. Exception known Cloud Shell / jump-host IPs after confirming the client actually ran there. +- Microsoft Teams, Office, OneDrive SyncEngine, Authentication Broker, Outlook Mobile, Bing, Azure Portal, and Office 365 Management Graph PRT are excluded. Do not treat their absence as a miss; they are omitted because split-tunnel M365 egress is routine. +- First sign-in of a new device can have sparse Windows Sign-In history in the 24-hour window; widen the hunt before responding. +- Hybrid-joined workstations that report both `is_compliant` and `is_managed` as false (no Intune) will not match the replay branch. Hunt those deviceids separately if harvest is already confirmed. + +### Response and remediation + +- Contact the user to confirm whether they ran the first-party client in `Esql.app_display_name_values` from the replay 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 = [ + "https://www.armadin.com/blog-posts/prtremote-extract-prt-cookies-remotely-with-interactivetoken-scheduled-task", + "https://github.com/armadin-public/PRTremote", + "https://github.com/dmcxblue/ANIMO/blob/master/helpers/scripts/GrabTokenAzureAD/PrtExtractor.cs", + "https://github.com/secureworks/family-of-client-ids-research", + "https://github.com/rvrsh3ll/TokenTactics", + "https://github.com/Gerenios/AADInternals", + "https://github.com/elastic/endpoint-rules/pull/6661", +] +risk_score = 73 +rule_id = "6a9fdaab-b50f-408d-b4da-54719f256d41" +setup = """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-*` so Windows Sign-In / WAM device activity and FOCI Graph, SharePoint, and Exchange token issuance are both available for the join. + +See [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). +""" +severity = "high" +tags = [ + "Domain: Cloud", + "Domain: Identity", + "Use Case: Threat Detection", + "Use Case: Identity and Access Audit", + "Data Source: Azure", + "Data Source: Microsoft Entra ID", + "Data Source: Microsoft Entra ID Sign-in Logs", + "Platform: Entra ID", + "Tactic: Credential Access", + "Tactic: Defense Evasion", + "Resources: Investigation Guide", + "Rule Type: ESQL", +] +timestamp_override = "event.ingested" +type = "esql" + +query = ''' +from logs-azure.signinlogs-* +// find successful sign-in events where a managed device exists +| where event.dataset == "azure.signinlogs" + and azure.signinlogs.properties.status.error_code == 0 + and azure.signinlogs.properties.device_detail.device_id is not null + +// filter for device sign-in events from Windows Sign-In or WAM (login session) +| eval Esql.is_device_session = azure.signinlogs.properties.app_display_name == "Windows Sign In" + or user_agent.original == "Windows-AzureAD-Authentication-Provider/1.0" + +// filter for tooling FOCI clients that can redeem a PRT (replay) +| eval Esql.is_prt_replay = azure.signinlogs.properties.app_id in ( + "04b07795-8ddb-461a-bbee-02f9e1bf7b46", // Microsoft Azure CLI + "1950a258-227b-4e31-a9cf-717495945fc2", // Microsoft Azure PowerShell + "aebc6443-996d-45c2-90f0-388ff96faa56", // Visual Studio Code + "14d82eec-204b-4c2f-b7e8-296a70dab67e", // Microsoft Graph Command Line Tools + "1b730954-1685-4b74-9bfd-dac224a7b894", // Azure Active Directory PowerShell + "872cd9fa-d31f-45e0-9eab-6e460a02d1f1" // Visual Studio + ) + + // target resource are common adversary targets for access + and azure.signinlogs.properties.resource_id in ( + "00000003-0000-0000-c000-000000000000", // Microsoft Graph + "00000003-0000-0ff1-ce00-000000000000", // Office 365 SharePoint Online + "6a9b9266-8161-4a7b-913a-a9eda19da220", // OneDrive for Business + "00000002-0000-0ff1-ce00-000000000000" // Office 365 Exchange Online + ) + and azure.signinlogs.properties.incoming_token_type == "primaryRefreshToken" + and ( + azure.signinlogs.properties.device_detail.is_compliant == true + or azure.signinlogs.properties.device_detail.is_managed == true + ) + +// device session or PRT replay event have to exist +| where Esql.is_device_session or Esql.is_prt_replay + +// aggregate entities for both device session and PRT replay events +// aggregate by user and device +| stats + Esql.source_ip_device_values = values(source.ip) where Esql.is_device_session, + Esql.source_ip_replay_values = values(source.ip) where Esql.is_prt_replay, + Esql.event_count_replay = count(*) where Esql.is_prt_replay, + Esql.event_count_device_session = count(*) where Esql.is_device_session, + Esql.user_principal_name_values = values(azure.signinlogs.properties.user_principal_name), + Esql.app_display_name_values = values(azure.signinlogs.properties.app_display_name) where Esql.is_prt_replay, + Esql.resource_id_values = values(azure.signinlogs.properties.resource_id) where Esql.is_prt_replay, + Esql.resource_display_name_values = values(azure.signinlogs.properties.resource_display_name) where Esql.is_prt_replay, + Esql.device_display_name_values = values(azure.signinlogs.properties.device_detail.display_name), + Esql.user_agent_original_values = values(user_agent.original) where Esql.is_prt_replay, + Esql.device_is_compliant_values = values(azure.signinlogs.properties.device_detail.is_compliant) where Esql.is_prt_replay, + Esql.device_is_managed_values = values(azure.signinlogs.properties.device_detail.is_managed) where Esql.is_prt_replay, + Esql.authentication_requirement_values = values(azure.signinlogs.properties.authentication_requirement) where Esql.is_prt_replay, + Esql.conditional_access_status_values = values(azure.signinlogs.properties.conditional_access_status) where Esql.is_prt_replay, + Esql.earliest_timestamp = min(@timestamp), + Esql.latest_timestamp = max(@timestamp) + by azure.signinlogs.properties.user_id, azure.signinlogs.properties.device_detail.device_id + +// filter for PRT replay events that have at least one replay IP +| where Esql.event_count_replay > 0 + and Esql.event_count_device_session > 0 + and Esql.source_ip_replay_values is not null + and Esql.source_ip_device_values is not null + +// expand the replay IP list and keep only IPs that are not in the device-session set +| mv_expand Esql.source_ip_replay_values +| where not mv_contains(Esql.source_ip_device_values, Esql.source_ip_replay_values) +| eval Esql.source_ip_replay = Esql.source_ip_replay_values, + user.id = azure.signinlogs.properties.user_id, + source.ip = Esql.source_ip_replay_values +| keep + user.id, + source.ip, + azure.signinlogs.properties.user_id, + azure.signinlogs.properties.device_detail.device_id, + Esql.* +''' + + +[[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.technique]] +id = "T1539" +name = "Steal Web Session Cookie" +reference = "https://attack.mitre.org/techniques/T1539/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" +[[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 = "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.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + +[rule.investigation_fields] +field_names = [ + "user.id", + "source.ip", + "azure.signinlogs.properties.user_id", + "azure.signinlogs.properties.device_detail.device_id", + "Esql.user_principal_name_values", + "Esql.device_display_name_values", + "Esql.source_ip_device_values", + "Esql.source_ip_replay_values", + "Esql.app_display_name_values", + "Esql.resource_display_name_values", + "Esql.user_agent_original_values", + "Esql.device_is_compliant_values", + "Esql.device_is_managed_values", +] + diff --git a/rules/integrations/azure/credential_access_entra_id_prt_from_unusual_device_ip.toml b/rules/integrations/azure/credential_access_entra_id_prt_from_unusual_device_ip.toml new file mode 100644 index 00000000000..f5b252be148 --- /dev/null +++ b/rules/integrations/azure/credential_access_entra_id_prt_from_unusual_device_ip.toml @@ -0,0 +1,203 @@ +[metadata] +creation_date = "2026/08/28" +integration = ["azure"] +maturity = "production" +updated_date = "2026/08/28" + +[rule] +author = ["Elastic"] +description = """ +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. +""" +false_positives = [ + """ + A user who runs Azure CLI, Azure PowerShell, VS Code, Graph CLI, or Visual Studio from a new egress (VPN, hotel, + Cloud Shell, jump host) while WAM still attaches a compliant or managed workstation deviceid will match on first + sight of that IP. Exception known developer and Cloud Shell ranges after confirming the client ran there. + """, + """ + Split-tunnel or dual-homed devices can present a new Microsoft 365 egress for tooling clients. Confirm the IP + belongs to the enrolled device before treating the event as cookie theft. + """, + """ + Microsoft Teams, Office, OneDrive SyncEngine, Authentication Broker, Outlook Mobile, Bing, Azure Portal, and Office + 365 Management are omitted because first sight of a mobile or M365 egress IP for those clients is routine. + """, +] +from = "now-9m" +index = ["filebeat-*", "logs-azure.signinlogs-*"] +language = "kuery" +license = "Elastic License v2" +name = "Entra ID Device-Bound PRT from Unusual Device IP" +note = """## 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.exe` → `BrowserCore.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 = [ + "https://www.armadin.com/blog-posts/prtremote-extract-prt-cookies-remotely-with-interactivetoken-scheduled-task", + "https://github.com/armadin-public/PRTremote", + "https://github.com/dmcxblue/ANIMO/blob/master/helpers/scripts/GrabTokenAzureAD/PrtExtractor.cs", + "https://github.com/rvrsh3ll/TokenTactics", + "https://github.com/Gerenios/AADInternals", +] +risk_score = 73 +rule_id = "9e8d9bb5-6d3a-4431-a0d0-8d0475e726a4" +setup = """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-*`. + +See [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). +""" +severity = "high" +tags = [ + "Domain: Cloud", + "Domain: Identity", + "Use Case: Threat Detection", + "Use Case: Identity and Access Audit", + "Data Source: Azure", + "Data Source: Microsoft Entra ID", + "Data Source: Microsoft Entra ID Sign-in Logs", + "Platform: Entra ID", + "Tactic: Credential Access", + "Tactic: Defense Evasion", + "Resources: Investigation Guide", + "Rule Type: New Terms", +] +timestamp_override = "event.ingested" +type = "new_terms" + +query = ''' +data_stream.dataset: azure.signinlogs and + event.outcome: success and + azure.signinlogs.properties.status.error_code: 0 and + azure.signinlogs.properties.incoming_token_type: "primaryRefreshToken" and + azure.signinlogs.properties.device_detail.device_id: * and + source.ip: * and + ( + azure.signinlogs.properties.device_detail.is_compliant: true or + azure.signinlogs.properties.device_detail.is_managed: true + ) and azure.signinlogs.properties.app_id: ( + "04b07795-8ddb-461a-bbee-02f9e1bf7b46" or + "1950a258-227b-4e31-a9cf-717495945fc2" or + "aebc6443-996d-45c2-90f0-388ff96faa56" or + "14d82eec-204b-4c2f-b7e8-296a70dab67e" or + "1b730954-1685-4b74-9bfd-dac224a7b894" or + "872cd9fa-d31f-45e0-9eab-6e460a02d1f1" + ) and azure.signinlogs.properties.resource_id: ( + "00000003-0000-0000-c000-000000000000" or + "00000003-0000-0ff1-ce00-000000000000" or + "6a9b9266-8161-4a7b-913a-a9eda19da220" or + "00000002-0000-0ff1-ce00-000000000000" + ) +''' + + +[[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.technique]] +id = "T1539" +name = "Steal Web Session Cookie" +reference = "https://attack.mitre.org/techniques/T1539/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" +[[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 = "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.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + +[rule.investigation_fields] +field_names = [ + "azure.signinlogs.properties.user_principal_name", + "azure.signinlogs.properties.user_id", + "azure.signinlogs.properties.device_detail.device_id", + "azure.signinlogs.properties.device_detail.display_name", + "azure.signinlogs.properties.app_id", + "azure.signinlogs.properties.app_display_name", + "azure.signinlogs.properties.resource_id", + "azure.signinlogs.properties.resource_display_name", + "azure.signinlogs.properties.incoming_token_type", + "azure.signinlogs.properties.device_detail.is_compliant", + "azure.signinlogs.properties.device_detail.is_managed", + "azure.signinlogs.properties.authentication_requirement", + "azure.signinlogs.properties.conditional_access_status", + "source.ip", + "source.geo.country_name", + "user_agent.original", +] + +[rule.new_terms] +field = "new_terms_fields" +value = ["azure.signinlogs.properties.device_detail.device_id", "source.ip"] +[[rule.new_terms.history_window_start]] +field = "history_window_start" +value = "now-5d" + + From b8f4f2768b4ad901da6db509fb3a2036fd8eabca Mon Sep 17 00:00:00 2001 From: Terrance DeJesus <99630311+terrancedejesus@users.noreply.github.com> Date: Fri, 28 Aug 2026 12:45:40 -0400 Subject: [PATCH 2/7] Update references in credential_access_entra_id_prt_cookie_replay_unusual_ip rule Removed outdated references from the Azure credential access rule. --- ...credential_access_entra_id_prt_cookie_replay_unusual_ip.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml b/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml index 010c34f47a1..be5c801c0da 100644 --- a/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml +++ b/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml @@ -75,10 +75,8 @@ references = [ "https://www.armadin.com/blog-posts/prtremote-extract-prt-cookies-remotely-with-interactivetoken-scheduled-task", "https://github.com/armadin-public/PRTremote", "https://github.com/dmcxblue/ANIMO/blob/master/helpers/scripts/GrabTokenAzureAD/PrtExtractor.cs", - "https://github.com/secureworks/family-of-client-ids-research", "https://github.com/rvrsh3ll/TokenTactics", "https://github.com/Gerenios/AADInternals", - "https://github.com/elastic/endpoint-rules/pull/6661", ] risk_score = 73 rule_id = "6a9fdaab-b50f-408d-b4da-54719f256d41" From 5bfcd1fd139d23a1709aad57621c455d49a69a47 Mon Sep 17 00:00:00 2001 From: Terrance DeJesus <99630311+terrancedejesus@users.noreply.github.com> Date: Fri, 28 Aug 2026 12:46:23 -0400 Subject: [PATCH 3/7] Update minimum stack version to 9.3.0 Updated minimum stack version to the latest supported for 9.X releases. --- ...credential_access_entra_id_prt_cookie_replay_unusual_ip.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml b/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml index be5c801c0da..2d7cf500d70 100644 --- a/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml +++ b/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml @@ -2,8 +2,6 @@ creation_date = "2026/08/27" integration = ["azure"] maturity = "production" -min_stack_comments = "Changing min stack to 9.3.0, the latest minimum supported version for 9.X releases." -min_stack_version = "9.3.0" updated_date = "2026/08/28" [rule] From 4b44d9bcaa6787a6b1bcaf40194d6f6fadeb4528 Mon Sep 17 00:00:00 2001 From: Terrance DeJesus <99630311+terrancedejesus@users.noreply.github.com> Date: Mon, 31 Aug 2026 10:43:09 -0400 Subject: [PATCH 4/7] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../credential_access_entra_id_prt_from_unusual_device_ip.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/integrations/azure/credential_access_entra_id_prt_from_unusual_device_ip.toml b/rules/integrations/azure/credential_access_entra_id_prt_from_unusual_device_ip.toml index f5b252be148..98aac6bef4f 100644 --- a/rules/integrations/azure/credential_access_entra_id_prt_from_unusual_device_ip.toml +++ b/rules/integrations/azure/credential_access_entra_id_prt_from_unusual_device_ip.toml @@ -17,7 +17,7 @@ false_positives = [ """ A user who runs Azure CLI, Azure PowerShell, VS Code, Graph CLI, or Visual Studio from a new egress (VPN, hotel, Cloud Shell, jump host) while WAM still attaches a compliant or managed workstation deviceid will match on first - sight of that IP. Exception known developer and Cloud Shell ranges after confirming the client ran there. + sight of that IP. Exception: add known developer and Cloud Shell ranges after confirming the client ran there. """, """ Split-tunnel or dual-homed devices can present a new Microsoft 365 egress for tooling clients. Confirm the IP From 606fa51fcef6d14b8289413e73c02285ce63c30b Mon Sep 17 00:00:00 2001 From: Terrance DeJesus <99630311+terrancedejesus@users.noreply.github.com> Date: Mon, 31 Aug 2026 10:43:31 -0400 Subject: [PATCH 5/7] Update credential_access_entra_id_prt_cookie_replay_unusual_ip.toml --- ...credential_access_entra_id_prt_cookie_replay_unusual_ip.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml b/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml index 2d7cf500d70..e9bad0cb569 100644 --- a/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml +++ b/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml @@ -2,7 +2,7 @@ creation_date = "2026/08/27" integration = ["azure"] maturity = "production" -updated_date = "2026/08/28" +updated_date = "2026/08/27" [rule] author = ["Elastic"] From 6bf7783d96718a0bd2e4a36d14b4710b65521d93 Mon Sep 17 00:00:00 2001 From: Terrance DeJesus <99630311+terrancedejesus@users.noreply.github.com> Date: Thu, 10 Sep 2026 11:30:43 -0400 Subject: [PATCH 6/7] Apply suggestion from @terrancedejesus --- .../credential_access_entra_id_prt_cookie_replay_unusual_ip.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml b/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml index e9bad0cb569..ca9997b87dc 100644 --- a/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml +++ b/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml @@ -45,7 +45,6 @@ Adversaries who steal a WAM PRT SSO cookie (BrowserCore / InteractiveToken harve This is not ConsentFix / OAuth-code phishing. Those flows show `OAuth2:Authorize` with `Redirect` and often lack a bound compliant device on the Graph token. Do not close this alert by following the first-party OAuth phishing playbook alone. -Companion coverage: **Entra ID Device-Bound PRT from Unusual Device IP** (new terms on `device_id` + `source.ip`, no in-window Windows Sign-In required). Endpoint: SIEM **Potential Entra ID PRT Harvest via BrowserCore** and [endpoint-rules#6661](https://github.com/elastic/endpoint-rules/pull/6661). ### Possible investigation steps From 007153e9d6bbab386e3792a7f16d728bb3989a30 Mon Sep 17 00:00:00 2001 From: Terrance DeJesus <99630311+terrancedejesus@users.noreply.github.com> Date: Thu, 10 Sep 2026 11:31:30 -0400 Subject: [PATCH 7/7] Apply suggestion from @terrancedejesus --- .../credential_access_entra_id_prt_cookie_replay_unusual_ip.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml b/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml index ca9997b87dc..0879c6af4f5 100644 --- a/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml +++ b/rules/integrations/azure/credential_access_entra_id_prt_cookie_replay_unusual_ip.toml @@ -93,6 +93,7 @@ tags = [ "Platform: Entra ID", "Tactic: Credential Access", "Tactic: Defense Evasion", + "Tactic: Initial Access", "Resources: Investigation Guide", "Rule Type: ESQL", ]