Every authentication story a Windows machine can tell starts with the same two records. The Windows logon event IDs 4624 and 4625 — successful logon and failed logon — are the highest-volume, highest-value entries in the Security log, and almost every account-based detection I run eventually joins back to one of them. This post explains how to read both events, what the logon type numbers actually mean, and the PowerShell queries I use to turn the raw stream into something that spots password sprays and exposed RDP.
Key Takeaways
- Event ID 4624 records every successful logon and Event ID 4625 every failure, always on the machine where the logon happened — not only on the domain controller.
- The Logon Type field is what turns a generic logon record into a detection signal: type 2 is console, type 3 is network, type 10 is RDP, and type 8 means the password crossed the wire in cleartext.
- The Sub Status code in 4625 tells you why the logon failed —
0xC000006Ais a wrong password,0xC0000064is a username that does not exist, and the two patterns mean different attacks. - Windows logon event IDs come in pairs of audit categories: 4624/4625 live in Logon/Logoff on the target machine, while 4768, 4769 and 4776 live in Account Logon on the authenticating DC.
- A burst of 4625s with one Sub Status across many accounts from one source address is the classic password-spray shape, and it is queryable in a few lines of PowerShell.
Environment
- Active Directory lab domain on Windows Server 2022 domain controllers, with Windows 11 23H2 clients.
- Advanced Audit Policy applied via Group Policy; Logon/Logoff auditing enabled for Success and Failure.
- Security logs centralised with Windows Event Forwarding to a collector server.
- PowerShell 5.1 and 7.4 for the queries; everything here also converts to KQL if the logs land in Sentinel.
The Problem
4624 and 4625 are documented to death, but most write-ups stop at "4624 means success". That is true and useless. The event fires for every service logon, scheduled task, SMB connection, and machine-account session renewal — a domain-joined workstation produces thousands per day without a human touching it. Reading the stream without understanding logon types, the two audit categories, and the failure codes means either alert fatigue or turning the channel off in the SIEM to save ingestion cost.
The other trap is looking in the wrong place. Logon events are written where the logon happens. A failed RDP attempt against a member server is a 4625 on that server, not on the DC. Collect only domain controller logs and you are blind to most of the estate.
The Solution
Step 1 — Understand the two audit categories for authentication events
Windows splits authentication auditing into two categories, and mixing them up leads to double-counting or missed coverage:
- Logon/Logoff — events about a session being created on a specific machine: 4624 (success), 4625 (failure), 4634 and 4647 (logoff), 4648 (logon with explicit credentials), 4672 (special privileges assigned). These land on the machine being logged on to.
- Account Logon — events about credentials being validated: 4768 and 4769 for Kerberos ticket activity, 4776 for NTLM validation. In a domain, these land on the domain controller regardless of which machine the user is signing in to.
This split is also the answer to the "which Windows event codes cover SSO and authentication" question: one interactive sign-in typically produces a 4768 and 4769 on the DC (the Kerberos exchange), a 4624 on the workstation (the session), and later 4624 type 3 events on every server the ticket touches. Single sign-on does not mean a single event — it means the credential prompt only happened once. The Kerberos half is covered in the Event ID 4769 Kerberoasting post; this post is the Logon/Logoff half.
Verify the right subcategories are on before trusting any query:
auditpol /get /category:"Logon/Logoff"
auditpol /get /category:"Account Logon"
Step 2 — Read Event ID 4624 and its logon types
The fields worth reading in a 4624: New Logon → Account Name (who got the session), Logon Type (how), Source Network Address (from where), Authentication Package (Kerberos or NTLM), and on current Windows versions Elevated Token, which tells you whether the session got an administrative token. The Logon Type is the field that does the analytical work:
| Logon type | Name | What it means in practice |
|---|---|---|
| 2 | Interactive | Keyboard at the console, or a Hyper-V/VM console session. Credentials are cached in LSASS. |
| 3 | Network | SMB shares, most remote PowerShell, IIS with Windows auth. By far the noisiest type; credentials are not cached on the target. |
| 4 | Batch | Scheduled task running with stored credentials. |
| 5 | Service | A service starting under its configured account. Fires at boot for every service. |
| 7 | Unlock | Workstation unlock. Useful for presence timelines, not much else. |
| 8 | NetworkCleartext | The password crossed the wire in cleartext — classically IIS Basic authentication. Worth an alert on any modern network. |
| 9 | NewCredentials | runas /netonly. Also what pass-the-hash tooling produces when it injects credentials into a new logon session, which makes unexpected type 9s interesting. |
| 10 | RemoteInteractive | RDP session. Credentials cached on the target unless Remote Credential Guard or Restricted Admin is in play. |
| 11 | CachedInteractive | Interactive logon using cached domain credentials — a laptop signing in while off the corporate network. |
Two immediate detections fall out of the table: any type 8 logon is a configuration problem waiting to be an incident, and type 10 logons from unexpected source addresses are your RDP exposure map. Types 12 and 13 exist as cached variants of remote and unlock logons; they are rare enough that I look at them individually when they appear.
The Step 2 anatomy on a real event: Subject is SYSTEM, New Logon is the account that matters, Logon Type 7 says unlock — read those three before anything else.
Step 3 — Read Event ID 4625 failure codes
4625 carries a Status and a more specific Sub Status, both NTSTATUS codes. The Sub Status is the one to key detections on:
| Sub Status | Meaning |
|---|---|
0xC000006A | Correct username, wrong password. |
0xC0000064 | Username does not exist. |
0xC0000234 | Account locked out. |
0xC0000072 | Account disabled. |
0xC000006F | Logon outside permitted hours. |
0xC0000071 | Password expired. |
0xC0000193 | Account expired. |
0xC000015B | Account not granted this logon type on this machine. |
The distinction between the first two rows matters. A spike of 0xC000006A across many accounts is password spraying against known-good usernames; a spike of 0xC0000064 is someone still enumerating, guessing usernames that do not exist. Both are worth alerts, but they sit at different stages of the same attack.
One honest caveat from my own lab: not every 0xC000006A burst is an attacker. My Hyper-V VM consoles default to a US keyboard layout, and typing a German password with a z or a symbol in it through that console produces a perfectly attacker-shaped wrong-password failure every time. Stale credentials in scheduled tasks and disconnected RDP sessions produce the same effect on a schedule. Baseline first, alert second.
Step 4 — Query Windows logon event IDs with PowerShell
The password-spray shape — one source, many accounts, same failure code — groups cleanly. Run this against the forwarded-events channel on the collector rather than per-machine:
# Failed logons in the last 24h, grouped by source address
Get-WinEvent -FilterHashtable @{
LogName = 'ForwardedEvents'
Id = 4625
StartTime = (Get-Date).AddDays(-1)
} -ErrorAction SilentlyContinue |
Where-Object { $_.Properties[9].Value -eq 0xC000006A } |
Group-Object { $_.Properties[19].Value } |
ForEach-Object {
[pscustomobject]@{
SourceIP = $_.Name
Failures = $_.Count
DistinctAccounts = ($_.Group | ForEach-Object { $_.Properties[5].Value } |
Sort-Object -Unique).Count
}
} |
Where-Object DistinctAccounts -gt 5 |
Sort-Object DistinctAccounts -Descending
In my lab, replaying a small spray from COMP1 against ten accounts showed up as a single row: one source address, ten distinct accounts, eleven failures. The same grouping trick with Properties[8].Value (logon type) on 4624 builds the RDP exposure report:
# Successful RDP logons (type 10) in the last 7 days
Get-WinEvent -FilterHashtable @{
LogName = 'ForwardedEvents'; Id = 4624
StartTime = (Get-Date).AddDays(-7)
} -ErrorAction SilentlyContinue |
Where-Object { $_.Properties[8].Value -eq 10 } |
Select-Object TimeCreated, MachineName,
@{N='User'; E={ $_.Properties[5].Value }},
@{N='SourceIP'; E={ $_.Properties[18].Value }}
The cloud-identity equivalent of the spray query — the same shape against Entra ID sign-in logs — is covered in the Entra ID password spray detection post.
The Step-4 grouping query on the collector: one source address resolving to many distinct accounts under the 0xC000006A wrong-password code — the password-spray shape in a single row.
Step 5 — The supporting cast: 4634, 4647, 4648 and 4672
Four neighbours round out the logon picture. 4634 is the generic session-end event and 4647 is a user actually clicking sign-out; pairing them with 4624 by the Logon ID field gives session duration. 4648 fires when a logon uses explicitly different credentials — runas, or an attacker moving laterally with stolen admin credentials from a normal user's session. 4672 fires alongside any 4624 that received sensitive privileges, which makes it the cheapest possible "an admin just logged on here" marker. On a workstation where domain admins should never interactively sign in, 4672 for a domain admin account is a one-line, high-fidelity rule.
Frequently Asked Questions
What is the difference between Event ID 4624 and 4625?
4624 records a successful logon and 4625 a failed one, both written to the Security log of the machine where the logon was attempted. They share most fields — account, logon type, source address — but 4625 adds the Status and Sub Status codes that explain why the attempt failed.
Which logon type is RDP in Event ID 4624?
Type 10 (RemoteInteractive). A reconnect to an existing session can also surface as type 7, and if Restricted Admin mode or Remote Credential Guard is enabled the session behaves differently around credential caching, but type 10 is the number to filter on for RDP tracking.
What does Sub Status 0xC000006A mean in Event ID 4625?
The username was valid but the password was wrong. Many of these across different accounts from one source is the password-spray pattern; the same code repeating for one account on a schedule is usually a stale stored credential — a scheduled task, service, or disconnected session using an old password.
Why is Event ID 4625 not on my domain controller?
Because Logon/Logoff events are written where the logon happens, not where the credential is validated. A failed logon against a member server is a 4625 on that server; the DC records the validation side as 4776 (NTLM) or 4768/4771 (Kerberos). Collecting only DC logs misses every local and member-server logon failure.
Which Windows event IDs cover logoff?
4634 fires when any logon session ends, and 4647 fires when a user initiates an interactive sign-out. 4647 is the more deliberate signal; 4634 is bulk session housekeeping and appears for network logons constantly. Join either back to the matching 4624 via the Logon ID field to reconstruct session lifetimes.
Conclusion
4624 and 4625 are not sophisticated telemetry. They are old, verbose, and drowning in machine-account noise — and still the backbone of account-based detection on Windows, because every attacker who authenticates produces them and very few avoid the patterns they leave. Logon types, the two audit categories, and the Sub Status codes are the three pieces of reading comprehension that make the channel usable.
The practical order of work: confirm auditing is on, centralise the logs so member servers are not invisible, then start with the two queries above. Microsoft's field-level reference is worth keeping open the first few times you read one raw: Event 4624 on Microsoft Learn. After that, the structure sticks.
Related Posts
- Essential Windows Event IDs for Security Monitoring — where 4624 and 4625 sit in the full monitoring baseline.
- Detecting Kerberoasting with Windows Event ID 4769 — the Account Logon side of the same authentication flow.
- PowerShell Event Log Management for Windows Security — sizing and querying the Security log these events land in.
Editorial note: posts on this blog are drafted with AI assistance and then reviewed, edited, and tested against a real environment before publishing. Commands, output, and screenshots come from systems I actually ran the work on.
0 comments:
Post a Comment