sysmonlinux.util.psm1
function Get-SysmonLinuxEvent { <# .SYNOPSIS Gets one or more Sysmon for Linux event types from Syslog logs. .DESCRIPTION Gets one or more Sysmon for Linux event types from Syslog logs. Allows for filtering by ProcessGUID and User. .EXAMPLE PS /> Get-SysmonLinuxEvent -EventType Any -ProcessGuid "{de9527a5-6a3f-616f-a52f-d98154560000}" EventId : 1 Version : 5 EventType : ProcessCreate Computer : ubuntu EventRecordID : 35705 RuleName : - UtcTime : 2021-10-20 01:00:47.600 ProcessGuid : {de9527a5-6a3f-616f-a52f-d98154560000} ProcessId : 2356 Image : /usr/sbin/dumpe2fs FileVersion : - Description : - Product : - Company : - OriginalFileName : - CommandLine : dumpe2fs -h /dev/sda5 CurrentDirectory : / User : root LogonGuid : {de9527a5-0000-0000-0000-000000000000} LogonId : 0 TerminalSessionId : 4294967295 IntegrityLevel : no level Hashes : - ParentProcessGuid : {00000000-0000-0000-0000-000000000000} ParentProcessId : 874 ParentImage : - ParentCommandLine : - ParentUser : - EventId : 9 Version : 2 EventType : RawAccessRead Computer : ubuntu EventRecordID : 35706 RuleName : - UtcTime : 2021-10-20 01:00:47.619 ProcessGuid : {de9527a5-6a3f-616f-a52f-d98154560000} ProcessId : 2356 Image : /usr/sbin/dumpe2fs Device : /dev/sda5 User : root EventId : 5 Version : 3 EventType : ProcessTerminate Computer : ubuntu EventRecordID : 35707 RuleName : - UtcTime : 2021-10-20 01:00:47.620 ProcessGuid : {de9527a5-6a3f-616f-a52f-d98154560000} ProcessId : 2356 Image : /usr/sbin/dumpe2fs User : root Find all events that match the specified ProcessGuid. .INPUTS System.IO.FileInfo .OUTPUTS System.Management.Automation.PSCustomObject .NOTES General notes #> [CmdletBinding(DefaultParameterSetName="All")] param ( # Event type to pull from Syslog log file. [Parameter(Mandatory=$True)] [ValidateSet("Any","ProcessCreate","ProcessTerminate","NetworkConnect", "SysmonState","RawAccessRead","FileCreate","ConfigChange","FileDelete")] [string[]] $EventType, # Specifies a path to one or more locations. [Parameter( Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage="Path to one or more locations.")] [Alias("PSPath")] [ValidateNotNullOrEmpty()] [ValidateScript({Test-Path $_})] [string[]] $SyslogFile = @("/var/log/syslog"), # ProcessGuid to search for a given event type, ParentProcessGuid will also be matched to this value. [Parameter(Mandatory=$false, ParameterSetName="Guid")] [string[]] $ProcessGuid, # Image to search for a given event type.The '*' wildcard is supported for matching. [Parameter(mandatory=$false)] [SupportsWildcards()] [string[]] $Image, # User to seach for a given event type. [Parameter(Mandatory=$false)] [string[]] $User ) begin { $EventTypetoId = @{ 'ProcessCreate' = '1' 'NetworkConnect' = '3' 'SysmonState' = '4' 'ProcessTerminate' = '5' 'RawAccessRead' = '9' 'FileCreate' = '11' 'FileDelete' = '23' 'ConfigChange' = '16' 'Any' = @('1','3','4','5','9','11','23','16') } $EventIdtoType = @{ '1' = 'ProcessCreate' '2' = 'FileCreateTime' '3' = 'NetworkConnect' '4' = 'StateChange' '5' = 'ProcessTerminate' '9' = 'RawAccessRead' '11' = 'FileCreate' '16' = 'ConfigChange' '23' = 'FileDelete' } # Create EventType pattern. $eventToQ = @() foreach ($etype in $EventType) { $eventToQ += $EventTypetoId[$etype] } $eventids = $eventToQ -join "|" write-verbose -message "Searching for events $($eventids)" $pattern = "^*sysmon:.*<EventID>($($eventids))<\/EventID>" if ($ProcessGuid.Length -gt 0){ $pattern = $pattern + ".*<Data Name=`"(ProcessGuid|ParentProcessGuid)`">($($ProcessGuid -join "|"))<\/Data>" } if ($Image.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"Image`">($(($Image -join "|").Replace("`*",".`*")))<\/Data>" } if ($User.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"User`">($($User))<\/Data>" } write-verbose -Message "RegEx is $pattern" } process { if ($SyslogFile -like "*.gz") { $file2process = Expand-GzFile (resolve-path $SyslogFile).Path } else { $file2process = $SyslogFile } Write-Verbose -Message "Opening $($file2process)" Select-String -Pattern $pattern -Path $file2process | ForEach-Object { $evtxml = [xml]($_.line.split("sysmon:"))[1] $EvtInfo = [ordered]@{} $EvtInfo['EventId'] = $evtxml.Event.System.EventID $EvtInfo['Version'] = $evtxml.Event.System.Version $EvtInfo['EventType'] = "$($EventIdtoType[$([string]$evtxml.Event.System.EventID)] )" $EvtInfo['Computer'] = $evtxml.Event.System.Computer $EvtInfo['EventRecordID'] = $evtxml.Event.System.EventRecordID $evtxml.event.eventdata.data | ForEach-Object { $EvtInfo[$_.name] = $_.'#text' } $Obj = New-Object psobject -Property $EvtInfo $Obj.pstypenames[0] = "Sysmon.EventRecord.$($EventIdtoType[$([string]$evtxml.Event.System.EventID)] )" $Obj } } end { } } function Get-SysmonLinuxProcessCreate { <# .SYNOPSIS Gets Sysmon process creation events from Syslog logs. .DESCRIPTION Gets Sysmon Process creation events from Syslog logs.It allows filtering by field content. .EXAMPLE PS /> ls syslog* | Get-SysmonLinuxProcessCreate -Image */ping,*/whoami,*/id EventId : 1 Version : 5 EventType : ProcessCreate Computer : ubuntu EventRecordID : 7468 RuleName : - UtcTime : 2021-10-16 04:51:15.156 ProcessGuid : {de9527a5-5a43-616a-312b-c11c7a550000} ProcessId : 8455 Image : /usr/bin/ping FileVersion : - Description : - Product : - Company : - OriginalFileName : - CommandLine : ping 8.8.8.8 -c 2 CurrentDirectory : /home/carlos/Desktop User : carlos LogonGuid : {de9527a5-0000-0000-e803-000001000000} LogonId : 1000 TerminalSessionId : 3 IntegrityLevel : no level Hashes : - ParentProcessGuid : {de9527a5-5a43-616a-f537-ea5ba5550000} ParentProcessId : 8454 ParentImage : /usr/bin/dash ParentCommandLine : /usr/bin/sh ParentUser : carlos EventId : 1 Version : 5 EventType : ProcessCreate Computer : ubuntu EventRecordID : 452 RuleName : - UtcTime : 2021-10-16 00:45:59.711 ProcessGuid : {de9527a5-20c7-616a-e171-bdc707560000} ProcessId : 1740 Image : /usr/bin/id FileVersion : - Description : - Product : - Company : - OriginalFileName : - CommandLine : id -un CurrentDirectory : /home/carlos User : carlos LogonGuid : {de9527a5-0000-0000-e803-000001000000} LogonId : 1000 TerminalSessionId : 2 IntegrityLevel : no level Hashes : - ParentProcessGuid : {de9527a5-20c7-616a-0507-b18881550000} ParentProcessId : 1726 ParentImage : /usr/bin/bash ParentCommandLine : /bin/bash ParentUser : carlos Find across multiple syslog files events that match the images specified using wildcards. .INPUTS System.IO.FileInfo .OUTPUTS System.Management.Automation.PSCustomObject .NOTES General notes #> [CmdletBinding(DefaultParameterSetName="All")] param ( # Specifies a path to one or more locations. [Parameter( Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage="Path to one or more locations.")] [Alias("PSPath")] [ValidateNotNullOrEmpty()] [ValidateScript({Test-Path $_})] [string[]] $SyslogFile = @("/var/log/syslog"), # ProcessGuid to search for, one or more can be provided. [Parameter(Mandatory=$false, ParameterSetName="ProcessGuid")] [string[]] $ProcessGuid, # RuleName to search for the given event type. #[Parameter(mandatory=$false)] #[string] #$RuleName, # ProcessID to search for, one or more can be provided. [Parameter(Mandatory=$false)] [string[]] $ProcessId, # ProcessGuid to search for, one or more can be provided.. [Parameter(Mandatory=$false)] [string[]] $ParentProcessGuid, # Logon to search for , one or more can be provided. [Parameter(Mandatory=$false, ParameterSetName="LogonGuid")] [string[]] $LogonGuid, # LogonId to search for , one or more can be provided. [Parameter(Mandatory=$false)] [string[]] $LogonId, # Image to search for this event type.The '*' wildcard is supported for matching. [Parameter(mandatory=$false)] [SupportsWildcards()] [string[]] $Image, # CommandLine to search for this event type.The '*' wildcard is supported for matching. [Parameter(mandatory=$false)] [SupportsWildcards()] [string[]] $CommandLine, # CurrentDirectory to search for a given event type. [Parameter(mandatory=$false)] [string[]] $CurrentDirectory, # User to seach for, one or more can be provided. [Parameter(Mandatory=$false)] [string[]] $User, # ParentImage to search for, one or more can be provided. [Parameter(mandatory=$false)] [SupportsWildcards()] [string[]] $ParentImage, # ParentProcessId to search for, one or more can be provided. [Parameter(mandatory=$false)] [string[]] $ParentProcessId, # ParentCommandLine to search for this event type.The '*' wildcard is supported for matching. [Parameter(mandatory=$false)] [SupportsWildcards()] [string[]] $ParentCommandLine, # TerminalSessionId to search for, one or more can be provided. [Parameter(mandatory=$false)] [string[]] $TerminalSessionId, # ParentUser to seach for, one or more can be provided. [Parameter(Mandatory=$false)] [string[]] $ParentUser, # Start Time to search for event created on and after this time. [Parameter(Mandatory=$false)] [datetime] $StartTime, # End Time to search for event created on and after this time. [Parameter(Mandatory=$false)] [datetime] $EndTime ) begin { $pattern = "^*sysmon:.*<EventID>1<\/EventID>" if ($RuleName.Length -gt 0){ $pattern = $pattern + ".*<Data Name=`"RuleName`">($($RuleName))<\/Data>" } if ($ProcessGuid.Length -gt 0){ $pattern = $pattern + ".*<Data Name=`"ProcessGuid`">($($ProcessGuid -join "|"))<\/Data>" } if ($ProcessId.Length -gt 0){ $pattern = $pattern + ".*<Data Name=`"(ProcessId)`">($($ProcessId -join "|"))<\/Data>" } if ($Image.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"Image`">($(($Image -join "|").Replace("`*",".`*")))<\/Data>" } if ($CommandLine.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"CommandLine`">($(($CommandLine -join "|").Replace("`*",".`*")))<\/Data>" } if ($CurrentDirectory.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"CurrentDirectory`">($($CurrentDirectory -join "|"))<\/Data>" } if ($User.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"User`">($($User -join "|"))<\/Data>" } if ($LogonGuid.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"LogonGuid`">($($LogonGuid -join "|"))<\/Data>" } if ($LogonId.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"LogonId`">($($LogonId -join "|"))<\/Data>" } if ($TerminalSessionId.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"TerminalSessionId`">($($TerminalSessionId -join "|"))<\/Data>" } if ($ParentProcessGuid.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"ParentProcessGuid`">($($ParentProcessGuid -join "|"))<\/Data>" } if ($ParentProcessId.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"ParentProcessId`">($($ParentProcessId -join "|"))<\/Data>" } if ($ParentImage.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"ParentImage`">($(($ParentImage -join "|").Replace("`*",".`*")))<\/Data>" } if ($ParentCommandLine.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"ParentCommandLine`">($(($ParentCommandLine -join "|").Replace("`*",".`*")))<\/Data>" } if ($ParentUser.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"ParentUser`">($($ParentUser -join "|"))<\/Data>" } write-verbose -Message "RegEx is $pattern" $ParamsPassed = $PSBoundParameters.Keys } process { if ($SyslogFile -like "*.gz") { $file2process = Expand-GzFile (resolve-path $SyslogFile).Path } else { $file2process = $SyslogFile } Write-Verbose -Message "Opening $($file2process)" Select-String -Pattern $pattern -Path $file2process | ForEach-Object { try { $evtxml = [xml]($_.line.split("sysmon:"))[1] } catch { return } $EvtInfo = [ordered]@{} $EvtInfo['EventId'] = $evtxml.Event.System.EventID $EvtInfo['Version'] = $evtxml.Event.System.Version $EvtInfo['EventType'] = "ProcessCreate" $EvtInfo['Computer'] = $evtxml.Event.System.Computer $EvtInfo['EventRecordID'] = $evtxml.Event.System.EventRecordID $evtxml.event.eventdata.data | ForEach-Object { $EvtInfo[$_.name] = $_.'#text' } if ($ParamsPassed -contains "StartTime") { if (!([datetime]$EvtInfo['UtcTime'] -ge $StartTime)) { return } } if ($ParamsPassed -contains "EndTime") { if (!([datetime]$EvtInfo['UtcTime'] -le $EndTime)) { return } } $Obj = New-Object psobject -Property $EvtInfo $Obj.pstypenames[0] = "Sysmon.EventRecord.ProcessCreate" $Obj } } end { } } function Get-SysmonLinuxProcessTerminate { <# .SYNOPSIS Gets Sysmon process termination events from Syslog logs. .DESCRIPTION Gets Sysmon process termination events from Syslog logs.It allows filtering by field content. .INPUTS System.IO.FileInfo .OUTPUTS System.Management.Automation.PSCustomObject .NOTES General notes #> [CmdletBinding()] param ( # Specifies a path to one or more locations. [Parameter( Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage="Path to one or more locations.")] [Alias("PSPath")] [ValidateNotNullOrEmpty()] [ValidateScript({Test-Path $_})] [string[]] $SyslogFile = @("/var/log/syslog"), # ProcessGuid to search for, one or more can be provided. [Parameter(Mandatory=$false)] [string[]] $ProcessGuid, # RuleName to search for the given event type. #[Parameter(mandatory=$false)] #[string] #$RuleName, # ProcessID to search for, one or more can be provided. [Parameter(Mandatory=$false)] [string[]] $ProcessId, # Image to search forthis event type.The '*' wildcard is supported for matching. [Parameter(mandatory=$false)] [SupportsWildcards()] [string[]] $Image, # User to seach for, one or more can be provided. [Parameter(Mandatory=$false)] [string[]] $User, # Start Time to search for event created on and after this time. [Parameter(Mandatory=$false)] [datetime] $StartTime, # End Time to search for event created on and after this time. [Parameter(Mandatory=$false)] [datetime] $EndTime ) begin { $pattern = "^*sysmon:.*<EventID>5<\/EventID>" if ($RuleName.Length -gt 0){ $pattern = $pattern + ".*<Data Name=`"RuleName`">($($RuleName))<\/Data>" } if ($ProcessGuid.Length -gt 0){ $pattern = $pattern + ".*<Data Name=`"ProcessGuid`">($($ProcessGuid -join "|"))<\/Data>" } if ($ProcessGuid.Length -gt 0){ $pattern = $pattern + ".*<Data Name=`"ProcessGuid`">($($ProcessGuid -join "|"))<\/Data>" } if ($Image.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"Image`">($(($Image -join "|").Replace("`*",".`*")))<\/Data>" } if ($User.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"User`">($($User -join "|"))<\/Data>" } write-verbose -Message "RegEx is $pattern" $ParamsPassed = $PSBoundParameters.Keys } process { if ($SyslogFile -like "*.gz") { $file2process = Expand-GzFile (resolve-path $SyslogFile).Path } else { $file2process = $SyslogFile } Write-Verbose -Message "Opening $($file2process)" Select-String -Pattern $pattern -Path $file2process | ForEach-Object { try { $evtxml = [xml]($_.line.split("sysmon:"))[1] } catch { return } $EvtInfo = [ordered]@{} $EvtInfo['EventId'] = $evtxml.Event.System.EventID $EvtInfo['Version'] = $evtxml.Event.System.Version $EvtInfo['EventType'] = "ProcessTerminate" $EvtInfo['Computer'] = $evtxml.Event.System.Computer $EvtInfo['EventRecordID'] = $evtxml.Event.System.EventRecordID $evtxml.event.eventdata.data | ForEach-Object { $EvtInfo[$_.name] = $_.'#text' } if ($ParamsPassed -contains "StartTime") { if (!([datetime]$EvtInfo['UtcTime'] -ge $StartTime)) { return } } if ($ParamsPassed -contains "EndTime") { if (!([datetime]$EvtInfo['UtcTime'] -le $EndTime)) { return } } $Obj = New-Object psobject -Property $EvtInfo $Obj.pstypenames[0] = "Sysmon.EventRecord.ProcessTerminate" $Obj } } end { } } function Get-SysmonLinuxConfigChange { <# .SYNOPSIS Gets Sysmon config change events from Syslog logs. .DESCRIPTION Gets Sysmon config change events from Syslog logs. .EXAMPLE PS /> ls syslog* | Get-SysmonLinuxConfigChange EventId : 16 Version : 3 EventType : ConfigChange Computer : ubuntu EventRecordID : 8044 UtcTime : 2021-10-17 14:20:46.867 Configuration : ./sysmon.xml ConfigurationFileHash : - EventId : 16 Version : 3 EventType : ConfigChange Computer : ubuntu EventRecordID : 0 UtcTime : 2021-10-16 00:43:54.472 Configuration : /home/carlos/Desktop/sysmon.xml ConfigurationFileHash : - .INPUTS System.IO.FileInfo .OUTPUTS System.Management.Automation.PSCustomObject .NOTES General notes #> [CmdletBinding()] param ( # Specifies a path to one or more locations. [Parameter( Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage="Path to one or more locations.")] [Alias("PSPath")] [ValidateNotNullOrEmpty()] [ValidateScript({Test-Path $_})] [string[]] $SyslogFile = @("/var/log/syslog"), # Configuration file used to configure the service. [Parameter(Mandatory=$false)] [string] $Configuration, # Start Time to search for event created on and after this time. [Parameter(Mandatory=$false)] [datetime] $StartTime, # End Time to search for event created on and after this time. [Parameter(Mandatory=$false)] [datetime] $EndTime ) begin { $pattern = "^*sysmon:.*<EventID>16<\/EventID>" if ($Configuration.Length -gt 0){ $pattern = $pattern + ".*<Data Name=`"Configuration`">($($Configuration))<\/Data>" } write-verbose -Message "RegEx is $pattern" $ParamsPassed = $PSBoundParameters.Keys } process { if ($SyslogFile -like "*.gz") { $file2process = Expand-GzFile (resolve-path $SyslogFile).Path } else { $file2process = $SyslogFile } Write-Verbose -Message "Opening $($file2process)" Select-String -Pattern $pattern -Path $file2process | ForEach-Object { try { $evtxml = [xml]($_.line.split("sysmon:"))[1] } catch { return } $EvtInfo = [ordered]@{} $EvtInfo['EventId'] = $evtxml.Event.System.EventID $EvtInfo['Version'] = $evtxml.Event.System.Version $EvtInfo['EventType'] = "ConfigChange" $EvtInfo['Computer'] = $evtxml.Event.System.Computer $EvtInfo['EventRecordID'] = $evtxml.Event.System.EventRecordID $evtxml.event.eventdata.data | ForEach-Object { $EvtInfo[$_.name] = $_.'#text' } if ($ParamsPassed -contains "StartTime") { if (!([datetime]$EvtInfo['UtcTime'] -ge $StartTime)) { return } } if ($ParamsPassed -contains "EndTime") { if (!([datetime]$EvtInfo['UtcTime'] -le $EndTime)) { return } } $Obj = New-Object psobject -Property $EvtInfo $Obj.pstypenames[0] = "Sysmon.EventRecord.ConfigChange" $Obj } } end { } } function Get-SysmonLinuxState { <# .SYNOPSIS Gets Sysmon service state change events from Syslog logs. .DESCRIPTION Gets Sysmon service state change events from Syslog logs. .EXAMPLE PS /> ls syslog* | Get-SysmonLinuxState -State Stopped EventId : 4 Version : 1.0.0 EventType : SysmonState Computer : ubuntu EventRecordID : 229 UtcTime : 2021-10-16 00:44:07.686 State : Stopped SchemaVersion : 4.81 EventId : 4 Version : 1.0.0 EventType : SysmonState Computer : ubuntu EventRecordID : 2397 UtcTime : 2021-10-16 00:49:14.832 State : Stopped SchemaVersion : 4.81 EventId : 4 Version : 1.0.0 EventType : SysmonState Computer : ubuntu EventRecordID : 2471 UtcTime : 2021-10-16 00:49:24.198 State : Stopped SchemaVersion : 4.81 EventId : 4 Version : 1.0.0 EventType : SysmonState Computer : ubuntu EventRecordID : 5686 UtcTime : 2021-10-16 00:56:49.291 State : Stopped SchemaVersion : 4.81 .INPUTS System.IO.FileInfo .OUTPUTS System.Management.Automation.PSCustomObject .NOTES General notes #> [CmdletBinding()] param ( # Specifies a path to one or more locations. [Parameter( Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage="Path to one or more locations.")] [Alias("PSPath")] [ValidateNotNullOrEmpty()] [ValidateScript({Test-Path $_})] [string[]] $SyslogFile = @("/var/log/syslog"), # State of the service to search for. [Parameter(Mandatory=$false)] [ValidateSet("Started", "Stopped")] [string] $State , # Start Time to search for event created on and after this time. [Parameter(Mandatory=$false)] [datetime] $StartTime, # End Time to search for event created on and after this time. [Parameter(Mandatory=$false)] [datetime] $EndTime ) begin { $pattern = "^*sysmon:.*<EventID>4<\/EventID>" if ($State.Length -gt 0){ $pattern = $pattern + ".*<Data Name=`"State`">($($State))<\/Data>" } write-verbose -Message "RegEx is $pattern" $ParamsPassed = $PSBoundParameters.Keys } process { if ($SyslogFile -like "*.gz") { $file2process = Expand-GzFile (resolve-path $SyslogFile).Path } else { $file2process = $SyslogFile } Write-Verbose -Message "Opening $($file2process)" Select-String -Pattern $pattern -Path $file2process | ForEach-Object { try { $evtxml = [xml]($_.line.split("sysmon:"))[1] } catch { return } $EvtInfo = [ordered]@{} $EvtInfo['EventId'] = $evtxml.Event.System.EventID $EvtInfo['Version'] = $evtxml.Event.System.Version $EvtInfo['EventType'] = "SysmonState" $EvtInfo['Computer'] = $evtxml.Event.System.Computer $EvtInfo['EventRecordID'] = $evtxml.Event.System.EventRecordID $evtxml.event.eventdata.data | ForEach-Object { $EvtInfo[$_.name] = $_.'#text' } if ($ParamsPassed -contains "StartTime") { if (!([datetime]$EvtInfo['UtcTime'] -ge $StartTime)) { return } } if ($ParamsPassed -contains "EndTime") { if (!([datetime]$EvtInfo['UtcTime'] -le $EndTime)) { return } } $Obj = New-Object psobject -Property $EvtInfo $Obj.pstypenames[0] = "Sysmon.EventRecord.SysmonState" $Obj } } end { } } function Get-SysmonLinuxFileCreate { <# .SYNOPSIS Gets Sysmon file creation events from Syslog logs. .DESCRIPTION Gets Sysmon file creation events from Syslog logs.It allows filtering by field content. .EXAMPLE PS /home/carlos/Desktop> ls syslog* | Get-SysmonLinuxFileCreate -TargetFilename *.sh EventId : 11 Version : 2 EventType : FileCreate Computer : ubuntu EventRecordI : 3792 RuleName : - UtcTime : 2021-10-16 00:50:28.049 ProcessGuid : {de9527a5-21d3-616a-f5b7-a09aff550000} ProcessId : 2205 Image : /usr/bin/dash TargetFilename : /tmp/apt-key-gpghome.H5mVCI5gcY/gpg.1.sh CreationUtcTime : 2021-10-16 00:50:28.049 User : _apt EventId : 11 Version : 2 EventType : FileCreate Computer : ubuntu EventRecordID : 3905 RuleName : - UtcTime : 2021-10-16 00:50:28.402 ProcessGuid : {de9527a5-21d4-616a-f5d7-d7f930560000} ProcessId : 2264 Image : /usr/bin/dash TargetFilename : /tmp/apt-key-gpghome.jP1FNudhMk/gpg.1.sh CreationUtcTime : 2021-10-16 00:50:28.402 User : _apt .INPUTS System.IO.FileInfo .OUTPUTS System.Management.Automation.PSCustomObject .NOTES General notes #> [CmdletBinding(DefaultParameterSetName="All")] param ( # Specifies a path to one or more locations. [Parameter( Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage="Path to one or more locations.")] [Alias("PSPath")] [ValidateNotNullOrEmpty()] [ValidateScript({Test-Path $_})] [string[]] $SyslogFile = @("/var/log/syslog"), # ProcessGuid to search for, one or more can be provided. [Parameter(Mandatory=$false, ParameterSetName="ProcessGuid")] [string[]] $ProcessGuid, # RuleName to search for the given event type. #[Parameter(mandatory=$false)] #[string] #$RuleName, # ProcessID to search for, one or more can be provided. [Parameter(Mandatory=$false)] [string[]] $ProcessId, # Image to search for, one or more can be provided. The '*' wildcard is supported for matching. [Parameter(mandatory=$false)] [string[]] $Image, # TargetFilename to search for, one or more can be provided. The '*' wildcard is supported for matching. [Parameter(mandatory=$false)] [SupportsWildcards()] [string[]] $TargetFilename, # User to seach for, one or more can be provided. [Parameter(Mandatory=$false)] [string[]] $User, # Start Time to search for event created on and after this time. [Parameter(Mandatory=$false)] [datetime] $StartTime, # End Time to search for event created on and after this time. [Parameter(Mandatory=$false)] [datetime] $EndTime ) begin { $pattern = "^*sysmon:.*<EventID>11<\/EventID>" if ($RuleName.Length -gt 0){ $pattern = $pattern + ".*<Data Name=`"RuleName`">($($RuleName))<\/Data>" } if ($ProcessGuid.Length -gt 0){ $pattern = $pattern + ".*<Data Name=`"ProcessGuid`">($($ProcessGuid -join "|"))<\/Data>" } if ($ProcessGuid.Length -gt 0){ $pattern = $pattern + ".*<Data Name=`"(ProcessId)`">($($ProcessId -join "|"))<\/Data>" } if ($Image.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"Image`">($(($Image -join "|").Replace("`*",".`*")))<\/Data>" } if ($TargetFilename.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"TargetFilename`">($(($TargetFilename -join "|").Replace("`*",".`*")))<\/Data>" } write-verbose -Message "RegEx is $pattern" $ParamsPassed = $PSBoundParameters.Keys } process { if ($SyslogFile -like "*.gz") { $file2process = Expand-GzFile (resolve-path $SyslogFile).Path } else { $file2process = $SyslogFile } Write-Verbose -Message "Opening $($file2process)" Select-String -Pattern $pattern -Path $file2process | ForEach-Object { try { $evtxml = [xml]($_.line.split("sysmon:"))[1] } catch { return } $EvtInfo = [ordered]@{} $EvtInfo['EventId'] = $evtxml.Event.System.EventID $EvtInfo['Version'] = $evtxml.Event.System.Version $EvtInfo['EventType'] = "FileCreate" $EvtInfo['Computer'] = $evtxml.Event.System.Computer $EvtInfo['EventRecordID'] = $evtxml.Event.System.EventRecordID $evtxml.event.eventdata.data | ForEach-Object { $EvtInfo[$_.name] = $_.'#text' } if ($ParamsPassed -contains "StartTime") { if (!([datetime]$EvtInfo['UtcTime'] -ge $StartTime)) { return } } if ($ParamsPassed -contains "EndTime") { if (!([datetime]$EvtInfo['UtcTime'] -le $EndTime)) { return } } $Obj = New-Object psobject -Property $EvtInfo $Obj.pstypenames[0] = "Sysmon.EventRecord.FileCreate" $Obj } } end { } } function Get-SysmonLinuxFileDelete { <# .SYNOPSIS Gets Sysmon file deletion events from Syslog logs. .DESCRIPTION Gets Sysmon file deletion events from Syslog logs.It allows filtering by field content. .EXAMPLE PS /> Get-SysmonLinuxFileDelete -TargetFilename *.log EventId : 23 Version : 5 EventType : FileDelete Computer : ubuntu EventRecordID : 41011 RuleName : - UtcTime : 2021-10-20 03:11:31.597 ProcessGuid : {de9527a5-88e3-616f-e1e4-f23bd1550000} ProcessId : 6559 User : root Image : /usr/bin/rm TargetFilename : /var/log/app_audit.log Hashes : - IsExecutable : - Archived : - .INPUTS System.IO.FileInfo .OUTPUTS System.Management.Automation.PSCustomObject .NOTES General notes #> [CmdletBinding(DefaultParameterSetName="All")] param ( # Specifies a path to one or more locations. [Parameter( Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage="Path to one or more locations.")] [Alias("PSPath")] [ValidateNotNullOrEmpty()] [ValidateScript({Test-Path $_})] [string[]] $SyslogFile = @("/var/log/syslog"), # ProcessGuid to search for, one or more can be provided. [Parameter(Mandatory=$false, ParameterSetName="ProcessGuid")] [string[]] $ProcessGuid, # RuleName to search for, one or more can be provided. #[Parameter(mandatory=$false)] #[string[]] #$RuleName, # ProcessID to search for, one or more can be provided. [Parameter(Mandatory=$false)] [string[]] $ProcessId, # Image to search for, one or more can be provided. The '*' wildcard is supported for matching. [Parameter(mandatory=$false)] [SupportsWildcards()] [string[]] $Image, # TargetFilename to search for, one or more can be provided. The '*' wildcard is supported for matching. [Parameter(mandatory=$false)] [SupportsWildcards()] [string[]] $TargetFilename, # User to seach for, one or more can be provided. [Parameter(Mandatory=$false)] [string[]] $User, # Start Time to search for event created on and after this time. [Parameter(Mandatory=$false)] [datetime] $StartTime, # End Time to search for event created on and after this time. [Parameter(Mandatory=$false)] [datetime] $EndTime ) begin { $pattern = "^*sysmon:.*<EventID>23<\/EventID>" if ($RuleName.Length -gt 0){ $pattern = $pattern + ".*<Data Name=`"RuleName`">($($RuleName))<\/Data>" } if ($ProcessGuid.Length -gt 0){ $pattern = $pattern + ".*<Data Name=`"ProcessGuid`">($($ProcessGuid -join "|"))<\/Data>" } if ($ProcessGuid.Length -gt 0){ $pattern = $pattern + ".*<Data Name=`"(ProcessId)`">($($ProcessId -join "|"))<\/Data>" } if ($Image.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"Image`">($(($Image -join "|").Replace("`*",".`*")))<\/Data>" } if ($TargetFilename.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"TargetFilename`">($(($TargetFilename -join "|").Replace("`*",".`*")))<\/Data>" } write-verbose -Message "RegEx is $pattern" $ParamsPassed = $PSBoundParameters.Keys } process { if ($SyslogFile -like "*.gz") { $file2process = Expand-GzFile (resolve-path $SyslogFile).Path } else { $file2process = $SyslogFile } Write-Verbose -Message "Opening $($file2process)" Select-String -Pattern $pattern -Path $file2process | ForEach-Object { try { $evtxml = [xml]($_.line.split("sysmon:"))[1] } catch { return } $EvtInfo = [ordered]@{} $EvtInfo['EventId'] = $evtxml.Event.System.EventID $EvtInfo['Version'] = $evtxml.Event.System.Version $EvtInfo['EventType'] = "FileDelete" $EvtInfo['Computer'] = $evtxml.Event.System.Computer $EvtInfo['EventRecordID'] = $evtxml.Event.System.EventRecordID $evtxml.event.eventdata.data | ForEach-Object { $EvtInfo[$_.name] = $_.'#text' } if ($ParamsPassed -contains "StartTime") { if (!([datetime]$EvtInfo['UtcTime'] -ge $StartTime)) { return } } if ($ParamsPassed -contains "EndTime") { if (!([datetime]$EvtInfo['UtcTime'] -le $EndTime)) { return } } $Obj = New-Object psobject -Property $EvtInfo $Obj.pstypenames[0] = "Sysmon.EventRecord.FileDelete" $Obj } } end { } } function Get-SysmonLinuxRawAccess { <# .SYNOPSIS Gets Sysmon events for direct access to a block device. .DESCRIPTION Gets Sysmon events for direct access to a block device. from Syslog logs.It allows filtering by field content. .EXAMPLE PS /> Get-SysmonLinuxRawAccess | select image,device,user -unique | ConvertTo-SysmonRule <Rule groupRelation="and"> <Image condition='is'>/usr/lib/systemd/systemd-logind</Image> <Device condition='is'>/dev/sda1</Device> <User condition='is'>root</User> </Rule> <Rule groupRelation="and"> <Image condition='is'>/usr/lib/systemd/systemd-logind</Image> <Device condition='is'>/dev/sda</Device> <User condition='is'>root</User> </Rule> <Rule groupRelation="and"> <Image condition='is'>/usr/sbin/dumpe2fs</Image> <Device condition='is'>/dev/sda5</Device> <User condition='is'>root</User> </Rule> <Rule groupRelation="and"> <Image condition='is'>/usr/sbin/blkid</Image> <Device condition='is'>/dev/sda5</Device> <User condition='is'>root</User> </Rule> <Rule groupRelation="and"> <Image condition='is'>/usr/sbin/blkid</Image> <Device condition='is'>/dev/sda</Device> <User condition='is'>root</User> </Rule> <Rule groupRelation="and"> <Image condition='is'>/usr/sbin/grub-probe</Image> <Device condition='is'>/dev/sda</Device> <User condition='is'>root</User> </Rule> Create rule set for use in exclusion of known behaviour. .INPUTS System.IO.FileInfo .OUTPUTS System.Management.Automation.PSCustomObject .NOTES General notes #> [CmdletBinding(DefaultParameterSetName="All")] param ( # Specifies a path to one or more locations. [Parameter( Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage="Path to one or more locations.")] [Alias("PSPath")] [ValidateNotNullOrEmpty()] [ValidateScript({Test-Path $_})] [string[]] $SyslogFile = @("/var/log/syslog"), # ProcessGuid to search for a given event type. [Parameter(Mandatory=$false, ParameterSetName="ProcessGuid")] [string[]] $ProcessGuid, # RuleName to search for the given event type. #[Parameter(mandatory=$false)] #[string[]] #$RuleName, # ProcessID to search for a given event type. [Parameter(Mandatory=$false)] [string[]] $ProcessId, # Image to search for a given event type. [Parameter(mandatory=$false)] [SupportsWildcards()] [string[]] $Image, # TargetFilename to search for a given event type. [Parameter(mandatory=$false)] [string] $Device, # User to seach for a given event type. [Parameter(Mandatory=$false)] [string[]] $User, # Start Time to search for event created on and after this time. [Parameter(Mandatory=$false)] [datetime] $StartTime, # End Time to search for event created on and after this time. [Parameter(Mandatory=$false)] [datetime] $EndTime ) begin { $pattern = "^*sysmon:.*<EventID>9<\/EventID>" if ($RuleName.Length -gt 0){ $pattern = $pattern + ".*<Data Name=`"RuleName`">($($RuleName))<\/Data>" } if ($ProcessGuid.Length -gt 0){ $pattern = $pattern + ".*<Data Name=`"ProcessGuid`">($($ProcessGuid -join "|"))<\/Data>" } if ($ProcessGuid.Length -gt 0){ $pattern = $pattern + ".*<Data Name=`"(ProcessId)`">($($ProcessId -join "|"))<\/Data>" } if ($Image.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"Image`">($(($Image -join "|").Replace("`*",".`*")))<\/Data>" } if ($Device.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"Device`">($($Device))<\/Data>" } write-verbose -Message "RegEx is $pattern" $ParamsPassed = $PSBoundParameters.Keys } process { if ($SyslogFile -like "*.gz") { $file2process = Expand-GzFile (resolve-path $SyslogFile).Path } else { $file2process = $SyslogFile } Write-Verbose -Message "Opening $($file2process)" Select-String -Pattern $pattern -Path $file2process | ForEach-Object { try { $evtxml = [xml]($_.line.split("sysmon:"))[1] } catch { return } $EvtInfo = [ordered]@{} $EvtInfo['EventId'] = $evtxml.Event.System.EventID $EvtInfo['Version'] = $evtxml.Event.System.Version $EvtInfo['EventType'] = "FileDelete" $EvtInfo['Computer'] = $evtxml.Event.System.Computer $EvtInfo['EventRecordID'] = $evtxml.Event.System.EventRecordID $evtxml.event.eventdata.data | ForEach-Object { $EvtInfo[$_.name] = $_.'#text' } if ($ParamsPassed -contains "StartTime") { if (!([datetime]$EvtInfo['UtcTime'] -ge $StartTime)) { return } } if ($ParamsPassed -contains "EndTime") { if (!([datetime]$EvtInfo['UtcTime'] -le $EndTime)) { return } } $Obj = New-Object psobject -Property $EvtInfo $Obj.pstypenames[0] = "Sysmon.EventRecord.FileDelete" $Obj } } end { } } function Get-SysmonLinuxNetworkConnect { <# SYNOPSIS Gets Sysmon network events from Syslog logs. .DESCRIPTION Gets Sysmon network events from Syslog logs.It allows filtering by field content. .EXAMPLE PS C:\> <example usage> Explanation of what the example does .INPUTS System.IO.FileInfo .OUTPUTS System.Management.Automation.PSCustomObject .NOTES General notes #> [CmdletBinding(DefaultParameterSetName="All")] param ( # Specifies a path to one or more locations. [Parameter( Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage="Path to one or more locations.")] [Alias("PSPath")] [ValidateNotNullOrEmpty()] [ValidateScript({Test-Path $_})] [string[]] $SyslogFile = @("/var/log/syslog"), # ProcessGuid to search for a given event type. [Parameter(Mandatory=$false, ParameterSetName="ProcessGuid")] [string[]] $ProcessGuid, # RuleName to search for the given event type. #[Parameter(mandatory=$false)] #[string[]] #$RuleName, # ProcessID to search for a given event type. [Parameter(Mandatory=$false)] [string[]] $ProcessId, # Image to search for a given event type. [Parameter(mandatory=$false)] [SupportsWildcards()] [string[]] $Image, # User to seach for a given event type. [Parameter(Mandatory=$false)] [string[]] $User, # User to seach for a given event type. [Parameter(Mandatory=$false)] [ValidateSet('TCP','UDP')] [string] $Protocol, # User to seach for a given event type. [Parameter(Mandatory=$false)] [ValidateSet('True','False')] [string] $Initiated, [Parameter(Mandatory=$false)] [ValidateSet('True','False')] [string] $SourceIsIpv6, [Parameter(Mandatory=$false)] [string[]] $SourceIp, [Parameter(Mandatory=$false)] [string[]] $SourcePort, [Parameter(Mandatory=$false)] [ValidateSet('True','False')] [string] $DestinationIsIpv6, [Parameter(Mandatory=$false)] [string[]] $DestinationIp, [Parameter(Mandatory=$false)] [string[]] $DestinationPort, # Start Time to search for event created on and after this time. [Parameter(Mandatory=$false)] [datetime] $StartTime, # End Time to search for event created on and after this time. [Parameter(Mandatory=$false)] [datetime] $EndTime ) begin { $pattern = "^*sysmon:.*<EventID>3<\/EventID>" if ($RuleName.Length -gt 0){ $pattern = $pattern + ".*<Data Name=`"RuleName`">($($RuleName))<\/Data>" } if ($ProcessGuid.Length -gt 0){ $pattern = $pattern + ".*<Data Name=`"ProcessGuid`">($($ProcessGuid -join "|"))<\/Data>" } if ($ProcessGuid.Length -gt 0){ $pattern = $pattern + ".*<Data Name=`"(ProcessId)`">($($ProcessId -join "|"))<\/Data>" } if ($Image.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"Image`">($($Image.Replace("`*",".`*")))<\/Data>" } if ($Protocol.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"Protocol`">($(($Protocol -join "|").ToLower()))<\/Data>" } if ($Initiated.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"Initiated`">($(($Initiated -join "|").ToLower()))<\/Data>" } if ($SourceIsIpv6.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"SourceIsIpv6`">($(($SourceIsIpv6 -join "|").ToLower()))<\/Data>" } if ($SourceIp.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"SourceIp`">($(($SourceIp -join "|")))<\/Data>" } if ($SourcePort.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"SourcePort`">($(($SourcePort -join "|")))<\/Data>" } if ($DestinationIsIpv6.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"DestinationIsIpv6`">($(($DestinationIsIpv6 -join "|").ToLower()))<\/Data>" } if ($DestinationIp.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"DestinationIp`">($(($DestinationIp -join "|")))<\/Data>" } if ($DestinationPort.Length -gt 0) { $pattern = $pattern + ".*<Data Name=`"DestinationPort`">($(($DestinationPort -join "|")))<\/Data>" } write-verbose -Message "RegEx is $pattern" $ParamsPassed = $PSBoundParameters.Keys } process { if ($SyslogFile -like "*.gz") { $file2process = Expand-GzFile (resolve-path $SyslogFile).Path } else { $file2process = $SyslogFile } Write-Verbose -Message "Opening $($file2process)" Select-String -Pattern $pattern -Path $file2process | ForEach-Object { try { $evtxml = [xml]($_.line.split("sysmon:"))[1] } catch { return } $EvtInfo = [ordered]@{} $EvtInfo['EventId'] = $evtxml.Event.System.EventID $EvtInfo['Version'] = $evtxml.Event.System.Version $EvtInfo['EventType'] = "NetworkConnect" $EvtInfo['Computer'] = $evtxml.Event.System.Computer $EvtInfo['EventRecordID'] = $evtxml.Event.System.EventRecordID $evtxml.event.eventdata.data | ForEach-Object { $EvtInfo[$_.name] = $_.'#text' } if ($ParamsPassed -contains "StartTime") { if (!([datetime]$EvtInfo['UtcTime'] -ge $StartTime)) { return } } if ($ParamsPassed -contains "EndTime") { if (!([datetime]$EvtInfo['UtcTime'] -le $EndTime)) { return } } $Obj = New-Object psobject -Property $EvtInfo $Obj.pstypenames[0] = "Sysmon.EventRecord.NetworkConnect" $Obj } } end { } } function ConvertTo-SysmonRule { <# .SYNOPSIS Turn Sysmon Event objects in to Rules or RuleGroups for use in configuration files. .DESCRIPTION Funtion for creationg Rules or RuleGroups depending on the number of properties from Sysmon Event Objects. When more than 1 property select will be turned in to RuleGroups, if only one property is present they are turned in to Rules. RuleGroups have a Group Relation of 'and'. For rules since exact matches are used the conditions supported for selectio are 'is', 'is not', "excludes", "begin with" and "image". Default consition if not specified the "is" is used. .EXAMPLE .INPUTS System.Management.Automation.PSCustomObject System.String .OUTPUTS System.String .NOTES General notes #> [CmdletBinding()] param ( # Sysmon Event Object [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [pscustomobject[]] $SysmonEvent, # Rule condition. [Parameter(Mandatory=$false)] [ValidateSet('is', 'is not',"excludes", "begin with","image")] [string] $Condition = "is" ) begin { } process { foreach($event in $SysmonEvent) { $propCount = (Get-Member -InputObject $event -MemberType Properties).count if ($propCount -eq 1){ $event.PSObject.Properties | ForEach-Object { "<$($_.name) condition='$($Condition)'>$($_.value.Replace("&","&"))</$($_.name)>" } } elseif ($propCount -gt 1) { $RuleGroup = "<Rule groupRelation=`"and`">`n" $event.PSObject.Properties | ForEach-Object { $RuleGroup += " <$($_.name) condition='$($Condition)'>$($_.value.Replace("&","&"))</$($_.name)>`n" } $RuleGroup += "</Rule>" $RuleGroup } } } end {} } Function Expand-GzFile{ Param( $infile ) begin{} process{ $outfile = "$([System.IO.Path]::GetTempPath())$([System.IO.Path]::GetFileNameWithoutExtension($infile))" $inputfile = New-Object System.IO.FileStream $inFile, ([IO.FileMode]::Open), ([IO.FileAccess]::Read), ([IO.FileShare]::Read) $output = New-Object System.IO.FileStream $outFile, ([IO.FileMode]::Create), ([IO.FileAccess]::Write), ([IO.FileShare]::None) $gzipStream = New-Object System.IO.Compression.GzipStream $inputfile, ([IO.Compression.CompressionMode]::Decompress) $buffer = New-Object byte[](1024) while($true){ $read = $gzipstream.Read($buffer, 0, 1024) if ($read -le 0){break} $output.Write($buffer, 0, $read) } $gzipStream.Close() $output.Close() $inputfile.Close() $outfile } } |