Home / Blog / Cheat Sheets
Windows Logon Events Cheat Sheet: Event IDs, Types and Failure Codes
A shift-ready reference for Windows logon event IDs, logon types and failure codes, with KQL, SPL and PowerShell to show who logged on, from where and how.
Almost every Windows investigation comes back to the same question: who logged on, from where and how? This cheat sheet puts the event IDs, logon types and failure codes you need in one place, so that newer analysts can read an authentication alert with confidence and experienced ones have a quick reference on shift.
Scenario: An alert reports 300 failed logons against FS-02 from 10.0.4.22 in ten minutes, followed by a successful logon for svc-backup. You need to work out whether this is a misconfigured service or an attack. The answer is sitting in three fields: the logon type, the sub status and the source address.
Which event IDs should you know?
All of these appear in the Windows Security log, provided the relevant audit policies are enabled. Keep in mind where each one is written, because a query against the wrong host type returns nothing and proves nothing.
| Event ID | Meaning | Logged on | Why it matters |
|---|---|---|---|
4624 | Successful logon | Target host | Your main record of access |
4625 | Failed logon | Target host | Brute force, spraying, stale credentials |
4634 | Logoff | Target host | Session end, matched on Logon ID |
4647 | User initiated logoff | Target host | Interactive sessions the user ended |
4648 | Logon with explicit credentials | Host running the process | A process used another account's credentials |
4672 | Special privileges assigned | Target host | Admin-equivalent logon session |
4740 | Account locked out | Domain controllers, member servers, workstations | Shows the caller computer behind a lockout |
4768 | Kerberos TGT requested | Domain controller | Initial domain authentication, including unknown users |
4771 | Kerberos pre-authentication failed | Domain controller | Wrong passwords against domain accounts |
4776 | NTLM credential validation | Authoritative host, so the DC for domain accounts | NTLM use and failures |
4778 | Session reconnected | Host with the session | RDP reconnects and fast user switching |
Tip: A 4625 only appears on the host the user tried to access. For a domain-wide view of bad passwords, add 4771 and 4776 from your domain controllers.
What does each logon type mean?
The logon type tells you how the session was created, and it is usually the fastest way to judge whether a logon makes sense. The last column shows whether Microsoft lists the type as leaving reusable credentials in the LSA session. That matters when you assess what an attacker could steal from a host after an administrator has logged on to it.
| Type | Name | What it usually means | Reusable credentials |
|---|---|---|---|
0 | System | System account activity, such as startup | Not listed |
2 | Interactive | Logon at the keyboard or console | Yes |
3 | Network | Access over the network, such as a file share | No, except with delegation |
4 | Batch | Scheduled tasks | Yes |
5 | Service | A service started by the Service Control Manager | Yes |
7 | Unlock | A workstation was unlocked | Not listed |
8 | NetworkCleartext | Password passed to the authentication package in unhashed form, such as IIS Basic | Yes |
9 | NewCredentials | Same local identity, different credentials for outbound connections, such as runas /netonly | Yes |
10 | RemoteInteractive | Remote Desktop or Terminal Services | Yes |
11 | CachedInteractive | Logon with cached credentials, DC not contacted | Not listed |
12 | CachedRemoteInteractive | As type 10, used for internal auditing | Not listed |
13 | CachedUnlock | Unlock using cached credentials | Not listed |
Note: Failed RDP attempts are not always logged as type 10. With Network Level Authentication on, a failure commonly appears as a 4625 with logon type 3, because it fails before the remote session exists. Do not filter out type 3 when you investigate failed RDP.
What do the failure codes tell you?
In a 4625, Status gives the reason and SubStatus often gives the more precise one. Read the sub status first. If it is 0x0, fall back on the status. Most of these codes also appear as the Error Code in event 4776.
| Code | Meaning | What to think |
|---|---|---|
0xC0000064 | Username does not exist | Many of these across names suggests enumeration or a bad wordlist |
0xC000006A | Correct username, wrong password | The account is real, so guessing is more of a concern |
0xC000006D | Generic bad username or authentication information | Check the sub status for the detail |
0xC000006F | Outside authorised hours | Valid credentials, possibly used at an odd time |
0xC0000070 | Unauthorised workstation | Valid credentials used from a host they are not allowed on |
0xC0000071 | Password expired | Often a stale service or scheduled task |
0xC0000072 | Account disabled | Attempts on leavers' accounts deserve a look |
0xC000015B | Logon type not granted on this host | Correct credentials, wrong logon right, worth checking who tried |
0xC0000193 | Account expired | Often contractors or old accounts |
0xC0000224 | Must change password at next logon | Usually new or recently reset accounts |
0xC0000234 | Account locked out | Pair with 4740 to find the caller computer |
Kerberos result codes
Kerberos failures on domain controllers use different codes. You will see these in 4771, and 0x6 in 4768.
| Code | Name | Meaning |
|---|---|---|
0x6 | KDC_ERR_C_PRINCIPAL_UNKNOWN | Username does not exist |
0x12 | KDC_ERR_CLIENT_REVOKED | Credentials revoked, such as a disabled or locked account |
0x17 | KDC_ERR_KEY_EXPIRED | Password has expired |
0x18 | KDC_ERR_PREAUTH_FAILED | Wrong password |
0x25 | KRB_AP_ERR_SKEW | Clock difference too great, usually a time sync fault |
Which fields answer who, where and how?
Each question maps to a few fields. The names below are the Windows event names and, in brackets, the Microsoft Sentinel SecurityEvent columns.
Which patterns should you escalate?
These combinations come up regularly. None of them is proof on its own, so confirm each against what the account and host normally do.
Failures, then success
HighMany 4625 events with 0xC000006A for one account from one source, then a 4624 from the same source.
Treat the credentials as compromised until shown otherwise. Review what the session did. T1110 Brute Force.
Password spraying
HighOne source, many usernames, few attempts for each. Spraying is designed to stay below lockout limits, so expect few lockouts.
Check for any success from the source and identify the targeted accounts. T1110.003 Password Spraying.
Possible pass the hash
HighA 4624 of type 9 with seclogo as the logon process, or type 3 using NTLM with a key length of 0. Both appear in the Sigma rule "Pass the Hash Activity 2".
Rule out runas /netonly and check the host for credential tool activity. T1550.002 Pass the Hash.
Unusual RDP
MedA type 10 between workstations, from a server to a workstation, or from a public address.
Confirm with the user, check 4778 reconnects and trace the source host. T1021.001 Remote Desktop Protocol.
Service account misuse
MedAn account that normally logs on as type 4 or 5 suddenly appears with type 2 or 10.
Service accounts rarely need interactive sessions. Identify the source and ask the owner. T1078 Valid Accounts.
New task or service logon
MedA type 4 or 5 logon for an account that has not used one on that host before.
Look for a recent 4698 (scheduled task created) or 4697 (service installed) on the same host.
Keep these queries to hand
Adjust the thresholds and time ranges to suit your environment. Splunk field names depend on how your Windows data is ingested, so check them first.
Microsoft Sentinel
SecurityEvent
| where TimeGenerated > ago(1h)
| where EventID == 4625
| where IpAddress !in ("-", "")
| summarize Attempts = count(),
Users = dcount(TargetUserName),
Hosts = dcount(Computer),
Reasons = make_set(SubStatus, 5)
by IpAddress
| where Users >= 10
| sort by Users desc
let lookback = 1h;
let failures = SecurityEvent
| where TimeGenerated > ago(lookback)
| where EventID == 4625
| summarize Failures = count(), LastFailure = max(TimeGenerated)
by TargetUserName, IpAddress
| where Failures >= 5;
SecurityEvent
| where TimeGenerated > ago(lookback)
| where EventID == 4624
| where LogonType in (3, 10)
| project SuccessTime = TimeGenerated, TargetUserName, IpAddress, Computer,
LogonType, AuthenticationPackageName
| join kind=inner failures on TargetUserName, IpAddress
| where SuccessTime > LastFailure
| project SuccessTime, TargetUserName, IpAddress, Computer, LogonType,
AuthenticationPackageName, Failures
Microsoft Defender XDR
The DeviceLogonEvents table stores the logon type as text instead of a number, so check the values in your tenant if a filter returns nothing.
DeviceLogonEvents
| where Timestamp > ago(24h)
| where ActionType == "LogonSuccess"
| where LogonType == "RemoteInteractive"
| where RemoteIPType == "Public"
| project Timestamp, DeviceName, AccountDomain, AccountName, RemoteIP, Protocol
| sort by Timestamp desc
Splunk
index=wineventlog EventCode=4625 earliest=-1h
| stats count AS attempts dc(user) AS users values(Sub_Status) AS sub_status BY src
| where users>=10
| sort - users
Note: Classic Windows event sourcetypes tend to expose Sub_Status and Logon_Type, whereas XML ingestion tends to use SubStatus and LogonType. Run a quick search over one event to see which you have.
PowerShell on a single host
Use this when the host is not sending logs to your SIEM. Reading the Security log needs elevated rights.
$events = Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 4625
StartTime = (Get-Date).AddHours(-24)
} -MaxEvents 200 -ErrorAction SilentlyContinue
foreach ($e in $events) {
$xml = [xml]$e.ToXml()
$d = @{}
foreach ($n in $xml.Event.EventData.Data) { $d[$n.Name] = $n.'#text' }
[pscustomobject]@{
Time = $e.TimeCreated
User = $d['TargetUserName']
LogonType = $d['LogonType']
Status = $d['Status']
SubStatus = $d['SubStatus']
Source = $d['IpAddress']
}
}
Key takeaways
- Read logon type, source address and sub status first: together they explain most authentication alerts.
- 4625 lives on the target host, while 4768 and 4771 live on domain controllers, so query the right place.
0xC0000064means the username is wrong and0xC000006Ameans the password is wrong, which changes how you read an attack.- Failed RDP can appear as type 3, so do not rely on type 10 alone.
- A failure run followed by a success from the same source is the pattern to check first.
Bookmark this page, and test the queries against your own data while things are quiet. Knowing how normal logons look in your estate, including which accounts use which logon types, is what makes the odd one stand out when an alert arrives.