The KQL Master’s Guide to Detecting Actor Token Abuse (CVE-2025-55241)

Listen to this Post

Featured Image

Introduction:

A critical vulnerability, CVE-2025-55241, has emerged, enabling threat actors to abuse service principal tokens for lateral movement and privilege escalation within Azure AD. This novel attack vector bypasses traditional detections by masquerading as legitimate service-to-service (S2S) traffic, making advanced KQL hunting essential for modern defense. Security teams must now pivot their hunting strategies to identify anomalous token usage that originates from non-Microsoft infrastructure.

Learning Objectives:

  • Understand the core mechanics of the Actor Token Abuse vulnerability (CVE-2025-55241).
  • Learn to implement and customize advanced KQL queries for hunting suspicious service principal sign-ins.
  • Develop a proactive defense strategy for identifying and mitigating token-based attacks in Azure environments.

You Should Know:

1. The Core Detection Query

The foundational KQL query, developed by Mehmet Erdem and verified with security expert Dirk-jan Mollema, is designed to flag service principal sign-ins originating from IP addresses not belonging to Microsoft’s trusted infrastructure.

let MicrosoftIPs = dynamic(['13.107.0.0/16', '40.96.0.0/13', '52.96.0.0/12', '104.44.0.0/15']); // Partial list
AADServicePrincipalSignInLogs
| where TimeGenerated >= ago(7d)
| where ResultType == "0"
| where ServicePrincipalName !endswith "microsoft.com"
| where ServicePrincipalName !endswith "microsoftonline.com"
| where IPAddress !has_any (MicrosoftIPs)
| where not(IPAddress startswith "10.") // Exclude hybrid tenant on-premise IPs
| project TimeGenerated, ServicePrincipalId, ServicePrincipalName, IPAddress, Location, ResultDescription, AppDisplayName
| summarize count() by ServicePrincipalId, IPAddress, bin(TimeGenerated, 15m)

Step‑by‑step guide:

This query first defines a list of known Microsoft IP ranges. It then scans the Azure AD Service Principal sign-in logs for successful authentications (ResultType == "0") from service principals whose names do not end with Microsoft domains. Crucially, it filters out any sign-ins from Microsoft’s IP blocks and, based on community feedback, also excludes traffic from private IP space (10.0.0.0/8) which is common in hybrid setups. The results are summarized to show the count of sign-ins per service principal and IP address in 15-minute bins, highlighting potential brute-force or automated abuse.

2. Enriching with Threat Intelligence Feeds

A detection becomes far more powerful when enriched with real-time threat intelligence. This command uses `externaldata` operator to pull in a list of known malicious IPs from a public feed for cross-referencing.

let KnownBadIPs = externaldata(IP:string)[@"https://mythreatintel.com/feeds/badips.csv"] with (format="csv");
let MicrosoftIPs = dynamic(['13.107.0.0/16', '40.96.0.0/13', '52.96.0.0/12', '104.44.0.0/15']);
AADServicePrincipalSignInLogs
| where TimeGenerated >= ago(1d)
| where ResultType == "0"
| where IPAddress !has_any (MicrosoftIPs)
| where IPAddress in (KnownBadIPs)
| project TimeGenerated, ServicePrincipalId, ServicePrincipalName, IPAddress, AppDisplayName, ResultDescription

Step‑by‑step guide:

This query demonstrates how to integrate external threat data. The `externaldata` operator fetches a CSV list of malicious IPs from a specified URL. The main query then joins this data, checking if the `IPAddress` from each service principal sign-in is present in the `KnownBadIPs` list. This immediately elevates the alert severity, indicating a high probability of compromise from a known malicious infrastructure.

3. Baselining Normal Service Principal Behavior

Proactive hunting involves understanding what is normal to find what is anomalous. This query establishes a baseline of typical sign-in locations for each service principal.

AADServicePrincipalSignInLogs
| where TimeGenerated >= ago(30d)
| where ResultType == "0"
| summarize BaselineLocations = make_set(Location) by ServicePrincipalId
| join kind=inner (
AADServicePrincipalSignInLogs
| where TimeGenerated >= ago(1d)
| where ResultType == "0"
) on ServicePrincipalId
| where Location !in (BaselineLocations)
| project TimeGenerated, ServicePrincipalId, ServicePrincipalName, IPAddress, Location, AppDisplayName

Step‑by‑step guide:

This two-part query first creates a 30-day historical baseline, storing all the locations from which each service principal has successfully signed in. It then performs an inner join with the last day’s worth of sign-in logs. The final `where` clause filters for any sign-ins where the current `Location` is not in the historical `BaselineLocations` set. This is excellent for detecting geographic anomalies that might indicate token theft and reuse from a new region.

  1. Hunting for Token Replay with Time Delta Analysis
    Stolen tokens can be replayed from different locations. This query hunts for the same service principal signing in from geographically disparate locations within an impossibly short time frame.
AADServicePrincipalSignInLogs
| where TimeGenerated >= ago(2d)
| where ResultType == "0"
| summarize Locations = makeset(Location), IPs = makeset(IPAddress), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by ServicePrincipalId, bin(TimeGenerated, 1h)
| where array_length(IPs) > 1
| extend TimeDelta = datetime_diff('minute', EndTime, StartTime)
| where TimeDelta < 60 // Less than 60 minutes between first and last sign-in from different IPs
| project ServicePrincipalId, IPs, Locations, StartTime, EndTime, TimeDelta

Step‑by‑step guide:

This query groups service principal sign-ins into one-hour bins. For each group, it creates sets of all IP addresses and locations used. It then filters for bins where more than one unique IP was used and calculates the time difference between the first and last sign-in in that bin. If this delta is less than 60 minutes, it’s physically impossible for legitimate traffic to originate from different geographic regions, strongly suggesting token replay abuse.

5. Automating Response with Logic Apps Playbooks

Detection is only half the battle. This Azure CLI command can be used within an Azure Logic App to automatically disable a compromised service principal upon alert generation.

az ad sp credential list --id $(ServicePrincipalId) --query "[].keyId" -o tsv

Step‑by‑step guide:

Within an Azure Logic App triggered by a KQL alert from the previous queries, this CLI command can be executed. It lists all key credentials (passwords and certificates) for the potentially compromised service principal ($(ServicePrincipalId) would be passed from the alert). The output can then be fed into subsequent commands to selectively remove specific keys or entirely reset the service principal’s credentials, effectively revoking the stolen token and containing the breach automatically.

What Undercode Say:

  • The sophistication of this attack lies in its abuse of trust. It doesn’t exploit a code flaw but a logical trust assumption in S2S communication, making it a potent supply chain attack vector.
  • The community-driven refinement of the detection query, exemplified by the addition of the `10.x` IP filter, is a critical lesson in defense: no detection is perfect at version 1.0.
    This incident underscores a paradigm shift in cloud security. The perimeter is now defined by identity and trust relationships, not network boundaries. Defenders must adopt a zero-trust mindset, rigorously validating the “who, what, where, and when” of every authentication attempt, especially for machine identities like service principals. The ability to quickly develop, deploy, and iteratively refine KQL-based hunts is no longer a niche skill but a core competency for any security team operating in Azure.

Prediction:

The successful exploitation of CVE-2025-55241 will catalyze a new wave of attacks focused on software supply chains and cloud identity federations. Threat actors, particularly ransomware groups and state-sponsored APTs, will increasingly target service principals and workload identities as a primary method for lateral movement and persistence within cloud environments. This will force a rapid evolution in Cloud Security Posture Management (CSPM) and Identity Threat Detection and Response (ITDR) solutions, with a much heavier emphasis on behavioral analytics for non-human identities. Within 18 months, we predict that automated token abuse will become one of the top three initial access vectors in major cloud breaches.

🎯Let’s Practice For Free:

IT/Security Reporter URL:

Reported By: https://lnkd.in/p/d76A_TQ5 – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow UndercodeTesting & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin | 🦋BlueSky