ATT&CK library
T1110.003Credential Access

Password Spraying

Instead of many passwords against one account (which locks it), spraying tries one common password against many accounts. Here is the failed-logon signature and the rules that catch it before it succeeds.

Run it live: Kerberoast to Domain Admin

On a real domain, spray a common password across accounts from the attacker box and watch the 4625 failure pattern build in Wazuh.

Launch it

Password spraying flips brute force on its head. Trying 1,000 passwords against one account trips the lockout policy fast. Trying one password (like Autumn2026! or the company name) against 1,000 accounts often doesn't, and in an org that size, some account is using it. It is one of the most common ways attackers get their first valid domain credential, and it is quiet because each account only sees one or two failures.

What it looks like

The signature is not in any single event, it is in the pattern: a burst of failed logons (Event ID 4625) across many distinct accounts from one source, in a short window, often with failure reason 0xC000006A (bad password). One success (4624) among the failures is the account that just fell.

  • Security EID 4625 for many different TargetUserNames from one IpAddress/Workstation in minutes.
  • SubStatus 0xC000006A (wrong password), not 0xC0000064 (user doesn't exist) — the attacker has a real user list.
  • Against a DC or a public-facing service (VPN, OWA, ADFS), often Logon Type 3.
  • A lone 4624 success mixed into the 4625 burst is the compromised account.

Detect it: Sigma (threshold correlation)

sigma / password-spraying-4625.yml
title: Password Spraying, Many Accounts from One Source
id: 0f1a2b3c-spry-4d5e-6f70-tyrian000007
status: stable
logsource:
  product: windows
  service: security
detection:
  selection:
    EventID: 4625
    SubStatus: '0xc000006a'   # bad password (account exists)
  timeframe: 5m
  condition: selection | count(TargetUserName) by IpAddress > 10
level: high
tags:
  - attack.credential_access
  - attack.t1110.003

The `count(distinct TargetUserName) by source` over a short window is the whole detection, spraying is defined by breadth, not depth. Ten distinct accounts failing one password from one IP in five minutes is not a user fat-fingering their password. Tune the threshold to your environment's baseline.

Detect it: Wazuh (frequency rule)

wazuh / local_rules.xml
<group name="windows,credential_access,attack,">
  <rule id="100610" level="5">
    <if_group>windows_security</if_group>
    <field name="win.system.eventID">^4625$</field>
    <field name="win.eventdata.subStatus">0xc000006a</field>
    <description>Failed logon, bad password</description>
  </rule>

  <!-- Many bad-password failures from one source = spraying -->
  <rule id="100611" level="12" frequency="10" timeframe="300">
    <if_matched_sid>100610</if_matched_sid>
    <same_field>win.eventdata.ipAddress</same_field>
    <description>Password spraying: many failed logons from one source (T1110.003)</description>
    <mitre>
      <id>T1110.003</id>
    </mitre>
  </rule>
</group>

Reduce the surface

  • MFA on every external surface (VPN, webmail, ADFS), it defeats a valid sprayed password.
  • Ban common and breached passwords with a password filter; 'Season+Year!' should be impossible.
  • Smart lockout / rate limiting on public auth endpoints.
  • Alert on the distinct-account failure pattern, and hunt for the lone success inside it.
Tyrian's Kerberoast to Domain Admin scenario runs on a real domain, so you can spray from the attacker box and watch the 4625 breadth pattern build in Wazuh, then confirm your threshold rule actually fires before it matters.

Test this detection on your own SIEM

Launch the Kerberoast to Domain Admin range, fire T1110.003, and measure how fast you catch it. $5 free credit, no card.