Security tips / Digital Forensics / Windows

Windows Event Logs: 10 Event IDs That Reveal an Intruder

Here is a fact that surprises most people: on a typical breach, the evidence was sitting in the Windows event log the whole time. Logons, new accounts, new services, cleared logs. Windows records it all. The attacker is counting on nobody reading it.

This post gives you the ten event IDs worth knowing by heart, what a suspicious one looks like, and a one-liner to pull each from PowerShell.

Before you start

  • Open Event Viewer (press the Windows key, type Event Viewer) or an elevated PowerShell window.
  • Most of these live in the Security log. One lives in System and one in the PowerShell operational log. I say which.
  • Some events only appear if auditing is switched on. The Auditing you need section near the end shows the settings.
  • Only review logs on machines you are authorized to administer.

1. Event ID 4624: successful logon

The most important event in the log. Every time someone (or something) logs on, you get one of these, including a Logon Type that tells you how.

Logon type Meaning Worth attention?
2 Interactive, at the keyboard Normal for users
3 Network: file shares, remote admin tools Yes, if from unexpected sources
5 Service start Normal
7 Screen unlock Normal
10 Remote Desktop Yes, always review
11 Cached credentials, offline Normal for laptops
Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4624} -MaxEvents 300 |
  Where-Object { $_.Properties[8].Value -in 3,10 } |
  Select-Object TimeCreated, @{n="User";e={$_.Properties[5].Value}}, @{n="Type";e={$_.Properties[8].Value}}, @{n="FromIP";e={$_.Properties[18].Value}}

Suspicious when: type 10 at odd hours, type 3 from an address outside your network, or a service account logging on interactively.

2. Event ID 4625: failed logon

A password was wrong, an account was locked, or a username did not exist. A handful is life. A thousand in an hour is a brute-force attack.

Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4625} -MaxEvents 1000 |
  Group-Object { $_.Properties[5].Value } | Sort-Object Count -Descending | Select-Object Count, Name -First 10

Suspicious when: many failures against one account, failures against many accounts from one source (password spraying), or failures for accounts that do not exist on this machine.

3. Event ID 4648: logon with explicit credentials

Someone ran something as a different user, such as runas, or connected to another machine with alternate credentials. Normal for admins. Also exactly what lateral movement looks like.

Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4648} -MaxEvents 100 |
  Select-Object TimeCreated, @{n="By";e={$_.Properties[1].Value}}, @{n="As";e={$_.Properties[5].Value}}, @{n="Target";e={$_.Properties[8].Value}}

Suspicious when: a regular user account is using admin credentials, or one workstation is reaching out to many others.

4. Event ID 4672: special privileges assigned

Logged when an account with admin-level rights logs on. Expect it for your admins. Do not expect it for anyone else.

Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4672} -MaxEvents 100 |
  Select-Object TimeCreated, @{n="User";e={$_.Properties[1].Value}} | Group-Object User | Select-Object Count, Name

Suspicious when: a name appears that is not on your admin list.

5. Event ID 4688: a new process was created

Every program start, with the parent process and (if enabled) the full command line. This is the single richest source of evidence on a Windows machine. It is off by default. Turn it on today (see Auditing you need below).

Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4688} -MaxEvents 200 |
  Select-Object TimeCreated, @{n="Process";e={$_.Properties[5].Value}}, @{n="Parent";e={$_.Properties[13].Value}}, @{n="CmdLine";e={$_.Properties[8].Value}}

Suspicious when: Office programs (Word, Excel, Outlook) spawning powershell.exe or cmd.exe, encoded PowerShell commands (-enc, -EncodedCommand), or anything running from Temp, AppData or Downloads.

6. Event ID 4698: scheduled task created

Scheduled tasks are a top persistence method. This event shows who created a task and the full task definition, including the command it runs.

Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4698} -MaxEvents 50 |
  Select-Object TimeCreated, @{n="By";e={$_.Properties[1].Value}}, @{n="Task";e={$_.Properties[4].Value}}

Suspicious when: created by a non-admin, named to look like system maintenance, or pointing at a script in a user folder.

7. Event ID 4720: user account created

A new local or domain account. Attackers create accounts so they can come back after you reset the one they stole.

Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4720} -MaxEvents 50 |
  Select-Object TimeCreated, @{n="NewAccount";e={$_.Properties[0].Value}}, @{n="CreatedBy";e={$_.Properties[4].Value}}

Suspicious when: you did not create it. Pair with 4722 (enabled), 4724 (password reset) and 4726 (deleted) to see the whole story.

8. Event ID 4732: member added to a local group

Specifically, security-enabled local groups like Administrators and Remote Desktop Users. The domain equivalents are 4728 (global group) and 4756 (universal group).

Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4732,4728,4756} -MaxEvents 50 |
  Select-Object TimeCreated, Id, @{n="Group";e={$_.Properties[2].Value}}, @{n="By";e={$_.Properties[6].Value}}

Suspicious when: anyone is added to Administrators outside a change window.

9. Event ID 7045: a new service was installed (System log)

Services run as SYSTEM, start at boot and need no user. Tools like PsExec and many malware families install one. Note this lives in the System log, not Security.

Get-WinEvent -FilterHashtable @{LogName="System"; Id=7045} -MaxEvents 50 |
  Select-Object TimeCreated, @{n="Service";e={$_.Properties[0].Value}}, @{n="Path";e={$_.Properties[1].Value}}, @{n="Account";e={$_.Properties[4].Value}}

Suspicious when: the path is outside C:\Windows or C:\Program Files, the name is random letters, or the service appeared right after an unexplained logon.

10. Event ID 1102: the audit log was cleared

The one event an attacker cannot avoid creating when they try to cover their tracks. Clearing the Security log writes this as the very first entry in the new, empty log, with the account that did it.

Get-WinEvent -FilterHashtable @{LogName="Security"; Id=1102} -ErrorAction SilentlyContinue |
  Select-Object TimeCreated, @{n="ClearedBy";e={$_.Properties[1].Value}}

Suspicious when: always. There is almost no legitimate reason to clear the Security log on a production machine.

Bonus: Event ID 4104, PowerShell script block logging

In the Microsoft-Windows-PowerShell/Operational log. When enabled, Windows records the actual content of every script that runs, even if it was obfuscated or encoded. Attackers hate this one.

Get-WinEvent -FilterHashtable @{LogName="Microsoft-Windows-PowerShell/Operational"; Id=4104} -MaxEvents 50 |
  Select-Object TimeCreated, @{n="Script";e={$_.Message.Substring(0,[Math]::Min(200,$_.Message.Length))}}

Auditing you need

Several of these are silent unless the policy is on. Open Local Security Policy (or your domain GPO) and go to Advanced Audit Policy Configuration:

Event Policy to enable
4624, 4625, 4648 Logon/Logoff → Audit Logon (Success and Failure)
4672 Logon/Logoff → Audit Special Logon
4688 Detailed Tracking → Audit Process Creation. Also enable Include command line in process creation events under Administrative Templates → System → Audit Process Creation
4698 Object Access → Audit Other Object Access Events
4720, 4732 Account Management → Audit User Account Management and Audit Security Group Management
4104 Administrative Templates → Windows Components → Windows PowerShell → Turn on Script Block Logging

Also raise the Security log size. The default is small and rolls over in hours on a busy server. 1 GB is a reasonable floor.

Common mistakes

  • Logs only on the machine. If the attacker clears them, they are gone. Forward logs to a central server or SIEM.
  • Alerting on 4625 alone. Failed logons are noisy. The real signal is a run of 4625s followed by a 4624 of type 3 or 10.
  • Never enabling 4688 with command line. Without it, you know a process started but not what it was told to do.
  • Ignoring the System log. 7045 lives there and it catches a great deal.

FAQ

How far back do the logs go?

As far as the log size allows. Check with Get-WinEvent -ListLog Security and look at MaximumSizeInBytes. Increase it.

Can I search all machines at once?

With PowerShell Remoting, yes: Invoke-Command -ComputerName (Get-Content servers.txt) -ScriptBlock { ... }. For anything beyond a few dozen machines, you want a SIEM.

Is Sysmon better?

Sysmon (free, from Microsoft Sysinternals) adds much more detail: network connections per process, file hashes, DNS queries. The built-in events above are where to start because they are already there.

Final thoughts

You do not need a six-figure security platform to catch an intruder. You need the logs switched on, kept long enough, and read by someone who knows these ten numbers. Print the quick reference, pin it next to your monitor, and run the queries once a week until they are reflex.

Useful resources

Know the attack. Own the defense.

Tagged:WindowsEvent logsIncident responseBlue teamPowerShell

Need this done for your organization?

I run security and compliance programs for a living. I can review, set up, or train your team.

Work with me →