T1110.004 Microsoft Sentinel · KQL

Detect Credential Stuffing in Microsoft Sentinel

Adversaries may use credentials obtained from breach dumps of unrelated accounts to gain access to target accounts through credential overlap. Unlike password spraying (T1110.003), which tests one password against many accounts, credential stuffing uses known username-password pairs harvested from prior data breaches — exploiting users who reuse passwords across personal and business accounts. Targeted services commonly include SSH (22/TCP), RDP (3389/TCP), SMB (445/TCP), LDAP (389/TCP), HTTP management portals, VPN gateways, and cloud identity providers such as Azure AD, Okta, and federated SSO endpoints. Real-world threat actors including Chimera and TrickBot (rdpscanDll module) have used credential stuffing at scale against enterprise remote services.

MITRE ATT&CK

Tactic
Credential Access
Technique
T1110 Brute Force
Sub-technique
T1110.004 Credential Stuffing
Canonical reference
https://attack.mitre.org/techniques/T1110/004/

KQL Detection Query

Microsoft Sentinel (KQL)
kusto
let LookbackWindow = 1h;
let FailureThreshold = 15;
let AccountThreshold = 5;
// Windows Security Event failed network/remote-interactive logons
let WindowsStuffing = SecurityEvent
| where TimeGenerated > ago(LookbackWindow)
| where EventID == 4625
| where LogonType in (3, 10)
| where isnotempty(IpAddress) and IpAddress != "-" and IpAddress != "127.0.0.1" and IpAddress != "::1"
| summarize
    FailureCount = count(),
    UniqueTargetAccounts = dcount(TargetUserName),
    AccountSample = make_set(TargetUserName, 10),
    TargetHosts = make_set(Computer, 5),
    SubStatusCodes = make_set(SubStatus, 5),
    FirstAttempt = min(TimeGenerated),
    LastAttempt = max(TimeGenerated)
    by SourceIP = IpAddress, WorkstationName
| where FailureCount >= FailureThreshold and UniqueTargetAccounts >= AccountThreshold;
// Azure AD sign-in failures (cloud credential stuffing)
let AzureStuffing = SigninLogs
| where TimeGenerated > ago(LookbackWindow)
| where ResultType in ("50126", "50053", "50055", "50056", "50057", "50034", "70008", "81016")
| where isnotempty(IPAddress)
| summarize
    FailureCount = count(),
    UniqueTargetAccounts = dcount(UserPrincipalName),
    AccountSample = make_set(UserPrincipalName, 10),
    AppSample = make_set(AppDisplayName, 5),
    UserAgents = make_set(UserAgent, 5),
    FirstAttempt = min(TimeGenerated),
    LastAttempt = max(TimeGenerated)
    by SourceIP = IPAddress
| where FailureCount >= FailureThreshold and UniqueTargetAccounts >= AccountThreshold;
// Successful logon from same source IP — critical indicator that a stuffed pair succeeded
let SuccessAfterFailure = SecurityEvent
| where TimeGenerated > ago(LookbackWindow)
| where EventID == 4624
| where LogonType in (3, 10)
| where isnotempty(IpAddress) and IpAddress != "-"
| summarize
    SuccessCount = count(),
    SuccessAccounts = make_set(TargetUserName, 10)
    by SuccessSourceIP = IpAddress;
union
  (WindowsStuffing
   | join kind=leftouter SuccessAfterFailure on $left.SourceIP == $right.SuccessSourceIP
   | extend
       DataSource = "Windows Security Events",
       StuffingSuccess = isnotempty(SuccessCount),
       Severity = iff(isnotempty(SuccessCount), "Critical", "High")
   | project
       TimeGenerated = LastAttempt, SourceIP, DataSource, FailureCount,
       UniqueTargetAccounts, AccountSample, TargetHosts, SubStatusCodes,
       FirstAttempt, LastAttempt, StuffingSuccess, SuccessAccounts, Severity),
  (AzureStuffing
   | extend
       DataSource = "Azure AD SigninLogs",
       StuffingSuccess = false,
       Severity = "High",
       TargetHosts = dynamic([]),
       SubStatusCodes = dynamic([]),
       SuccessAccounts = dynamic([])
   | project
       TimeGenerated = LastAttempt, SourceIP, DataSource, FailureCount,
       UniqueTargetAccounts, AccountSample, TargetHosts, SubStatusCodes,
       FirstAttempt, LastAttempt, StuffingSuccess, SuccessAccounts, Severity)
| sort by StuffingSuccess desc, FailureCount desc
high severity high confidence

Detects credential stuffing attacks by identifying high-volume authentication failures from a single source IP against multiple distinct accounts within a 1-hour window. Covers on-premises Windows authentication via Security Event 4625 (LogonType 3=Network, 10=RemoteInteractive) and Azure AD via SigninLogs ResultType codes for invalid credentials. The critical indicator is a successful logon (Event 4624) from the same source IP during the same window — proving at least one stuffed credential pair was valid. Results are unioned across both data sources and marked Critical when StuffingSuccess is true.

Data Sources

Logon Session: Logon Session CreationLogon Session: Logon Session MetadataApplication Log: Application Log ContentWindows Security Event ID 4625Windows Security Event ID 4624Azure AD SigninLogs

Required Tables

SecurityEventSigninLogs

False Positives & Tuning

  • Misconfigured service accounts with expired or incorrect credentials repeatedly attempting authentication against multiple systems simultaneously — will appear as high-volume failures from a single host IP
  • Azure AD Connect or third-party directory sync tools (Okta, OneLogin) generating batched authentication failures during sync interruptions or object mismatches
  • Authenticated security scanners (Nessus, Qualys, Rapid7) running credential-based assessments from a dedicated scan IP against multiple systems
  • Load balancers, NAT gateways, or reverse proxies that masquerade multiple users behind a single egress IP, making unrelated individual user failures aggregate as a single-IP attack
  • Helpdesk or IT staff testing account lockout/reset workflows by deliberately triggering failures across multiple test accounts from their workstation
Download portable Sigma rule (.yml)

Other platforms for T1110.004


Testing Methodology

Validate this detection against 4 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.

  1. Test 1Windows SMB Credential Stuffing Simulation (Authorized Lab)

    Expected signal: Windows Security Event ID 4625 on the target host for each attempt: LogonType=3 (Network), IpAddress=<attacker workstation IP>, TargetUserName=each test account, SubStatus=0xC000006A (wrong password for valid account) or 0xC0000064 (unknown username). WorkstationName shows the attacker's hostname. Events appear within 1-2 seconds of each attempt.

  2. Test 2SSH Credential Stuffing with Hydra (Linux — Authorized Lab)

    Expected signal: Linux /var/log/auth.log: multiple 'Failed password for <user> from 127.0.0.1 port <X> ssh2' entries across different usernames. If auditd is enabled: type=USER_AUTH msg= entries with res=failed and acct=<username> in /var/log/audit/audit.log. SSH daemon will log each attempt within milliseconds. If fail2ban is active it may ban 127.0.0.1 after its threshold.

  3. Test 3Azure AD Credential Stuffing via OAuth Password Grant (Authorized Tenant)

    Expected signal: Azure AD SigninLogs entries for each attempt: ResultType=50126 (invalid username or password), IPAddress of the test machine, UserPrincipalName of each test account, AppDisplayName='Microsoft Azure PowerShell', ClientAppUsed='Other clients', UserAgent showing PowerShell HTTP client. Entries appear in Entra admin center under Identity > Monitoring > Sign-in logs within 5-10 minutes.

  4. Test 4RDP Multi-Account Failure Generation (Windows — Lab Only)

    Expected signal: Windows Security Event ID 4625 on the target host: LogonType=10 (RemoteInteractive), TargetUserName showing each test account, IpAddress showing the attacker workstation IP. Event ID 4648 (Logon with Explicit Credentials) may appear on the source workstation. If NLA is enabled, failures occur at the network layer and may show as LogonType=3 before the RDP session establishes.

Unlock Pro Content

Get the full detection package for T1110.004 including response playbook, investigation guide, and atomic red team tests.

Response PlaybookInvestigation GuideHunting QueriesAtomic Red Team TestsTuning Guidance

Related Detections