Essential Windows Event IDs for Security Monitoring: The Complete Guide

Every defender eventually needs a working knowledge of Windows Event IDs for security monitoring. There are thousands of them, but a much smaller core actually drives detection. This post is the reference we hand to new analysts on the team: the events that matter, what each is for, the audit policy needed to produce them, and PowerShell queries to pull them on demand. The list is curated for defenders, not exhaustive — use it as a working baseline and extend per environment.

Key Takeaways

  • The high-value detection IDs cluster into five groups: authentication, account management, Active Directory changes, process and PowerShell execution, and policy or audit changes.
  • None of them appear without the right audit policy. Configure Advanced Audit Policy via Group Policy before assuming the events are missing.
  • Default log sizes are too small for security monitoring on Domain Controllers. Size Security to 4 GB and PowerShell/Operational to 1 GB at minimum.
  • Use Get-WinEvent -FilterHashtable for ad-hoc queries; centralise via Windows Event Forwarding or a SIEM for retention and correlation.
  • Pair every event with the MITRE ATT&CK technique it helps detect. Coverage gaps are easier to spot when alerts are technique-tagged.

Environment

  • Windows 10/11 endpoints and Windows Server 2019/2022 (Domain Controllers and member servers).
  • Active Directory domain with Advanced Audit Policy applied via Group Policy.
  • PowerShell 5.1 or PowerShell 7.4 for queries.
  • Optional: Sysmon for richer process and network telemetry, plus a SIEM (Sentinel, Splunk, Elastic, QRadar) for retention and correlation.

The Problem

Event Viewer is fine for a single host but useless for a fleet. The two recurring problems are missing events (audit policy not configured, log full and overwriting) and overwhelmed analysts (every event has equal weight in the GUI, even though 4624 dwarfs every other event ID in volume). The fix is the same in both cases: know which event IDs actually carry signal, configure audit policy and log size to capture them, and standardise the queries you reach for first.

The Solution

Step 1 — Configure audit policy and log size

Without Advanced Audit Policy, half the events in this list never fire. Apply via GPO under Computer Configuration → Windows Settings → Security Settings → Advanced Audit Policy Configuration. The minimum categories to enable with both Success and Failure:

  • Account Logon
  • Account Management
  • Detailed Tracking
  • DS Access
  • Logon/Logoff
  • Object Access
  • Policy Change
  • Privilege Use
  • System
# Verify what is configured locally
auditpol /get /category:*

# Size critical logs
wevtutil sl Security                                    /ms:4294967296
wevtutil sl Application                                 /ms:1073741824
wevtutil sl System                                      /ms:1073741824
wevtutil sl 'Microsoft-Windows-PowerShell/Operational'  /ms:1073741824

Roll the same configuration out via Group Policy preferences or your provisioning tool so every server inherits the same baseline.

Step 2 — Authentication events (Logon/Logoff)

The six most useful authentication event IDs:

  • 4624 — Successful logon. LogonType matters: 2 (interactive), 3 (network), 10 (RemoteInteractive/RDP).
  • 4625 — Failed logon. Status and SubStatus codes explain why.
  • 4634 — Logoff (matched to a 4624 logon ID).
  • 4647 — User-initiated logoff.
  • 4648 — Explicit credential use (RunAs, scheduled task with stored credentials, lateral movement primitive).
  • 4672 — Special privileges assigned at logon (administrator session indicator).
# Failed logons in the last hour, grouped by user and source IP
Get-WinEvent -FilterHashtable @{
    LogName = 'Security'; Id = 4625; StartTime = (Get-Date).AddHours(-1)
} -ErrorAction SilentlyContinue |
    Select-Object TimeCreated,
                  @{Name='User';     Expression={ $_.Properties[5].Value }},
                  @{Name='SourceIP'; Expression={ $_.Properties[19].Value }},
                  @{Name='Status';   Expression={ '{0:X}' -f $_.Properties[7].Value }} |
    Group-Object User, SourceIP |
    Where-Object Count -gt 10 |
    Sort-Object Count -Descending

Step 3 — Account management events

Anything that changes a user, group, or computer object in AD generates one of these:

  • 4720 — User account created.
  • 4722 — User account enabled.
  • 4723 — User attempted to change their password.
  • 4724 — Administrator reset a user's password.
  • 4726 — User account deleted.
  • 4728 / 4732 / 4756 — Member added to global, local, or universal group.
  • 4738 — User account changed.
  • 4741 / 4742 / 4743 — Computer account created, changed, deleted.

A 4732 adding a non-admin into the local Administrators group is a high-fidelity signal. Same for any 4728 against Domain Admins, Enterprise Admins, or Schema Admins.

Step 4 — Active Directory object changes

The 51xx range covers directory-service changes. These are noisy by default and need to be filtered to specific object classes:

  • 4662 — Operation performed on an AD object (the DCSync indicator).
  • 5136 — Directory service object modified.
  • 5137 — Directory service object created.
  • 5138 — Directory service object undeleted.
  • 5139 — Directory service object moved.
  • 5141 — Directory service object deleted.
$sensitive = 'CN=Domain Admins','CN=Enterprise Admins','CN=Schema Admins'

Get-WinEvent -FilterHashtable @{
    LogName = 'Security'; Id = 5136, 5137, 5141; StartTime = (Get-Date).AddDays(-7)
} -ErrorAction SilentlyContinue |
    Where-Object {
        $dn = $_.Properties[5].Value
        $sensitive | ForEach-Object { if ($dn -like "*$_*") { return $true } }
    } |
    Select-Object TimeCreated, Id,
                  @{Name='Object'; Expression={ $_.Properties[5].Value }},
                  @{Name='Actor';  Expression={ $_.Properties[1].Value }}

Step 5 — Process and PowerShell execution

These are the foundation for execution-style detections:

  • 4688 — Process creation. Enable Audit Process Creation and the Include command line setting under Detailed Tracking.
  • 4689 — Process termination.
  • 4103 — PowerShell module logging (parameters and module calls).
  • 4104PowerShell script block logging (deobfuscated script source). This is the gold standard for catching encoded payloads.
  • 4105 / 4106 — PowerShell pipeline execution started/stopped.
# Enable script block logging via registry (also configurable in GPO)
$path = 'HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging'
New-Item -Path $path -Force | Out-Null
Set-ItemProperty -Path $path -Name EnableScriptBlockLogging -Value 1

# Hunt 4104 events containing classic loader strings
Get-WinEvent -FilterHashtable @{
    LogName = 'Microsoft-Windows-PowerShell/Operational'; Id = 4104; StartTime = (Get-Date).AddDays(-1)
} -ErrorAction SilentlyContinue |
    Where-Object { $_.Message -match '(-enc|frombase64string|downloadstring|invoke-expression)' } |
    Select-Object TimeCreated,
                  @{Name='User';   Expression={ $_.UserId }},
                  @{Name='Block';  Expression={ ($_.Message -split "`n")[0..2] -join ' / ' }}

Step 6 — Object access (files, registry, scheduled tasks)

Object Access auditing is what makes the 46xx range fire. Once enabled, you get visibility into file, registry, and task changes:

  • 4657 — Registry value modified.
  • 4663 — Object accessed.
  • 4698 — Scheduled task created.
  • 4699 — Scheduled task deleted.
  • 4702 — Scheduled task updated.
  • 5140 / 5145 — Network share accessed; detailed share access.
  • 1102 — Audit log was cleared. Generates regardless of policy. Treat as a high-fidelity alert.

Step 7 — Policy and audit changes

Watch for an attacker turning off the very auditing you are relying on:

  • 4713 — Kerberos policy changed.
  • 4717 / 4718 — System security access granted/removed.
  • 4719 — System audit policy changed.
  • 4739 — Domain policy changed.
  • 4907 — Auditing settings on object were changed.
  • 4912 — Per-user audit policy changed.

Step 8 — Application control (AppLocker / WDAC)

If you run AppLocker or Windows Defender Application Control, the corresponding deny/allow events are highest-value detections:

  • 3001 — AppLocker policy applied.
  • 8002 — Executable/DLL was allowed by policy.
  • 8003 — Executable/DLL was denied by policy.
  • 8004 — Script/MSI was allowed by policy.
  • 8005 — Script/MSI was denied by policy.

Step 9 — Map events to MITRE ATT&CK and common attack patterns

A few patterns are worth pinning to a cheat sheet:

  • Kerberoasting (T1558.003) — bursts of 4769 with RC4-HMAC ticket encryption from a single user against multiple SPNs.
  • DCSync (T1003.006) — 4662 with GUID {1131f6aa-9c07-11d1-f79f-00c04fc2dcd2} ("DS-Replication-Get-Changes-All") from a non-DC principal.
  • Living-off-the-land (T1218) — 4688 with command-line for certutil -urlcache, bitsadmin /transfer, mshta, regsvr32 /s /i.
  • Privilege escalation (T1078) — 4672 immediately followed by 7045 (new service) or 4698 (new scheduled task) for the same user.
  • Audit tampering (T1562.002) — 1102 (audit cleared) or 4719 (audit policy changed) outside of approved change windows.

Frequently Asked Questions

Why are some of these event IDs not firing on my domain controllers?

Almost always because the matching Advanced Audit Policy subcategory is disabled. Verify with auditpol /get /category:* on the DC itself, then push the policy via GPO. Local audit settings can be overridden by GPO at the next refresh, so changing them with auditpol alone is temporary.

What is the relationship between Event ID 4624 LogonType values?

LogonType is in the event payload and tells you how the logon happened. The values that matter for detection are 2 (interactive console), 3 (network — most common), 4 (batch — scheduled task), 5 (service), 7 (unlock), 8 (network plaintext), 10 (RemoteInteractive — RDP), and 11 (cached credential).

Why does my Security log fill up so fast on a DC?

4624 and 4634 dominate volume on a busy DC, often thousands per minute. The fix is either a larger log (4 GB minimum) with rotation, central forwarding so the local log only buffers a short window, or both. Trying to retain a week of DC security events locally rarely works.

Are PowerShell 4104 events still useful if attackers use obfuscation?

Yes. Script block logging captures the deobfuscated text after PowerShell's parser has resolved encoded commands, so the malicious content is visible in plaintext even when the operator passed -EncodedCommand. Obfuscation that survives the parser (string concatenation, variable renaming) still leaves recognisable behavioural primitives like DownloadString.

What is Event ID 1102 and why is it special?

1102 fires whenever the Security log is cleared — by definition, after every other event in the log has been erased. It is one of the very few events that fires regardless of audit policy and survives clearing. Alert on it immediately and unconditionally.

Conclusion

The core list of Windows event IDs for security monitoring is shorter than the documentation suggests — five categories, maybe forty IDs, cover the vast majority of detection use cases. Configure the audit policy that produces them, size the logs to hold a useful window, and standardise the queries you reach for first. Pair the events with MITRE ATT&CK techniques and you have the foundation a SIEM correlation layer needs to do real work.

Related Posts

Authoritative reference: Advanced Security Audit Policy Settings on Microsoft Learn.

0 comments:

Post a Comment