EventMonitor/EventProcessors/PersistenceEvents.ps1
|
# ── Persistence Events Processor ────────────────────────────────────────────── # Monitors service installation and scheduled task creation/modification. # These are key persistence mechanisms used by attackers and malware. # Event IDs: 4697, 4698, 4702 (Security), 7045 (System) # # Reference: https://learn.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4697 <# .SYNOPSIS Collects persistence-related events within the time window. .DESCRIPTION These events are NOT filtered by user — any service/task install is relevant. Attackers frequently install services or scheduled tasks for persistence. #> function Get-PersistenceEvents { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$sessionId, [Parameter(Mandatory)] [DateTime]$StartTime ) Get-SecurityPersistenceEvents -sessionId $sessionId -StartTime $StartTime Get-Event7045_ServiceInstalled -sessionId $sessionId -StartTime $StartTime } # ── Events 4697, 4698, 4702: Security Log Persistence ──────────────────────── # 4697: Service installed — [0]SubjectSID [1]SubjectUserName [2]SubjectDomainName # [3]SubjectLogonId [4]ServiceName [5]ServiceFileName [6]ServiceType # [7]ServiceStartType [8]ServiceAccount # 4698: Scheduled task created — [0]SubjectSID [1]SubjectUserName [2]SubjectDomainName # [3]SubjectLogonId [4]TaskName [5]TaskContent (XML) # 4702: Scheduled task updated — same layout as 4698 function Get-SecurityPersistenceEvents { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$sessionId, [Parameter(Mandatory)] [DateTime]$StartTime ) try { $events = Read-WindowsEvents -EventId 4697, 4698, 4699, 4702 -LogName 'Security' -StartTime $StartTime foreach ($evt in $events) { switch ($evt.Id) { 4697 { $props = New-EventProperties -SessionId $sessionId -EventType 'Alert' -Severity 'Critical' $props['SubjectUserName'] = "$($evt.Properties[1].Value)" $props['SubjectDomain'] = "$($evt.Properties[2].Value)" $props['ServiceName'] = "$($evt.Properties[4].Value)" $props['ServiceFileName'] = "$($evt.Properties[5].Value)" $props['ServiceType'] = "$($evt.Properties[6].Value)" $props['ServiceStartType'] = "$($evt.Properties[7].Value)" $props['ServiceAccount'] = "$($evt.Properties[8].Value)" $props['EventDescription'] = 'Service Installed on System' Send-LogAnalyticsConnectEvents ` -eventName '4697 Service Installed' -Properties $props -sendEvent $evt } { $_ -in 4698, 4699, 4702 } { $description = switch ($evt.Id) { 4698 { 'Scheduled Task Created' } 4699 { 'Scheduled Task Deleted' } 4702 { 'Scheduled Task Updated' } } $severity = switch ($evt.Id) { 4698 { 'Critical' } 4699 { 'High' } 4702 { 'High' } } $props = New-EventProperties -SessionId $sessionId -EventType 'Alert' -Severity $severity $props['SubjectUserName'] = "$($evt.Properties[1].Value)" $props['SubjectDomain'] = "$($evt.Properties[2].Value)" $props['TaskName'] = "$($evt.Properties[4].Value)" $props['EventDescription'] = $description # Task XML content can be very large — truncate for telemetry $taskXml = "$($evt.Properties[5].Value)" if ($taskXml.Length -gt 2000) { $taskXml = $taskXml.Substring(0, 2000) + '...[truncated]' } $props['TaskContent'] = $taskXml Send-LogAnalyticsConnectEvents ` -eventName "$($evt.Id) $description" -Properties $props -sendEvent $evt } } } } catch { Write-EMLog -Message "Get-SecurityPersistenceEvents: $($_.Exception.Message)" -Level Error TrackException -ErrorRecord $_ ` -Properties (New-ErrorProperties -SessionId $sessionId -FunctionName 'Get-SecurityPersistenceEvents') } } # ── Event 7045: New Service Installed (System log) ──────────────────────────── # Properties: [0]ServiceName [1]ImagePath [2]ServiceType [3]StartType [4]AccountName function Get-Event7045_ServiceInstalled { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$sessionId, [Parameter(Mandatory)] [DateTime]$StartTime ) try { $events = Read-WindowsEvents -EventId 7045 -LogName 'System' -StartTime $StartTime foreach ($evt in $events) { $props = New-EventProperties -SessionId $sessionId -EventType 'Alert' -Severity 'High' $props['ServiceName'] = "$($evt.Properties[0].Value)" $props['ImagePath'] = "$($evt.Properties[1].Value)" $props['ServiceType'] = "$($evt.Properties[2].Value)" $props['StartType'] = "$($evt.Properties[3].Value)" $props['AccountName'] = "$($evt.Properties[4].Value)" $props['EventDescription'] = 'New Service Installed (System)' Send-LogAnalyticsConnectEvents ` -eventName '7045 Service Installed' -Properties $props -sendEvent $evt } } catch { Write-EMLog -Message "Get-Event7045_ServiceInstalled: $($_.Exception.Message)" -Level Error TrackException -ErrorRecord $_ ` -Properties (New-ErrorProperties -SessionId $sessionId -FunctionName 'Get-Event7045_ServiceInstalled') } } |