Reading Windows logon types in event 4624

Logon types, the 4624 fields that change the reading, 4625 failure codes, following a Logon ID through a session, and queries for PowerShell, wevtutil and KQL.

Event 4624, “An account was successfully logged on”, is the event most Windows investigations end up leaning on. It is written on the computer that was accessed, at the moment a logon session is created there. On its own it says that someone got in. The logon type says how, and the other fields say from where, with which protocol and with what privileges.

This post is a working reference: the logon types, the event’s XML fields, the failure codes in 4625, how to follow one session from logon to logoff, and queries that pull the answers out at scale.

Microsoft’s reference for the event lists these values:

TypeNameWhat it means
0SystemUsed only by the System account, for example at startup
2InteractiveA user logged on at this computer
3NetworkA user or computer logged on to this computer from the network
4BatchA process ran on behalf of a user without direct intervention, such as a scheduled task
5ServiceThe Service Control Manager started a service
7UnlockThe workstation was unlocked
8NetworkCleartextA network logon where the password reached the authentication package in unhashed form
9NewCredentialsA caller cloned its token and set new credentials for outbound connections only
10RemoteInteractiveA logon through Terminal Services or Remote Desktop
11CachedInteractiveA logon with locally cached domain credentials; no domain controller was contacted
12CachedRemoteInteractiveAs RemoteInteractive, used for internal auditing
13CachedUnlockWorkstation unlock with cached credentials

Type 2 and 10 are hands on a keyboard. Interactive and RemoteInteractive logons are a person at the console or over RDP. In an intrusion, a type 10 logon from an unexpected address is often the first solid sign of hands-on-keyboard activity.

Type 3 is the noisy one. Mapped drives, remote service management, file shares, WMI, WinRM and many lateral-movement tools all produce network logons. A single type 3 event proves little. A burst from one source to many hosts, or to one host from an unusual source, is where the signal is.

Type 4 and 5 should belong to known accounts. Batch and service logons are expected for scheduled tasks and services. Microsoft’s monitoring guidance suggests watching for a mismatch: a member of a domain administrative group appearing on a batch or service logon is worth a look.

Type 8 means a plaintext password reached the authentication package. That usually points at basic authentication against a web service such as IIS, or a script passing credentials in the clear.

Type 9 is easy to misread. A NewCredentials logon keeps the caller’s local identity and uses different credentials only for outbound network connections, which is what runas /netonly does. The account named under New Logon is not the one acting locally; the outbound identity appears in the TargetOutboundUserName field. The logon process is seclogo and the package Negotiate.

Caution:

Credential-theft tools that start a process with an injected NTLM hash or Kerberos ticket typically produce the same type 9 / seclogo shape, because they use the same API. A type 9 logon outside a known administrative workflow is worth following up, but the event alone cannot tell the two apart.

Type 11 means the domain controller was not asked. Cached logons happen on laptops away from the network. On a server that should always reach a domain controller, they are unusual.

The rendered message in Event Viewer is built from named fields in the event’s XML. Queries and parsers work on those names, so it pays to know them. This is a trimmed type 10 event, with illustrative values:

XML
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <System>
    <EventID>4624</EventID>
    <Version>2</Version>
    <TimeCreated SystemTime="2026-07-14T09:12:31.4410000Z" />
    <Computer>WS-042.corp.example</Computer>
  </System>
  <EventData>
    <Data Name="SubjectUserSid">S-1-5-18</Data>
    <Data Name="SubjectUserName">WS-042$</Data>
    <Data Name="SubjectLogonId">0x3e7</Data>
    <Data Name="TargetUserName">jdoe</Data>
    <Data Name="TargetDomainName">CORP</Data>
    <Data Name="TargetLogonId">0x2d4f1a7</Data>
    <Data Name="LogonType">10</Data>
    <Data Name="LogonProcessName">User32</Data>
    <Data Name="AuthenticationPackageName">Negotiate</Data>
    <Data Name="WorkstationName">WS-042</Data>
    <Data Name="LmPackageName">-</Data>
    <Data Name="ProcessName">C:\Windows\System32\svchost.exe</Data>
    <Data Name="IpAddress">10.20.4.17</Data>
    <Data Name="IpPort">0</Data>
    <Data Name="ImpersonationLevel">%%1833</Data>
    <Data Name="RestrictedAdminMode">%%1843</Data>
    <Data Name="VirtualAccount">%%1843</Data>
    <Data Name="TargetLinkedLogonId">0x2d4f1c2</Data>
    <Data Name="ElevatedToken">%%1842</Data>
  </EventData>
</Event>

The %%nnnn values are message-table references that Event Viewer replaces with text. The ones that turn up in this event are %%1833 (Impersonation), %%1842 (Yes) and %%1843 (No). A parser that reads the raw XML has to map them, or a filter for ElevatedToken = "Yes" will match nothing.

The field list grew over time, so older logs and older forwarders may not carry everything above:

VersionIntroduced withFields added
0Windows Server 2008, VistaBase set
1Windows Server 2012, Windows 8ImpersonationLevel
2Windows 10, Server 2016RestrictedAdminMode, TargetOutboundUserName, TargetOutboundDomainName, VirtualAccount, TargetLinkedLogonId, ElevatedToken
  • TargetLogonId is the session’s identifier, a locally unique ID (LUID). It ties the logon to everything else the session did, and it is only unique on that computer and until reboot. Never join Logon IDs across hosts.
  • SubjectLogonId belongs to the account that reported the logon. Well-known values are fixed: 0x3e7 is SYSTEM, 0x3e4 NETWORK SERVICE, 0x3e5 LOCAL SERVICE and 0x3e6 ANONYMOUS LOGON.
  • TargetLinkedLogonId pairs two sessions. When User Account Control splits an administrator’s token, two logons are created and each names the other. With no paired session it is 0x0.
  • ElevatedToken says whether the session has full administrator privileges.
  • RestrictedAdminMode is only filled in for type 10 logons, and says whether RDP used Restricted Admin mode, in which credentials are not sent to the remote host.
  • LogonProcessName narrows the mechanism: User32 for interactive and RDP, NtLmSsp for NTLM network logons, Kerberos, Advapi for services and scheduled tasks, seclogo for secondary logon.
  • AuthenticationPackageName and LmPackageName: for NTLM logons the second field shows the protocol version. NTLM V1 on a modern network is a weakness worth reporting in its own right.
  • IpAddress and WorkstationName show where the logon came from. ::1 or 127.0.0.1 means the local machine.
Warning:

Source fields depend on the protocol. Microsoft’s reference notes that Kerberos network logons are likely to have no workstation name and NTLM logons no IP details. An empty or - field is not proof the logon was local.

A logon is the start of a story, and the Logon ID is the thread. On the same host:

EventWhat it addsJoin on
4624The logon itselfTargetLogonId
4672Special privileges assigned: the session is administrativeSubjectLogonId = the 4624 TargetLogonId
4688A process was created (needs process-creation auditing; command line needs a separate policy)SubjectLogonId
4648Explicit credentials were used, as with runas or a mapped drive with another accountSubjectLogonId
4634The session endedTargetLogonId
4647The user started the logoff (interactive and RDP)TargetLogonId

For RDP, the Microsoft-Windows-TerminalServices-LocalSessionManager/Operational log adds session events: 21 (session logon), 22 (shell start), 24 (disconnected) and 25 (reconnected), each with the source address. Security events 4778 and 4779 record reconnects and disconnects. Together they show sessions that were left disconnected for days and picked up again, which a 4624-only view misses.

Case note:

A common lateral-movement shape on the target host is a type 3 logon with an administrative account, a 4672 for the same Logon ID within the same second, then a service install (System log event 7045) whose image path points at a newly written binary. Each event is ordinary on its own; the sequence, inside a few seconds, is what deserves an explanation.

Event 4625 records a failed logon with the same field layout plus Status, SubStatus and FailureReason. Status is often the generic 0xC000006D, and the useful detail is in SubStatus:

CodeMeaning
0xC0000064User name does not exist
0xC000006AUser name is correct but the password is wrong
0xC000006DBad user name or authentication information (generic)
0xC000006FLogon outside authorized hours
0xC0000070Logon from an unauthorized workstation
0xC0000072Account disabled by an administrator
0xC0000193Account expired
0xC0000234Account locked out
0xC000015BThe user has not been granted the requested logon type (logon right) on this machine
0xC000005ENo logon servers available (usually infrastructure, not security)
0xC0000192The Netlogon service was not started
0xC0000413Blocked by an authentication firewall

Patterns worth knowing:

  • Password spraying: one source, many different TargetUserName values, a few attempts each, mostly 0xC000006A. 0xC0000064 in the mix shows the attacker is guessing names that do not exist.
  • Brute force: one account, many attempts, often ending in 0xC0000234.
  • A success after the failures from the same source is the event that matters. Always look for the 4624 that follows a 4625 burst.
Note:

For domain accounts, the domain controller records its own side: 4771 for Kerberos pre-authentication failures and 4776 for NTLM credential validation. A spray against Kerberos can leave almost nothing in 4625 on member servers and a great deal in 4771 on the DCs.

Get-WinEvent returns the rendered message, which is awkward to filter. Converting each event to XML gives named fields:

PowerShell
Get-WinEvent -FilterHashtable @{ LogName = 'Security'; Id = 4624 } -MaxEvents 5000 |
  ForEach-Object {
    $d = @{}
    ([xml]$_.ToXml()).Event.EventData.Data | ForEach-Object { $d[$_.Name] = $_.'#text' }
    [pscustomobject]@{
      Time      = $_.TimeCreated
      Type      = [int]$d.LogonType
      User      = "$($d.TargetDomainName)\$($d.TargetUserName)"
      LogonId   = $d.TargetLogonId
      Source    = $d.IpAddress
      Package   = $d.AuthenticationPackageName
      Elevated  = $d.ElevatedToken -eq '%%1842'
    }
  } |
  Where-Object { $_.Type -in 3, 10 -and $_.Source -notin '-', '::1', '127.0.0.1' } |
  Group-Object User, Source | Sort-Object Count -Descending | Select-Object Count, Name

To run the same over an exported .evtx file from an image, swap LogName = 'Security' for Path = 'D:\case\Security.evtx'.

wevtutil accepts XPath directly, including filters on named data fields. RDP logons, newest first:

Batch
wevtutil qe Security /rd:true /c:50 /f:text ^
  /q:"*[System[EventID=4624] and EventData[Data[@Name='LogonType']='10']]"

Add /lf:true and a file path in place of Security to query an exported log.

The SecurityEvent table exposes the fields as columns. A spray detector over 4625:

kql
SecurityEvent
| where EventID == 4625
| where SubStatus in~ ("0xc000006a", "0xc0000064")
| summarize Attempts = count(), Users = dcount(TargetUserName),
            FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated)
          by IpAddress, bin(TimeGenerated, 15m)
| where Users >= 10
| order by Users desc

Join the result back to 4624 on IpAddress to find any account that eventually succeeded. The thresholds depend on the environment, so tune them against a known-quiet week before relying on them.

  1. Counting logons as people. A single action, such as opening a share, can produce several type 3 events. Group by Logon ID and source before counting.
  2. Ignoring the computer the event came from. 4624 is written on the machine that was accessed. To follow lateral movement you need events from every host involved, plus the domain controllers’ authentication events for the same window.
  3. Reading the Subject as the user. The Subject block is the account that reported the logon, usually the computer itself (SYSTEM, 0x3e7). The account that logged on is under New Logon (Target*).
  4. Joining Logon IDs across hosts or reboots. They are only unique on one machine between restarts.
  5. Treating the absence of 4624 as absence of access. Audit policy decides what is written and logs roll over. Check the audit configuration (auditpol /get /category:* on a live host, or the policy in the image) and the log’s retained range before concluding anything from a gap.
Tip:

EventHawk has a built-in Logon/Logoff profile and a logon session browser that groups 4624 events by Logon ID and links the paired sessions of a split token.