Detection Tools
KQL Helper
Search, filter, and reuse curated KQL queries for Microsoft Sentinel, Defender, and Entra ID investigations. Each query is paired with clear operational context so teams can understand when and why it should be used.
Showing 20 of 20 queries
Detect Suspicious PowerShell Execution
SentinelIdentifies PowerShell commands with encoded payloads, download operations, and common living-off-the-land techniques. Detects when PowerShell is used for encoded commands, web downloads, or reflection-based execution that is characteristic of malware and ransomware loaders.
DeviceProcessEvents
| where FileName == "powershell.exe" or FileName == "pwsh.exe"
| where ProcessCommandLine has_any (
"Invoke-Expression", "IEX", "DownloadString", "WebClient",
"FromBase64String", "EncodedCommand", "-enc", "Bypass", "Hidden"
)
| where ProcessCommandLine !has_any ("Get-Help", "Get-Module")
| extend CommandLength = strlen(ProcessCommandLine)
| where CommandLength > 100
| summarize
FirstSeen = min(Timestamp),
LastSeen = max(Timestamp),
Count = count(),
Sample = take_any(ProcessCommandLine)
by DeviceName, AccountName
| project FirstSeen, LastSeen, DeviceName, AccountName, Count, SampleDetect Brute Force Sign-In Attempts
Azure ADIdentifies accounts with multiple failed sign-in attempts followed by a successful authentication, indicating potential credential stuffing or brute force attacks. Focuses on detecting the pattern of failure-then-success that distinguishes successful account compromise from failed attacks.
let threshold = 10;
let timeWindow = 1h;
SigninLogs
| where TimeGenerated > ago(timeWindow)
| summarize
FailedAttempts = countif(ResultType != "0"),
SuccessfulLogins = countif(ResultType == "0"),
IPAddresses = make_set(IPAddress),
Locations = make_set(Location)
by UserPrincipalName, bin(TimeGenerated, timeWindow)
| where FailedAttempts >= threshold and SuccessfulLogins > 0
| project UserPrincipalName, FailedAttempts, SuccessfulLogins, IPAddresses, LocationsDetect Kerberoasting Attacks
SentinelDetects Kerberoasting by identifying requests for Kerberos service tickets (TGS) for accounts with Service Principal Names using weak encryption types (RC4). Attackers use Kerberoasting to extract service account password hashes offline for cracking.
SecurityEvent
| where EventID == 4769
| where TicketEncryptionType == "0x17"
| where ServiceName !endswith "$"
| where ServiceName !in ("krbtgt")
| summarize
Count = count(),
Accounts = make_set(ServiceName),
SourceIPs = make_set(IpAddress)
by Computer, Account, bin(TimeGenerated, 1h)
| where Count > 2
| project TimeGenerated, Computer, Account, Count, Accounts, SourceIPsDetect Impossible Travel Sign-Ins
Azure ADIdentifies sign-ins from geographically impossible locations within a short time window, indicating account compromise or VPN/proxy usage. Compares consecutive successful sign-ins from the same account for location changes that cannot be physically achieved.
SigninLogs
| where ResultType == "0"
| where isnotempty(Location)
| sort by UserPrincipalName, TimeGenerated asc
| extend
PrevLocation = prev(Location),
PrevTime = prev(TimeGenerated),
PrevUser = prev(UserPrincipalName)
| where UserPrincipalName == PrevUser
| where Location != PrevLocation
| extend TimeDiffHours = datetime_diff("hour", TimeGenerated, PrevTime)
| where TimeDiffHours <= 2 and TimeDiffHours >= 0
| project UserPrincipalName, TimeGenerated, Location, PrevLocation, TimeDiffHoursDetect Azure AD Privilege Escalation
Azure ADMonitors for addition of accounts to privileged Azure AD roles including Global Administrator and Security Administrator. Privilege escalation is a critical step in most significant breaches and should be alerted on in near real-time.
AuditLogs
| where OperationName has "Add member to role"
| extend
TargetUser = tostring(TargetResources[0].userPrincipalName),
RoleAssigned = tostring(TargetResources[0].displayName),
ModifiedBy = tostring(InitiatedBy.user.userPrincipalName)
| where RoleAssigned has_any (
"Global Administrator", "Privileged Role Administrator",
"Security Administrator", "Exchange Administrator",
"Application Administrator", "Cloud Application Administrator"
)
| project TimeGenerated, TargetUser, RoleAssigned, ModifiedByDetect Large Outbound Data Transfers
SentinelIdentifies anomalously large outbound data transfers that may indicate data exfiltration. Looks for egress traffic exceeding a configurable threshold. Particularly useful for detecting pre-ransomware double-extortion data staging.
let threshold_bytes = 100 * 1024 * 1024;
CommonSecurityLog
| where DeviceAction !has "deny"
| where tolong(SentBytes) > threshold_bytes
| summarize
TotalSentBytes = sum(tolong(SentBytes)),
SessionCount = count(),
DestinationIPs = make_set(DestinationIP)
by SourceUserName, SourceIP, bin(TimeGenerated, 1h)
| extend TotalSentMB = round(TotalSentBytes / 1048576.0, 2)
| order by TotalSentMB descDetect Lateral Movement via SMB
SentinelDetects lateral movement through internal network file share access patterns. Identifies accounts accessing multiple internal systems via SMB in a short time frame, which is characteristic of worm-like spread or attacker lateral movement.
DeviceNetworkEvents
| where RemotePort == 445
| where ActionType == "ConnectionSuccess"
| where not(RemoteIPType == "Private" and LocalIPType == "Public")
| summarize
TargetCount = dcount(RemoteIP),
Targets = make_set(RemoteIP, 20),
FirstSeen = min(Timestamp)
by DeviceName, InitiatingProcessAccountName, bin(Timestamp, 1h)
| where TargetCount >= 5
| project FirstSeen, DeviceName, InitiatingProcessAccountName, TargetCount, TargetsDetect Malware Execution Alerts
DefenderAggregates Microsoft Defender malware detection alerts with correlated device and account context. Provides a consolidated view of malware activity across the estate with severity prioritisation.
DeviceEvents
| where ActionType == "AntivirusDetection"
| extend
ThreatName = tostring(AdditionalFields.ThreatName),
WasRemediated = tostring(AdditionalFields.WasRemediated),
ThreatFamily = tostring(AdditionalFields.ThreatName) split(":", 0)[0]
| summarize
DetectionCount = count(),
Devices = make_set(DeviceName),
Users = make_set(InitiatingProcessAccountName)
by ThreatName, ThreatFamily, WasRemediated
| order by DetectionCount descDetect RDP from Unusual Countries
SentinelIdentifies Remote Desktop Protocol connections originating from countries not in the organisation's normal operating territory. RDP from unexpected geographies is a strong indicator of compromised credentials or unauthorised access attempts.
let AllowedCountries = dynamic(["GB", "US", "DE", "FR", "NL"]);
SecurityEvent
| where EventID == 4624
| where LogonType == 10
| extend Country = tostring(todynamic(EventData).NetworkInformation)
| where isnotempty(IpAddress)
| join kind=leftouter (
SigninLogs
| extend Country2 = Location
| project UserPrincipalName, Country2, IPAddress
) on $left.TargetUserName == $right.UserPrincipalName
| where Country2 !in (AllowedCountries)
| project TimeGenerated, TargetUserName, IpAddress, Country2, ComputerDetect Password Spray Attacks
Azure ADIdentifies password spray attacks by detecting a single IP address failing authentication against many different accounts within a short period. Unlike brute force which targets one account, spray attacks try one password across many accounts to avoid lockout policies.
let lookback = 1h;
let threshold = 20;
SigninLogs
| where TimeGenerated > ago(lookback)
| where ResultType != "0"
| summarize
FailedAccounts = dcount(UserPrincipalName),
AccountList = make_set(UserPrincipalName, 10),
ErrorCodes = make_set(ResultType)
by IPAddress, bin(TimeGenerated, 10m)
| where FailedAccounts >= threshold
| project TimeGenerated, IPAddress, FailedAccounts, AccountListMonitor Defender ASR Rule Violations
DefenderTracks Attack Surface Reduction rule violations from Microsoft Defender, highlighting the most frequently triggered rules. ASR violations often indicate attempted abuse of common attack vectors including Office macro execution and credential theft.
DeviceEvents
| where ActionType startswith "AsrBlocked"
| extend
RuleName = ActionType,
ProcessPath = FolderPath
| summarize
BlockCount = count(),
AffectedDevices = dcount(DeviceName),
SampleProcess = take_any(InitiatingProcessFileName)
by RuleName, bin(Timestamp, 1d)
| order by BlockCount descFind Non-Compliant Intune Devices
IntuneLists devices enrolled in Microsoft Intune that are currently non-compliant with security policies. Non-compliant devices represent a security risk and should be blocked from accessing corporate resources via Conditional Access.
IntuneDeviceComplianceOrg
| where ComplianceState == "noncompliant"
| summarize
NonCompliantCount = count(),
DeviceList = make_set(DeviceName, 20),
Users = make_set(UPN, 20)
by OS, PolicyName
| order by NonCompliantCount descDetect Anomalous Service Principal Activity
Azure ADIdentifies service principals performing actions outside their expected patterns — creating new credentials, assigning roles, or accessing unusual resources. Compromised service principals are high-impact since they often carry excessive permissions.
AuditLogs
| where OperationName has_any (
"Add credentials to application",
"Update application",
"Add service principal credentials"
)
| extend
SPName = tostring(TargetResources[0].displayName),
ModifiedBy = tostring(InitiatedBy.app.displayName)
| where isnotempty(SPName)
| project TimeGenerated, OperationName, SPName, ModifiedBy, ResultSentinel Incident Trend Analysis
SentinelProvides a daily trend of Sentinel incidents by severity over the past 30 days. Useful for operational dashboards, management reporting, and identifying spikes in alert volume that may indicate active threats or detection rule tuning opportunities.
SecurityIncident
| where TimeGenerated > ago(30d)
| summarize
CriticalCount = countif(Severity == "High"),
HighCount = countif(Severity == "Medium"),
TotalCount = count()
by bin(TimeGenerated, 1d)
| order by TimeGenerated asc
| project TimeGenerated, CriticalCount, HighCount, TotalCountFind Devices with Vulnerable Software
DefenderLists devices running software versions with known CVE vulnerabilities via Microsoft Defender Vulnerability Management. Prioritises by CVSS score and counts of affected devices to guide patching efforts.
DeviceTvmSoftwareVulnerabilities
| where CvssScore >= 7.0
| summarize
AffectedDeviceCount = dcount(DeviceName),
ExposedDevices = make_set(DeviceName, 10)
by SoftwareName, SoftwareVersion, CveId, CvssScore, VulnerabilitySeverityLevel
| order by CvssScore desc, AffectedDeviceCount desc
| project CveId, SoftwareName, SoftwareVersion, CvssScore, VulnerabilitySeverityLevel, AffectedDeviceCountAlert on Watchlist IP Matches
SentinelCorrelates incoming network connections against a Sentinel watchlist of known malicious IP addresses and threat intelligence indicators. Generates alerts when any traffic originates from or terminates at a watchlisted indicator.
let ThreatIntelIPs = _GetWatchlist("ThreatIntelIPs") | project SearchKey;
CommonSecurityLog
| where TimeGenerated > ago(1d)
| where DeviceAction !has "deny"
| where DestinationIP in (ThreatIntelIPs) or SourceIP in (ThreatIntelIPs)
| project
TimeGenerated,
SourceIP,
DestinationIP,
DeviceVendor,
DeviceProduct,
Activity
| order by TimeGenerated descDetect MFA Disabled for User Account
Azure ADMonitors Azure AD audit logs for MFA being disabled on user accounts. Attackers who have access to an admin account may disable MFA to facilitate persistent access. This detection helps identify both malicious actions and accidental policy changes.
AuditLogs
| where OperationName has_any (
"Disable Strong Authentication",
"Update user",
"Update StrongAuthenticationRequirement"
)
| extend
TargetAccount = tostring(TargetResources[0].userPrincipalName),
ChangedBy = tostring(InitiatedBy.user.userPrincipalName),
PropertyChanged = tostring(TargetResources[0].modifiedProperties[0].displayName)
| where PropertyChanged has "StrongAuth" or OperationName has "Disable Strong"
| project TimeGenerated, TargetAccount, ChangedBy, PropertyChanged, OperationNameDetect Suspicious Azure Cloud Shell Usage
SentinelIdentifies unusual Azure Cloud Shell sessions including sessions initiated from unfamiliar locations, sessions of unusual duration, or sessions running high-risk commands. Cloud Shell provides a fully privileged shell in Azure and abuse can lead to full tenant compromise.
AzureActivity
| where OperationNameValue has "Microsoft.Portal/cloudshell"
| where ActivityStatusValue == "Success"
| extend
CallerIP = tostring(HTTPRequest.clientIpAddress),
UserAgent = tostring(HTTPRequest.userAgent)
| summarize
SessionCount = count(),
UniqueIPs = dcount(CallerIP),
IPList = make_set(CallerIP)
by Caller, bin(TimeGenerated, 1d)
| where SessionCount > 10 or UniqueIPs > 2
| project TimeGenerated, Caller, SessionCount, UniqueIPs, IPListDetect Public Access Enabled on Storage Accounts
SentinelMonitors Azure Policy and Activity Logs for storage accounts where public blob access has been enabled or where the security configuration has been weakened. Public storage accounts are a leading cause of Azure data breaches.
AzureActivity
| where OperationNameValue has "microsoft.storage/storageaccounts/write"
| where ActivityStatusValue == "Success"
| extend
ResourceGroup = tostring(parse_json(Properties).resourceGroupName),
AccountName = tostring(parse_json(Properties).resource)
| join kind=leftouter (
AzureDiagnostics
| where Category == "StorageWrite"
| where StatusCode_d == 200
) on $left.ResourceId == $right.ResourceId
| where Properties has "allowBlobPublicAccess" and Properties has "true"
| project TimeGenerated, Caller, ResourceGroup, AccountNameDetect Disabled Sentinel Analytics Rules
SentinelTracks when Microsoft Sentinel analytics rules are disabled. Disabling detection rules is a known attacker technique to reduce alert noise during an attack. Monitoring for this action can help detect insider threats and compromised admin accounts.
AzureActivity
| where OperationNameValue has "microsoft.securityinsights/alertrules/write"
| extend Properties_parsed = parse_json(Properties)
| where Properties_parsed.isDataAction == false
| where Properties_parsed has "disabled" and Properties_parsed has "true"
| project
TimeGenerated,
Caller,
ResourceGroup,
OperationNameValue,
ActivityStatusValue

