Skip to content

Password Spraying

Also calledPassword spray, Spray attack

One guessed password tried against many accounts, over Kerberos and NTLM.

Needs
Network
Gives
PasswordandDomain Account

How the Attack Works

Each Kerberos AS request carries a timestamp sealed with a key made from the password, and each NTLM response is computed from it, so the DC confirms or refuses every guess it is sent. A spray tries one password across many accounts, so no account fails often enough to lock, while a common password is likely to fit one of them. With failure auditing on, the DC logs each refusal, but the failures are spread across accounts and across whichever DCs answered.

Read first AS Request and Pre-Authentication, NTLM Authenticate and Validation, Where Sign-In Evidence Lands, Reading Logon Events

How It Plays Out

The attack step by step. Each step shows which machines take part, what travels, the keys and tickets each side now holds, what is logged and what a defender can see.

An unknown device on the network tries the same password against many accounts, over Kerberos and over SMB.Step through it

192.0.2.66 Unknown device

dc-01 Domain controller

  • dana's key
  • krbtgt key
  • Netlogon key

srv-fin-01 File server

  • srv-fin-01 key
  • Netlogon key
  1. Step 1 of 3, AS Requests, 192.0.2.66 to dc-01
  2. Step 2 of 3, Refusals, One TGT, dc-01 to 192.0.2.66
  3. Step 3 of 3, NTLM Sign-Ins, 192.0.2.66 to srv-fin-01
  1. Step 1 of 3: AS Requests

    192.0.2.66 Unknown device to dc-01 Domain controller

    Requests for TGTs, one per account KRB_AS_REQ Kerberos, port 88

    The device asks dc-01 for a TGT for account after account, each with a timestamp sealed with a key made from the same guess.

    What Defenders See

    The Security log on dc-01 shows event 4771 with Failure Code 0x18 for many accounts from one Client Address. It also shows event 4768 with Result Code 0x6 for names that do not exist.

    Hooks into Kerberos AS Request

  2. Step 2 of 3: Refusals, One TGT

    dc-01 Domain controller to 192.0.2.66 Unknown device

    Error replies and one TGT KRB_ERROR, KRB_AS_REP Kerberos, port 88

    dc-01 refuses each wrong guess with an error, and answers dana's request with a TGT, which shows the guess was her password.

    Keys and Tickets

    • 192.0.2.66 now holds dana's key (new at this step) TGT (new at this step) TGT session key (new at this step)

    What Defenders See

    Among the failures, the Security log on dc-01 shows event 4768 with Result Code 0x0 for dana, from the same Client Address. Wherever an account locks out, event 4740 lands in that machine's Security log.

  3. Step 3 of 3: NTLM Sign-Ins

    192.0.2.66 Unknown device to srv-fin-01 File server

    NTLM answers made from the guess AUTHENTICATE_MESSAGE SMB, port 445

    The same guess goes to srv-fin-01 as NTLM sign-ins over SMB, and srv-fin-01 has dc-01 check each one.

    What Defenders See

    The Security log on srv-fin-01 shows event 4625 for many names from one Source Network Address. The Security log on dc-01 shows event 4776 with Error Code 0xC000006A or 0xC0000064.

    Hooks into NTLM DC Answer

Needs First

What the attacker must already hold for this attack to be possible.

  • Network AccessA device that can reach a domain controller, or a server that accepts NTLM, with no account needed.

Gives the Attacker

What running it hands the attacker to use next.

  • A PasswordThe password of any account that used the guessed one.
  • A Domain AccountA working domain account, enough for most of the attacks that follow.

What Defenders See

What this attack leaves for a defender to find, and what to read in each. None of it is proof on its own, so treat each as a lead and confirm it against the rest.

Event and LogWritten OnLook ForSwitch It On
4771 Kerberos pre-authentication failed (opens in a new tab) Security logDomain controllersFailure Code 0x18 for many different accounts from one Client Address.AS Request and Pre-Authentication explains how to read it.Audit Kerberos Authentication Service
4768 A Kerberos authentication ticket (TGT) was requested (opens in a new tab) Security logDomain controllersResult Code 0x6 for names that do not exist, and a 0x0 success from the same Client Address among the failures.AS Reply: The TGT explains how to read it.Audit Kerberos Authentication Service
4776 The computer attempted to validate the credentials for an account (opens in a new tab) Security logThe computer that holds the account, a domain controller for a domain account or the computer itself for a local oneError Code 0xC000006A (real name, wrong password) or 0xC0000064 (no such name) across many Logon Accounts.NTLM Authenticate and Validation explains how to read it.Audit Credential Validation
4625 An account failed to log on (opens in a new tab) Security logThe computer where the logon was attemptedMany names failing from one Source Network Address, Logon Type 3, Sub Status 0xC000006A or 0xC0000064.Reading Logon Events explains how to read it.Audit Logon, and Audit Account Lockout for a locked-out account
4740 A user account was locked out (opens in a new tab) Security logDomain controllers, member servers and workstationsSeveral accounts locking out together, with Caller Computer Name naming the machine the failures came from.Audit User Account Management
4648 A logon was attempted using explicit credentials (opens in a new tab) Security logThe computer the credentials were used fromWhere the guesses go through Windows on a domain machine, bursts show there, each naming a different account.Explicit Credentials on the Source Machine explains how to read it.Audit Logon

What It Looks Like

One event from the worked example, decoded field by field, so you can see what to read in it and what each value means.

4771 Kerberos pre-authentication failed

In the Security log on dc-01,

One of many wrong guesses, this one for svc-backup, from a device with no DHCP lease.

  • The account this guess was for. Count the distinct names failing from the same address, because a spray touches many, once each.

    As Windows writes it: Account Name svc-backup

  • A request for a TGT, the first step of any Kerberos sign-in.

    As Windows writes it: Service Name krbtgt/CORP.EXAMPLE

  • Pre-authentication information was invalid, which means the timestamp was sealed with the wrong password.

    As Windows writes it: Failure Code 0x18

  • An ordinary encrypted timestamp, so the request looked like a normal sign-in.

    As Windows writes it: Pre-Authentication Type 2

  • The source. With no DHCP lease and no device record, it is an unmanaged device on the network.

    As Windows writes it: Client Address ::ffff:192.0.2.66

Defender for Identity Alerts

Where Defender for Identity runs, its sensors raise these from what they read on the servers they are installed on, domain controllers above all. Each names what it flags, which is a lead to confirm, not proof on its own.

Blind Spots

Where this attack leaves little or nothing to see, so a quiet log is not read as an all-clear.

  • Per-account lockout and simple volume alerts miss a spray, so count the distinct accounts failing from each source, over days as well as minutes.
  • From a device outside the domain only the DCs' and the targets' events remain, and each DC logs only the guesses it answered, so collect every DC.

Hunt It

The query to run in each tool, and how well each one sees this attack. Pick the tool you use, and the others load their query when you open them.

Needs Defender for Identity sensors on every DC, which record the Kerberos and NTLM failures they see. A shared address such as a terminal server or VPN gateway also gathers many accounts' failures, so read FailureReason and look for a later success.

KQLDefender XDR, Advanced hunting
// Failed Kerberos and NTLM sign-ins spread across many accounts from one source (Defender for Identity)IdentityLogonEvents| where Timestamp > ago(30d)| where ActionType == "LogonFailed" and Protocol in~ ("Kerberos", "Ntlm")| summarize FailedAccounts = dcount(AccountName), Failures = count(), Protocols = make_set(Protocol), Reasons = make_set(FailureReason), FirstSeen = min(Timestamp), LastSeen = max(Timestamp) by IPAddress, DeviceName| order by FailedAccounts desc

How to Prevent It

The controls that break this attack, each with how it helps here and, where the Registry topic has it, where to check it on a machine.

Sources