{"id":201,"date":"2022-12-04T09:00:00","date_gmt":"2022-12-04T09:00:00","guid":{"rendered":"http:\/\/justruss.tech\/index.php\/2022\/12\/04\/my-windows-dfir-checklist-for-initial-triage\/"},"modified":"2026-05-13T12:59:35","modified_gmt":"2026-05-13T12:59:35","slug":"my-windows-dfir-checklist-for-initial-triage","status":"publish","type":"post","link":"https:\/\/justruss.tech\/index.php\/2022\/12\/04\/my-windows-dfir-checklist-for-initial-triage\/","title":{"rendered":"My Windows DFIR Checklist for Initial Triage"},"content":{"rendered":"<p>This is the triage checklist I actually use at the start of a Windows incident or serious CTF challenge. It is not exhaustive \u2014 deep-dive analysis follows once scope is understood. The goal of this phase is to answer three questions: what<br \/>\nhappened, roughly when, and how widely has it spread?<\/p>\n<h3>Phase 0 \u2014 Before touching anything<\/h3>\n<p>If the system is live and you have time:<\/p>\n<pre># Note the current system time and verify it against a trusted source\nw32tm \/query \/status\n# Check \"Stratum\" and \"Last Successful Sync Time\" - large skew = potential tampering\n\n# Confirm your investigation user has the right privileges\nwhoami \/priv | findstr \/i \"SeDebugPrivilege\\|SeBackupPrivilege\"\n# SeDebugPrivilege is needed for memory access and some NTFS operations<\/pre>\n<p>Document the system state before any commands run. Take a screenshot of Task Manager. Note the system time. These baselines matter if the case goes to legal proceedings.<\/p>\n<h3>Phase 1 \u2014 Volatile data collection (live system only)<\/h3>\n<pre># Running processes with full paths and command lines\nGet-WmiObject Win32_Process | Select-Object ProcessId, ParentProcessId, Name, ExecutablePath, CommandLine | Export-Csv C:\\ir\\processes.csv\n\n# Network connections with owning process\nGet-NetTCPConnection | Select-Object LocalAddress, LocalPort, RemoteAddress, RemotePort, State, OwningProcess | Export-Csv C:\\ir\\connections.csv\n\n# Cross-reference connection PIDs with process list\n$procs = Get-Process -IncludeUserName\nGet-NetTCPConnection -State Established | ForEach-Object {\n    $proc = $procs | Where-Object {$_.Id -eq $_.OwningProcess}\n    [PSCustomObject]@{\n        Remote = \"$($_.RemoteAddress):$($_.RemotePort)\"\n        PID = $_.OwningProcess\n        Process = $proc.Name\n        Path = $proc.Path\n        User = $proc.UserName\n    }\n} | Export-Csv C:\\ir\\active_connections.csv\n\n# Scheduled tasks - full details including actions and triggers\nschtasks \/query \/fo CSV \/v &gt; C:\\ir\\schtasks.csv\n\n# Services - include binary path and start type\nGet-WmiObject Win32_Service | Select-Object Name, State, StartMode, PathName, StartName | Export-Csv C:\\ir\\services.csv\n\n# Loaded drivers\nGet-WmiObject Win32_SystemDriver | Select-Object Name, State, PathName | Export-Csv C:\\ir\\drivers.csv\n\n# DNS cache (can reveal C2 domains contacted)\nGet-DnsClientCache | Export-Csv C:\\ir\\dns_cache.csv<\/pre>\n<h3>Phase 2 \u2014 Event log triage<\/h3>\n<p>Extract targeted events from the last 48 hours rather than pulling entire log files:<\/p>\n<pre># Account logon events - identify unusual accounts or times\nGet-WinEvent -FilterHashtable @{\n    LogName = \"Security\"\n    Id = 4624\n    StartTime = (Get-Date).AddHours(-48)\n} | Where-Object {\n    $_.Properties[8].Value -ne 5  # Exclude service logons\n} | Select-Object TimeCreated,\n    @{N=\"Account\";E={$_.Properties[5].Value}},\n    @{N=\"LogonType\";E={$_.Properties[8].Value}},\n    @{N=\"SourceIP\";E={$_.Properties[18].Value}}\n\n# New local accounts created\nGet-WinEvent -FilterHashtable @{LogName=\"Security\"; Id=4720; StartTime=(Get-Date).AddHours(-48)}\n\n# Services installed (common persistence)\nGet-WinEvent -FilterHashtable @{LogName=\"System\"; Id=7045; StartTime=(Get-Date).AddHours(-48)} |\n    ForEach-Object {\n        [xml]$xml = $_.ToXml()\n        [PSCustomObject]@{\n            Time = $_.TimeCreated\n            ServiceName = $xml.Event.EventData.Data[0].\"#text\"\n            ImagePath = $xml.Event.EventData.Data[2].\"#text\"\n        }\n    }\n\n# PowerShell script block logging - look for suspicious content\nGet-WinEvent -FilterHashtable @{\n    LogName = \"Microsoft-Windows-PowerShell\/Operational\"\n    Id = 4104\n    Level = 3  # Warning level = flagged by PowerShell as suspicious\n    StartTime = (Get-Date).AddHours(-48)\n} | Select-Object TimeCreated, Message | Format-List<\/pre>\n<h3>Phase 3 \u2014 Persistence locations<\/h3>\n<pre># Registry Run keys - all users\n$runkeys = @(\n    \"HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\",\n    \"HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce\",\n    \"HKCU:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\",\n    \"HKCU:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce\",\n    \"HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Run\"\n)\nforeach ($key in $runkeys) {\n    if (Test-Path $key) {\n        Get-ItemProperty $key | Select-Object * -ExcludeProperty PS*\n    }\n}\n\n# WMI event subscriptions - commonly missed in IR checklists\nGet-WMIObject -Namespace root\\subscription -Class __EventFilter\nGet-WMIObject -Namespace root\\subscription -Class __EventConsumer\nGet-WMIObject -Namespace root\\subscription -Class __FilterToConsumerBinding\n\n# AppInit_DLLs - DLL injection via registry\nGet-ItemProperty \"HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows\" -Name AppInit_DLLs\nGet-ItemProperty \"HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Windows\" -Name AppInit_DLLs\n\n# COM object hijacking candidates\n$userCOM = \"HKCU:\\SOFTWARE\\Classes\\CLSID\"\nif (Test-Path $userCOM) {\n    Get-ChildItem $userCOM | Select-Object Name, LastWriteTime\n}\n\n# Startup folders\nGet-ChildItem \"C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\" -ErrorAction SilentlyContinue\nGet-ChildItem \"$env:APPDATA\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\" -ErrorAction SilentlyContinue<\/pre>\n<h3>Phase 4 \u2014 Execution artefacts<\/h3>\n<pre># Prefetch - execution history\nif (Test-Path C:\\Windows\\Prefetch) {\n    Get-ChildItem C:\\Windows\\Prefetch\\*.pf |\n        Select-Object Name, LastWriteTime, CreationTime |\n        Sort-Object LastWriteTime -Descending |\n        Where-Object { $_.LastWriteTime -gt (Get-Date).AddHours(-48) }\n}\n\n# Amcache - file execution with hashes (run PECmd\/AmcacheParser offline)\nif (Test-Path C:\\Windows\\AppCompat\\Programs\\Amcache.hve) {\n    Write-Output \"Amcache.hve present - copy for offline analysis\"\n    Copy-Item C:\\Windows\\AppCompat\\Programs\\Amcache.hve C:\\ir\\\n}\n\n# Recently accessed files (Shellbags, LNK files)\nGet-ChildItem \"$env:APPDATA\\Microsoft\\Windows\\Recent\" -ErrorAction SilentlyContinue |\n    Sort-Object LastWriteTime -Descending | Select-Object Name, LastWriteTime | head -20<\/pre>\n<h3>The most common mistake<\/h3>\n<p>Spending the first 90 minutes going deep on a single suspicious process before completing broad triage. The suspicious process is often a distraction \u2014 a secondary tool run after the real persistence mechanism was already established. Complete<br \/>\nthe full checklist first. The most important finding is usually not the most obvious one.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>After working through enough incidents and CTF challenges, a checklist that<br \/>\ncovers the things that matter most in the first 30 minutes.<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-201","post","type-post","status-publish","format-standard","hentry","category-dfir"],"_links":{"self":[{"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/posts\/201","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/comments?post=201"}],"version-history":[{"count":2,"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/posts\/201\/revisions"}],"predecessor-version":[{"id":243,"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/posts\/201\/revisions\/243"}],"wp:attachment":[{"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/media?parent=201"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/categories?post=201"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/tags?post=201"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}