In my previous post I outlined how to set up Sysmon with a basic configuration. If you had followed those steps you will now have many events in your Sysmon logs without a good way of:
1) Filtering out unwanted processes or network connections and
2) No way of working with the logs themselves.
In this post. I want to show you how to address these two areas.
Filtering Out Noisy Events:
After looking at your Sysmon events, you decide that monitoring UDP traffic provides you no value. This is simple to exclude via the configuration file. Here's the syntax:
<NetworkConnect onmatch="exclude">
<Protocol condition="is">udp</Protocol>
</NetworkConnect>
Anything within the onmatch="exclude" tag will be excluded.
You can also exclude a certain process. For example, if you have do not wish to see network connections made by Chrome:
<NetworkConnect onmatch="exclude">
<Image condition="end with">chrome.exe</Image>
</NetworkConnect>
By looking at an EventID 3 (Network Connection) you can see what to filter on more clearly:
If you wanted to filter on SourcePort, for example, you would do:
<NetworkConnect onmatch="exclude">
<SourcePort="is">53</SourcePort>
</NetworkConnect>
Putting it all together, excluding the protocol UDP, Port 53(TCP&UDP), and Chrome, your configuration entry would look like this:
<NetworkConnect onmatch="exclude">
<Image condition="end with">chrome.exe</Image>
<SourcePort condition="is">53</SourcePort>
<Protocol condition="is">udp</Protocol>
</NetworkConnect>
If you look carefully, you will some conditions have "end with" and some "is" - if the condition is a file path, feel free to use "end with" and just include the process name without the full path.
Likewise, if the condition you are trying to match on is just a protocol or port, without a path, feel free to use "is". You can also use "is" and include the full path of the process. In this example, our chrome rule would look like:
<Image condition="is">C:\Program Files\Chrome\chrome.exe</Image>
You can follow the same rule building logic for other events. For example, here is one for the FileCreate event. This way you can exclude certain processes from logging an event when they create a file.
<FileCreate onmatch="exclude">
<Image condition="end with">chrome.exe</Image>
</FileCreate>
Using the above example, Sysmon will not log an event when chrome creates a file. Of course, choosing when to include and exclude events and processes is entirely up to you. Sysmon can show you as much or as little detail as you would like.
One piece of configuration that I highly recommend leaving in your Sysmon configuration is ProcessAcces, monitoring lsass.exe and winlogon.exe
<ProcessAccess onmatch="include">
<TargetImage condition="is">C:\Windows\System32\lsass.exe</TargetImage>
<TargetImage condition="is">C:\Windows\System32\winlogon.exe</TargetImage>
</ProcessAccess>
This configuration will monitor for processes accessing lsass and winlogon - chief among these that you want to watch for as a defender is Mimikatz, which - among many other things - can dump credentials from within memory in clear text.
Some great resources for Mimikatz can be found here:
https://www.sans.org/reading-room/whitepapers/detection/mimikatz-overview-defenses-detection-36780
https://adsecurity.org/?page_id=1821 [you can probably spend months reading / absorbing the information on adsecurity - such a great resource]
https://twitter.com/gentilkiwi
A note: The idea to include these processes is not mine. Please see this Tweet from Microsoft's John Lambert -https://twitter.com/JohnLaTwC/status/802178985106911232
You may find that the above ProcessAccess configuration produces some noise. Keep an eye on these events and exclude benign process using:
<ProcessAccess onmatch="exclude">
<SourceImage condition="is">xxxx.exe</SourceImage>
</ProcessAccess>
If you are still confused about the Sysmon configuration, a really good and comprehensive configuration can be found via Florian Roth - https://twitter.com/cyb3rops/status/809044800980844548
Please look this configuration over before loading into your environment, as it may need tweaking. Also, please use a test workstation. Certain mistakes / syntax errors in your configuration will be caught by Sysmon, but others will Bluescreen your system.
Working With Event Data
Now that we have a working configuration file, we need a good way of extracting and parsing these events. This section will attempt to cover that. First, a few things of note.
The scripts and code for this, while slightly tweaked by me, were originally downloaded from: https://gist.github.com/RamblingCookieMonster/da272fee3b9a879bfee9
You will also need the Get-WinEventData PowerShell module, available from here: https://gallery.technet.microsoft.com/scriptcenter/Get-WinEventData-Extract-344ad840
What this module allows you do is grab the custom event data that Sysmon writes to the Event Log, it works with the built-in PowerShell cmdlet Get-WinEvent ( https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.diagnostics/get-winevent ).
Before we begin diving into PowerShell, I have to confess: I am not good at PowerShell. If you happen to be reading this as a developer or as someone who has spent a lot of time writing PowerShell, you may cringe at my code. I am not a developer by trade, but I do respect the profession. I can hack together and read code to fit my needs, but it isn't pretty - please keep that in mind and do not judge me too harshly :)
Let's look at a sample Event ID 1 - ProcessCreate:
We only want to parse out the events that are highlighted in red (CommandLine, CurrentDirectory, User and Hashes).
We can do this via the following code:
$EventsID1 = Get-WinEvent -FilterHashtable @{logname="Microsoft-Windows-Sysmon/Operational";id=1} | Get-WinEventData | select MachineName, TaskDisplayName, EventDataCommandLine, EventDataCurrentDirectory, EventDataHashes, EventDataUser
foreach ($Event1 in $EventsID1)
{
$output = Write-Output ( ('Sysmon_Event_1: ')+($Event1.TaskDisplayName )+ (' Machine Name:'+$Event1.MachineName )+ (' CMD:'+$Event1.EventDataCommandLine+" ")+ (' Dir: '+$Event1.EventDataCurrentDirectory )+ (' Hashes: '+$Event1.EventDataHashes )+ (' UserName: '+$Event1.EventdataUser ))
Add-Content $File -Value $output
}
What the hell is happening here, you may ask.
What we are doing is loading the Sysmon Event ID 1 events, and filtering by hashtable into the variable $EventsID1 [ $EventsID1 = Get-WinEvent -FilterHashtable @{logname="Microsoft-Windows-Sysmon/Operational";id=1} ].
We then pipe these events to the Get-WinEventData cmdlet, which lets us parse out the custom Sysmon fields we want, these types of events are prepended with 'EventData':
[ Get-WinEventData | select MachineName, TaskDisplayName, EventDataCommandLine, EventDataCurrentDirectory, EventDataHashes, EventDataUser ] The MachineName and TaskDisplayName are variables from the Get-WinEvent cmdlet.
Now that we have the Sysmon events we are interested in assigned to a variable, we loop through them, appending some text and outputting that content to a file:
[ $output = Write-Output ( ('Sysmon_Event_1: ')+($Event1.TaskDisplayName )+ (' Machine Name:'+$Event1.MachineName )+ (' CMD:'+$Event1.EventDataCommandLine+" ")+ (' Dir: '+$Event1.EventDataCurrentDirectory )+ (' Hashes: '+$Event1.EventDataHashes )+ (' UserName: '+$Event1.EventdataUser ))
Add-Content $File -Value $output ]
Here is a small sample script:
#This script grabs Sysmon windows event logs and extracts elements of these logs into a text file to be parsed further by the SIEM.
Clear
#This module is needed to access Windows Event Custom data.
Import-Module 'Get-WinEventData.ps1'
#Grab the name of the computer - used for naming of files only
$HostName = $env:COMPUTERNAME
#Sets the variable of the file name
$File = "C:\Sysmon\$HostName.txt"
#Series of for loops to grab the relevant information - the first part grabs the Sysmon events and the pipe to Get-WinEventData grabs the custom elements of the logs, each ID or Sysmon event type has its own custom element.
#This is for Event ID 1: Process creation
$EventsID1 = Get-WinEvent -FilterHashtable @{logname="Microsoft-Windows-Sysmon/Operational";id=1} | Get-WinEventData | select MachineName, TaskDisplayName, EventDataCommandLine, EventDataCurrentDirectory, EventDataHashes, EventDataUser
foreach ($Event1 in $EventsID1)
{
$output = Write-Output ( ('Sysmon_Event_1: ')+($Event1.TaskDisplayName )+ (' Machine Name:'+$Event1.MachineName )+ (' CMD:'+$Event1.EventDataCommandLine+" ")+ (' Dir: '+$Event1.EventDataCurrentDirectory )+ (' Hashes: '+$Event1.EventDataHashes )+ (' UserName: '+$Event1.EventdataUser ))
Add-Content $File -Value $output
}
And here is what this looks like written to a file (My PC and User names replaced with X's):
Sysmon_Event_1: Process Create (rule: ProcessCreate) Machine Name:XXXX CMD:"C:\WINDOWS\system32\WindowsPowerShell\v1.0\PowerShell_ISE.exe" Dir: C:\WINDOWS\system32\ Hashes: SHA1=1B26F9BCAC988CC3BE3633D56E7992C60291B9CB,MD5=3F06E220C3E591F458D549B01ECCCB95,SHA256=C2E227A3A9668D651C9F7AF5B27C4FC198F4D043D951E6EC100BEDC5497942F7,IMPHASH=00000000000000000000000000000000 UserName: XXXXXX
You can use the same logic for other Sysmon events, here is one for Event 2:
#This is for Event ID 2: A process changed a file creation time
$EventsID2 = Get-WinEvent -FilterHashtable @{logname="Microsoft-Windows-Sysmon/Operational";id=2} | Get-WinEventData | select MachineName, TaskDisplayName, EventDataImage, EventDataTargetFileName, EventDataCreationUtcTime
foreach ($Event2 in $EventsID2)
{
$output = Write-Output ( ('Sysmon_Event_2: ')+($Event2.TaskDisplayName )+ (' Machine Name:'+$Event2.MachineName )+ (' DataImage:'+$Event2.EventDataImage+" ")+ (' TargetFile: '+$Event2.EventDataTargetFileName )+ (' Time: '+$Event2.EventDataCreationUtcTime ))
Add-Content $File -Value $output
}
The only thing that changes is id=2 (for Event 2) and the EventData elements you want to grab.
You can use the basics of this script to pull Sysmon events from Systems and output them to a file for parsing by a SIEM or some other appliance. Those with more PowerShell-fu can probably do fancier things like loading these events in a database.
Carlos also has an excellent write-up on Sysmon here: http://www.darkoperator.com/blog/2014/8/8/sysinternals-sysmon
Wrap-Up
Hopefully by now you have the knowledge to deploy and configure Sysmon on your system or in an environment you manage. You also have several options for working with Sysmon data.
Please check out all the links I referenced, they were my stepping stones for figuring Sysmon out when I first got wind of its release. A guide like I tried to write in this and my previous blog post did not exist for me when I was attempting to set up Sysmon. Thanks to those I referenced in these posts, I was able to figure it out. That's it for now, until I think of something else useful to blog about.
1) Filtering out unwanted processes or network connections and
2) No way of working with the logs themselves.
In this post. I want to show you how to address these two areas.
Filtering Out Noisy Events:
After looking at your Sysmon events, you decide that monitoring UDP traffic provides you no value. This is simple to exclude via the configuration file. Here's the syntax:
<NetworkConnect onmatch="exclude">
<Protocol condition="is">udp</Protocol>
</NetworkConnect>
Anything within the onmatch="exclude" tag will be excluded.
You can also exclude a certain process. For example, if you have do not wish to see network connections made by Chrome:
<NetworkConnect onmatch="exclude">
<Image condition="end with">chrome.exe</Image>
</NetworkConnect>
By looking at an EventID 3 (Network Connection) you can see what to filter on more clearly:
If you wanted to filter on SourcePort, for example, you would do:
<NetworkConnect onmatch="exclude">
<SourcePort="is">53</SourcePort>
</NetworkConnect>
Putting it all together, excluding the protocol UDP, Port 53(TCP&UDP), and Chrome, your configuration entry would look like this:
<NetworkConnect onmatch="exclude">
<Image condition="end with">chrome.exe</Image>
<SourcePort condition="is">53</SourcePort>
<Protocol condition="is">udp</Protocol>
</NetworkConnect>
If you look carefully, you will some conditions have "end with" and some "is" - if the condition is a file path, feel free to use "end with" and just include the process name without the full path.
Likewise, if the condition you are trying to match on is just a protocol or port, without a path, feel free to use "is". You can also use "is" and include the full path of the process. In this example, our chrome rule would look like:
<Image condition="is">C:\Program Files\Chrome\chrome.exe</Image>
You can follow the same rule building logic for other events. For example, here is one for the FileCreate event. This way you can exclude certain processes from logging an event when they create a file.
<FileCreate onmatch="exclude">
<Image condition="end with">chrome.exe</Image>
</FileCreate>
Using the above example, Sysmon will not log an event when chrome creates a file. Of course, choosing when to include and exclude events and processes is entirely up to you. Sysmon can show you as much or as little detail as you would like.
One piece of configuration that I highly recommend leaving in your Sysmon configuration is ProcessAcces, monitoring lsass.exe and winlogon.exe
<ProcessAccess onmatch="include">
<TargetImage condition="is">C:\Windows\System32\lsass.exe</TargetImage>
<TargetImage condition="is">C:\Windows\System32\winlogon.exe</TargetImage>
</ProcessAccess>
This configuration will monitor for processes accessing lsass and winlogon - chief among these that you want to watch for as a defender is Mimikatz, which - among many other things - can dump credentials from within memory in clear text.
Some great resources for Mimikatz can be found here:
https://www.sans.org/reading-room/whitepapers/detection/mimikatz-overview-defenses-detection-36780
https://adsecurity.org/?page_id=1821 [you can probably spend months reading / absorbing the information on adsecurity - such a great resource]
https://twitter.com/gentilkiwi
A note: The idea to include these processes is not mine. Please see this Tweet from Microsoft's John Lambert -https://twitter.com/JohnLaTwC/status/802178985106911232
You may find that the above ProcessAccess configuration produces some noise. Keep an eye on these events and exclude benign process using:
<ProcessAccess onmatch="exclude">
<SourceImage condition="is">xxxx.exe</SourceImage>
</ProcessAccess>
If you are still confused about the Sysmon configuration, a really good and comprehensive configuration can be found via Florian Roth - https://twitter.com/cyb3rops/status/809044800980844548
Please look this configuration over before loading into your environment, as it may need tweaking. Also, please use a test workstation. Certain mistakes / syntax errors in your configuration will be caught by Sysmon, but others will Bluescreen your system.
Working With Event Data
Now that we have a working configuration file, we need a good way of extracting and parsing these events. This section will attempt to cover that. First, a few things of note.
The scripts and code for this, while slightly tweaked by me, were originally downloaded from: https://gist.github.com/RamblingCookieMonster/da272fee3b9a879bfee9
You will also need the Get-WinEventData PowerShell module, available from here: https://gallery.technet.microsoft.com/scriptcenter/Get-WinEventData-Extract-344ad840
What this module allows you do is grab the custom event data that Sysmon writes to the Event Log, it works with the built-in PowerShell cmdlet Get-WinEvent ( https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.diagnostics/get-winevent ).
Before we begin diving into PowerShell, I have to confess: I am not good at PowerShell. If you happen to be reading this as a developer or as someone who has spent a lot of time writing PowerShell, you may cringe at my code. I am not a developer by trade, but I do respect the profession. I can hack together and read code to fit my needs, but it isn't pretty - please keep that in mind and do not judge me too harshly :)
Let's look at a sample Event ID 1 - ProcessCreate:
We only want to parse out the events that are highlighted in red (CommandLine, CurrentDirectory, User and Hashes).
We can do this via the following code:
$EventsID1 = Get-WinEvent -FilterHashtable @{logname="Microsoft-Windows-Sysmon/Operational";id=1} | Get-WinEventData | select MachineName, TaskDisplayName, EventDataCommandLine, EventDataCurrentDirectory, EventDataHashes, EventDataUser
foreach ($Event1 in $EventsID1)
{
$output = Write-Output ( ('Sysmon_Event_1: ')+($Event1.TaskDisplayName )+ (' Machine Name:'+$Event1.MachineName )+ (' CMD:'+$Event1.EventDataCommandLine+" ")+ (' Dir: '+$Event1.EventDataCurrentDirectory )+ (' Hashes: '+$Event1.EventDataHashes )+ (' UserName: '+$Event1.EventdataUser ))
Add-Content $File -Value $output
}
What the hell is happening here, you may ask.
What we are doing is loading the Sysmon Event ID 1 events, and filtering by hashtable into the variable $EventsID1 [ $EventsID1 = Get-WinEvent -FilterHashtable @{logname="Microsoft-Windows-Sysmon/Operational";id=1} ].
We then pipe these events to the Get-WinEventData cmdlet, which lets us parse out the custom Sysmon fields we want, these types of events are prepended with 'EventData':
[ Get-WinEventData | select MachineName, TaskDisplayName, EventDataCommandLine, EventDataCurrentDirectory, EventDataHashes, EventDataUser ] The MachineName and TaskDisplayName are variables from the Get-WinEvent cmdlet.
Now that we have the Sysmon events we are interested in assigned to a variable, we loop through them, appending some text and outputting that content to a file:
[ $output = Write-Output ( ('Sysmon_Event_1: ')+($Event1.TaskDisplayName )+ (' Machine Name:'+$Event1.MachineName )+ (' CMD:'+$Event1.EventDataCommandLine+" ")+ (' Dir: '+$Event1.EventDataCurrentDirectory )+ (' Hashes: '+$Event1.EventDataHashes )+ (' UserName: '+$Event1.EventdataUser ))
Add-Content $File -Value $output ]
Here is a small sample script:
#This script grabs Sysmon windows event logs and extracts elements of these logs into a text file to be parsed further by the SIEM.
Clear
#This module is needed to access Windows Event Custom data.
Import-Module 'Get-WinEventData.ps1'
#Grab the name of the computer - used for naming of files only
$HostName = $env:COMPUTERNAME
#Sets the variable of the file name
$File = "C:\Sysmon\$HostName.txt"
#Series of for loops to grab the relevant information - the first part grabs the Sysmon events and the pipe to Get-WinEventData grabs the custom elements of the logs, each ID or Sysmon event type has its own custom element.
#This is for Event ID 1: Process creation
$EventsID1 = Get-WinEvent -FilterHashtable @{logname="Microsoft-Windows-Sysmon/Operational";id=1} | Get-WinEventData | select MachineName, TaskDisplayName, EventDataCommandLine, EventDataCurrentDirectory, EventDataHashes, EventDataUser
foreach ($Event1 in $EventsID1)
{
$output = Write-Output ( ('Sysmon_Event_1: ')+($Event1.TaskDisplayName )+ (' Machine Name:'+$Event1.MachineName )+ (' CMD:'+$Event1.EventDataCommandLine+" ")+ (' Dir: '+$Event1.EventDataCurrentDirectory )+ (' Hashes: '+$Event1.EventDataHashes )+ (' UserName: '+$Event1.EventdataUser ))
Add-Content $File -Value $output
}
And here is what this looks like written to a file (My PC and User names replaced with X's):
Sysmon_Event_1: Process Create (rule: ProcessCreate) Machine Name:XXXX CMD:"C:\WINDOWS\system32\WindowsPowerShell\v1.0\PowerShell_ISE.exe" Dir: C:\WINDOWS\system32\ Hashes: SHA1=1B26F9BCAC988CC3BE3633D56E7992C60291B9CB,MD5=3F06E220C3E591F458D549B01ECCCB95,SHA256=C2E227A3A9668D651C9F7AF5B27C4FC198F4D043D951E6EC100BEDC5497942F7,IMPHASH=00000000000000000000000000000000 UserName: XXXXXX
You can use the same logic for other Sysmon events, here is one for Event 2:
#This is for Event ID 2: A process changed a file creation time
$EventsID2 = Get-WinEvent -FilterHashtable @{logname="Microsoft-Windows-Sysmon/Operational";id=2} | Get-WinEventData | select MachineName, TaskDisplayName, EventDataImage, EventDataTargetFileName, EventDataCreationUtcTime
foreach ($Event2 in $EventsID2)
{
$output = Write-Output ( ('Sysmon_Event_2: ')+($Event2.TaskDisplayName )+ (' Machine Name:'+$Event2.MachineName )+ (' DataImage:'+$Event2.EventDataImage+" ")+ (' TargetFile: '+$Event2.EventDataTargetFileName )+ (' Time: '+$Event2.EventDataCreationUtcTime ))
Add-Content $File -Value $output
}
The only thing that changes is id=2 (for Event 2) and the EventData elements you want to grab.
You can use the basics of this script to pull Sysmon events from Systems and output them to a file for parsing by a SIEM or some other appliance. Those with more PowerShell-fu can probably do fancier things like loading these events in a database.
If this method of working with Sysmon Events does not fit your needs, be sure to check out Posh-Sysmon by Carlos Perez - https://www.powershellgallery.com/packages/Posh-Sysmon/0.7.3 Posh-Sysmon is designed to help you create Sysmon configuration files, but it also has a module for grabbing Sysmon events. The method above worked better for my needs, as I could prepend my own text to event data making it much easier to parse, but play with both methods and see what fills your needs.
Carlos also has an excellent write-up on Sysmon here: http://www.darkoperator.com/blog/2014/8/8/sysinternals-sysmon
Wrap-Up
Hopefully by now you have the knowledge to deploy and configure Sysmon on your system or in an environment you manage. You also have several options for working with Sysmon data.
Please check out all the links I referenced, they were my stepping stones for figuring Sysmon out when I first got wind of its release. A guide like I tried to write in this and my previous blog post did not exist for me when I was attempting to set up Sysmon. Thanks to those I referenced in these posts, I was able to figure it out. That's it for now, until I think of something else useful to blog about.