Query Details

ROPC Credential Stuffing - Failed Password Grant Spray

24 ROPC Credential Stuffing

Query

let LegitRopcApps = dynamic([
    "Microsoft Authentication Broker",
    "Microsoft Intune Company Portal",
    "Azure AD Connect",
    "Microsoft Office",
    "Microsoft Office Authentication Broker"
]);
let SprayErrors = dynamic(["50126","50053","50056","50055","50064"]);
// ROPC failures land in SigninLogs as well as the non-interactive table; union both.
let MinFailures = 20;   // raised 15 -> 20 to offset the extra SigninLogs volume
let MinUsers    = 8;    // raised 5 -> 8
let RopcFailures =
    union isfuzzy=true
        (SigninLogs
            | where TimeGenerated > ago(1h)
            | where AuthenticationProtocol =~ "ropc"
            | project TimeGenerated, UserPrincipalName, IPAddress, Location, AppDisplayName, ResultType),
        (AADNonInteractiveUserSignInLogs
            | where TimeGenerated > ago(1h)
            | where AuthenticationProtocol =~ "ropc"
            | project TimeGenerated, UserPrincipalName, IPAddress, Location, AppDisplayName, ResultType);
RopcFailures
| invoke ExcludeAllowlistedIPs_AADNI()
| where ResultType in (SprayErrors)
| where AppDisplayName !in~ (LegitRopcApps)
| summarize
    FailCount = count(),
    Users     = dcount(UserPrincipalName),
    UserList  = make_set(UserPrincipalName, 50),
    Apps      = make_set(AppDisplayName),
    Errors    = make_set(ResultType),
    FirstSeen = min(TimeGenerated),
    LastSeen  = max(TimeGenerated)
  by IPAddress, Location
| where FailCount >= MinFailures and Users >= MinUsers
| order by FailCount desc

Explanation

This query is designed to detect suspicious activity that might indicate a credential-stuffing attack using the ROPC (Resource Owner Password Credential) method. Here's a simplified breakdown:

  1. Purpose: The query identifies patterns of failed login attempts that suggest a credential-stuffing attack. This is when an attacker tries many password combinations across different user accounts from a single IP address.

  2. How it Works:

    • It looks for at least 20 failed login attempts (specific error codes) from the same IP address within an hour.
    • These attempts must target at least 8 different user accounts.
    • The query checks two data sources: SigninLogs and AADNonInteractiveUserSignInLogs.
  3. Exclusions:

    • Known legitimate applications using ROPC are excluded to reduce false positives.
    • IP addresses on an allowlist are also excluded.
  4. Output:

    • The query summarizes the data by IP address, showing the number of failed attempts, the number of targeted users, and other details like the applications involved and error codes.
    • It orders the results by the number of failed attempts.
  5. Alerting:

    • If the conditions are met, an alert is generated with details about the IP address, number of users targeted, and number of failures.
    • The alert is configured to create an incident for further investigation.
  6. Security Context:

    • This detection is related to MITRE ATT&CK techniques for password spraying and valid accounts, indicating potential unauthorized access attempts.

In essence, this query helps security teams identify and respond to potential credential-stuffing attacks that exploit the ROPC protocol to bypass multi-factor authentication (MFA).

Details

David Alonso profile picture

David Alonso

Released: July 16, 2026

Tables

SigninLogsAADNonInteractiveUserSignInLogs

Keywords

AzureActiveDirectoryAADNonInteractiveUserSignInLogsSigninLogsUserPrincipalNameIPAddressLocationAppDisplayNameResultTypeMicrosoftAuthenticationBrokerMicrosoftIntuneCompanyPortalAzureADConnectMicrosoftOfficeMicrosoftOfficeAuthenticationBroker

Operators

letdynamicunionisfuzzywhere=~projectinvokein!in~summarizecountdcountmake_setminmaxbyorder bydesc

Severity

High

Tactics

CredentialAccessInitialAccess

MITRE Techniques

Frequency: 1h

Period: 1h

Actions

GitHub