Windows Persistence Mechanisms Triage Playbook
Adversaries establish persistence to maintain uninterrupted access across system restarts and credential resets. This field guide details the most prevalent Windows persistence locations and triage commands.
🗂️ Master Persistence Vector Checklist
Section titled “🗂️ Master Persistence Vector Checklist”[ ] 1. Registry Run / RunOnce Keys (HKLM / HKCU)[ ] 2. Startup Folders (User & All Users)[ ] 3. Windows Services (ImagePath, svchost ServiceDll)[ ] 4. Scheduled Tasks (XML actions, hidden tasks)[ ] 5. WMI Event Subscriptions (__EventConsumer)[ ] 6. Accessibility Binaries (Sticky Keys / Utilman)[ ] 7. Winlogon Shell & Userinit Keys[ ] 8. COM Component Hijacking (CLSID InprocServer32)⚙️ 1. Windows Services Abuse (T1543.003)
Section titled “⚙️ 1. Windows Services Abuse (T1543.003)”Adversaries create malicious services or tamper with existing service binary paths (binPath).
Critical Registry Locations
Section titled “Critical Registry Locations”HKLM\SYSTEM\CurrentControlSet\Services\[ServiceName]- Key values:
ImagePath(binary path),Start(2=Auto, 3=Manual, 4=Disabled),ServiceDll(for svchost services underParameters).
Rapid Triage via PowerShell
Section titled “Rapid Triage via PowerShell”# Identify services with unusual paths (outside System32 or Program Files)Get-CimInstance Win32_Service | Where-Object { $_.PathName -notmatch '^(C:\\Windows\\system32|C:\\Program Files|C:\\Program Files \(x86\))' -and $_.PathName -ne $null } | Select-Object Name, DisplayName, State, StartMode, PathName | Format-Table -AutoSize📅 2. Scheduled Tasks Triage (T1053.005)
Section titled “📅 2. Scheduled Tasks Triage (T1053.005)”Scheduled tasks are commonly created via schtasks.exe or PowerShell to execute payloads periodically.
On-Disk & Registry Locations
Section titled “On-Disk & Registry Locations”- Task XML Files:
C:\Windows\System32\Tasks\ - Task Registry Tree:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\and...\Tree\
Detection & Triage
Section titled “Detection & Triage”# Parse Task XML definitions directly for script interpreters or temporary folder pathsGet-ChildItem -Path "C:\Windows\System32\Tasks" -Recurse -File | ForEach-Object { try { [xml]$taskXml = Get-Content $_.FullName -Raw -ErrorAction Stop $actions = $taskXml.Task.Actions $exec = $actions.Exec.Command $args = $actions.Exec.Arguments
if ($exec -match '(powershell|cmd|cscript|wscript|mshta|temp|appdata)' -or $args -match '(temp|appdata|http|-enc)') { [PSCustomObject]@{ TaskName = $_.Name FullPath = $_.FullName Command = $exec Args = $args } } } catch {}} | Format-Table -AutoSize🕷️ 3. WMI Event Subscriptions (T1546.004)
Section titled “🕷️ 3. WMI Event Subscriptions (T1546.004)”WMI persistence runs completely in the repository without standard registry keys or executable files in startup folders, making it extremely stealthy.
The Three Required Components:
Section titled “The Three Required Components:”__EventFilter: WQL query specifying triggering event (e.g. system startup, user logon, or specific time).__EventConsumer: Action taken upon trigger (e.g.CommandLineEventConsumerrunning a command or script).__FilterToConsumerBinding: The link associating the filter to the consumer.
Hunting WMI Persistence
Section titled “Hunting WMI Persistence”# Query WMI Persistence in root\subscription namespace$ns = 'root\subscription'
$consumers = Get-CimInstance -Namespace $ns -ClassName __EventConsumer$filters = Get-CimInstance -Namespace $ns -ClassName __EventFilter$bindings = Get-CimInstance -Namespace $ns -ClassName __FilterToConsumerBinding
Write-Host "=== WMI CONSUMERS ===" -ForegroundColor Cyan$consumers | Select-Object Name, CommandLineTemplate, ExecutablePath, ScriptText | Format-List
Write-Host "=== WMI BINDINGS ===" -ForegroundColor Yellow$bindings | Select-Object Filter, Consumer | Format-List🔑 4. Winlogon & Authentication Packages (T1547.004)
Section titled “🔑 4. Winlogon & Authentication Packages (T1547.004)”Modifying the default shell or logon helper applications to execute an adversary binary at logon.
Keys to Inspect:
Section titled “Keys to Inspect:”HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinlogonShell: Must default toexplorer.exeUserinit: Must default toC:\Windows\system32\userinit.exe,Taskman: Normally empty
# Verify Winlogon defaultsGet-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" | Select-Object Shell, Userinit, Taskman, VmApplet | Format-List♿ 5. Accessibility Backdoors (Sticky Keys / Utilman) (T1546.008)
Section titled “♿ 5. Accessibility Backdoors (Sticky Keys / Utilman) (T1546.008)”Replacing accessibility binaries (sethc.exe or utilman.exe) with cmd.exe, or configuring an Image File Execution Options (IFEO) debugger.
# Check IFEO Debugger values for accessibility binaries$ifeoKeys = @('sethc.exe', 'utilman.exe', 'osk.exe', 'Magnify.exe', 'DisplaySwitch.exe')
foreach ($key in $ifeoKeys) { $path = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\$key" if (Test-Path $path) { $debugger = (Get-ItemProperty -Path $path).Debugger if ($debugger) { Write-Warning "BACKDOOR DETECTED on $key -> Debugger: $debugger" } }}