Query Details
id: b3c9d1e2-f7a8-0b4c-5d6e-7f8a9b0c1d2e
name: Brute Force Success - Credential Stuffing Succeeded
version: 1.0.0
kind: Scheduled
description: |
Detects the classic credential stuffing / brute force success pattern: a user account
experiences multiple non-interactive sign-in failures with brute-force-related error
codes (wrong password, locked account, etc.) followed by a successful sign-in — indicating
the attacker eventually guessed or stuffed the correct credentials.
MITRE ATT&CK: T1110 (Brute Force), T1110.004 (Credential Stuffing)
severity: High
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AADNonInteractiveUserSignInLogs
queryFrequency: 1h
queryPeriod: 3h
triggerOperator: gt
triggerThreshold: 0
tactics:
- CredentialAccess
- InitialAccess
relevantTechniques:
- T1110
query: |
let BruteForceErrors = dynamic(["50126","50055","50056","50064","50053","50034","50057","50128"]);
let Failures =
AADNonInteractiveUserSignInLogs
| where TimeGenerated > ago(3h)
| extend ErrorCode = tostring(ResultType)
| where ErrorCode in (BruteForceErrors)
| summarize
FailCount = count(),
LastFail = max(TimeGenerated),
FailIPs = make_set(IPAddress),
Countries = make_set(Location)
by UserPrincipalName;
AADNonInteractiveUserSignInLogs
| where TimeGenerated > ago(3h)
| where ResultType == 0
| summarize
FirstSuccess = min(TimeGenerated),
SuccessIP = tostring(make_set(IPAddress)[0])
by UserPrincipalName
| join kind=inner Failures on UserPrincipalName
| where FailCount > 5
and FirstSuccess > LastFail
| project
UserPrincipalName,
FailCount,
LastFail,
FirstSuccess,
TimeBetweenFailAndSuccess = (FirstSuccess - LastFail),
FailIPs,
SuccessIP,
Countries
| order by FailCount desc
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: UserPrincipalName
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SuccessIP
customDetails:
FailureCount: FailCount
Countries: Countries
FailureIPs: FailIPs
alertDetailsOverride:
alertDisplayNameFormat: "Brute Force Succeeded - {{UserPrincipalName}} had {{FailCount}} failures then logged in successfully"
alertDescriptionFormat: "Account {{UserPrincipalName}} experienced {{FailCount}} failed sign-in attempts before a successful non-interactive sign-in from {{SuccessIP}}. The pattern matches credential stuffing or brute force success."
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: PT5H
matchingMethod: AnyAlert
groupByEntities:
- Account
groupByAlertDetails: []
groupByCustomDetails: []
This query is designed to detect successful brute force or credential stuffing attacks on user accounts. Here's a simple breakdown of what it does:
Purpose: It identifies when a user account experiences multiple failed sign-in attempts due to brute-force-related errors (like wrong passwords or locked accounts) followed by a successful sign-in. This pattern suggests that an attacker may have guessed or used the correct credentials.
Data Source: The query uses logs from Azure Active Directory, specifically focusing on non-interactive user sign-in logs.
Time Frame: It examines sign-in attempts within the last 3 hours and runs every hour.
Error Codes: It looks for specific error codes that are commonly associated with brute force attacks.
Process:
Output: The query outputs details such as the user account name, the number of failed attempts, the time of the last failure, the time of the first success, the IP addresses involved, and the countries from which the failed attempts originated.
Alerting: If such a pattern is detected, it triggers an alert with a high severity level. The alert includes details about the user account and the nature of the sign-in attempts.
Incident Management: It can create an incident in the system for further investigation, grouping alerts by account to manage related incidents effectively.
Overall, this query helps security teams quickly identify and respond to potential credential stuffing or brute force attacks on their systems.

David Alonso
Released: May 29, 2026
Tables
Keywords
Operators