In part 1, we looked at the PowerShell command to work with the event log: Get-WinEvent. 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 Get-WinEvent 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 Get-WinEvent. 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.
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:
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 count:
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.
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:
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 TimeCreated 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.
Not all of these events will be malicious; you’ll need to understand what is normal in your environment. See my article on Threat Hunting with PowerShell Differential Analysis to quickly identify deviations from normal.
Get-WinEvent can filter using a severity level indicator, one of 6 numeric values:
If you only want to see logging information of a specific log level, add the Level attribute to the filter hash table:
NOTE: Critical events are only generated by the Windows system itself, such as a BSOD.
AppLocker uses event ID 8004 in the Microsoft-Windows-AppLocker/EXE and DLL 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:
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:
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 Microsoft-Windows-Bits-Client/Operational with event ID 59:
An attacker may modify the Windows Firewall settings to permit traffic for a specific program. This is recorded in the Microsoft-Windows-Windows Firewall With Advanced Security/Firewall log as event ID 2004 (event ID 2006 is a deleted firewall rule).
NOTE: The default rule name will be the executable description; here we see ApacheBench command line utility, the default for Metasploit Meterpreter.
Windows Defender quarantine events are recorded in Microsoft-Windows-Windows Defender/Operational. Look for anything where Data=’Severe’ as a hash table attribute:
The Microsoft-Windows-PowerShell/Operational 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.
Only the first invocation of the script is captured, to save logging storage space.
We can use Get-WinEvent 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:
[A-Za-z0-9+/=]{200}
Let’s break down this regular expression, step-by-step:
TIP: A great way to experiment with (and create) regular expressions is regex101.com, a site that lets you visually identify matches in sample data for a regular expression.
PowerShell supports matching with regular expressions using the Where-Object -Match parameter:
One useful query is to look for Security event log ID 4720, a user account was created:
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 Get-WinEvent returns a property UserId, it is almost always blank. The username information is populated in the Message property. You could use the PowerShell pipeline to search for the string assetmgr anywhere in the Message property, but that’s going to be slow. Fortunately there is a better option: -FilterXPath.
The Get-WinEvent -FilterXPath 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 -FilterXPath to search for other event logs where the username is assetmgr:
In this article we looked at 10 techniques for threat hunting with Windows event logs and PowerShell’s Get-WinEvent 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.