Blue Team Companion

Wordlist Builder — Password Spraying & Credential Stuffing

Counting failures per account misses spraying by design. The correct aggregation is distinct accounts per source, and the correct follow-up is joining to the first success from that same source.

Open in Red Team Toolkit — wordlist
Counting failures per account misses spraying by design. The correct aggregation is distinct accounts per source, and the correct follow-up is joining to the first success from that same source.

Telemetry generated

Log sourceField / identifierWhat it shows
Windows Security LogSubStatus0xC000006A = existing account, wrong password (spray candidate hit a real account). 0xC0000064 = nonexistent username (spray hit a fabricated account — useful for measuring wordlist quality).
Entra ID Sign-in Logs50126 / 50053 / 5005550126 = invalid credentials; 50053 = account locked; 50055 = password expired. All three appear in spray runs against cloud-joined or hybrid identities.
Windows Security LogKerberos pre-auth failureCatches spraying attempts that never produce a 4625 because the Kerberos AS-REQ fails before NTLM fallback. Essential for on-prem environments where Kerberos is the primary auth protocol.
VPN / SSO Logsauth failureLegacy protocols (IMAP, SMTP AUTH, Basic Auth to OWA) bypass conditional access and MFA, making them a preferred spray target. These failures appear only in VPN or application-specific logs, not in 4625.

Detection rules

Sigma — Distinct Accounts per Source (Password Spray)
title: Password Spray — High Distinct Account Count per Source
id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
status: experimental
description: >
  Counts distinct TargetUserName values per IpAddress over a 30-minute window.
  A high count with low per-account failure rate is the canonical spray signature.
logsource:
  product: windows
  service: security
detection:
  selection:
    EventID: 4625
  timeframe: 30m
  condition: selection | count(TargetUserName) by IpAddress > 15
falsepositives:
  - Misconfigured service accounts cycling through a stale credential list
  - Penetration testing activity
level: high
tags:
  - attack.credential_access
  - attack.t1110.003

Evasion & counters

Evasion

Slow spraying — one attempt per account per day to stay under per-account lockout thresholds.

Counter

Extend detection windows to 24 hours and 7 days as a scheduled hunt with cumulative distinct-account counts. A single source touching 200 accounts over a week is still a spray even if each account sees only one failure.

Evasion

Distributing attempts across a residential proxy pool so each source IP is quiet.

Counter

Aggregate by TARGET ACCOUNT instead of source. An account accumulating failures from many different ASNs is anomalous even when each individual source is below threshold. This is the account-centric inversion of the standard query.

Evasion

Targeting legacy protocols (IMAP, SMTP AUTH, Basic Auth) that bypass conditional access and MFA.

Counter

Disable legacy authentication entirely and alert on any attempt to use it. There is no legitimate reason for modern users to authenticate via legacy protocols in a well-managed environment.

Rule tuning

Preventive control

Deploy phishing-resistant MFA (FIDO2/WebAuthn) for all accounts — it makes credential validity irrelevant to the attacker. Maintain banned-password lists covering seasonal patterns, company name variants, and common substitutions. Disable legacy authentication protocols entirely; there is no compensating control that makes legacy auth safe against spraying.

Back to Detection Library