src/Private/Core/Write-FotonChainOfCustody.ps1
|
function Write-FotonChainOfCustody { param( [string]$OutputPath, [string]$CaseNumber, [string]$Examiner, [switch]$LoadUserHives, [switch]$NoZip, [switch]$RequireAdministrator ) $elevated = $script:FotonSession.IsElevated $tz = [System.TimeZoneInfo]::Local $os = $null try { $os = Get-CimInstance Win32_OperatingSystem -ErrorAction Stop } catch { } $cs = $null try { $cs = Get-CimInstance Win32_ComputerSystem -ErrorAction Stop } catch { } $lines = @() $lines += '================================================================' $lines += ' Foton - Collection Record / Chain of Custody Header' $lines += '================================================================' $lines += '' $lines += "Case Number : $(if ($CaseNumber) { $CaseNumber } else { '(not supplied)' })" $lines += "Examiner : $Examiner" $lines += "Collection Tool : Foton v$($script:FotonSession.Version)" $lines += "Collection Type : Live (running system) logical collection" $lines += "Collection Start UTC : $($script:FotonSession.StartTimeUtc.ToString('yyyy-MM-dd HH:mm:ss'))" $lines += "Local Time At Start : $((Get-Date).ToString('yyyy-MM-dd HH:mm:ss'))" $lines += "System Time Zone : $($tz.Id) (UTC offset $($tz.GetUtcOffset((Get-Date))))" $lines += '' $lines += "Hostname : $env:COMPUTERNAME" $lines += "Domain / Workgroup : $(if ($cs) { $cs.Domain } else { 'unknown' })" $lines += "Manufacturer / Model : $(if ($cs) { "$($cs.Manufacturer) $($cs.Model)" } else { 'unknown' })" $lines += "Operating System : $(if ($os) { "$($os.Caption) $($os.Version) (build $($os.BuildNumber))" } else { 'unknown' })" $lines += "Last Boot UTC : $(if ($os) { $os.LastBootUpTime.ToUniversalTime().ToString('yyyy-MM-dd HH:mm:ss') } else { 'unknown' })" $lines += '' $lines += "Collection Account : $env:USERDOMAIN\$env:USERNAME" $lines += "Elevated (Admin) : $elevated" $lines += "Coverage Profile : $(if ($elevated) { 'Elevated' } else { 'StandardUser' })" $lines += "PowerShell Version : $($PSVersionTable.PSVersion.ToString())" $lines += "Script Path : $($MyInvocation.ScriptName)" $lines += '' $lines += 'Parameters Used:' $lines += " OutputPath = $OutputPath" $lines += " EventLogDays = $($script:FotonSession.EventLogDays)" $lines += " MaxEventsPerLog = $($script:FotonSession.MaxEventsPerLog)" $lines += " SkipEvtxExport = $($script:FotonSession.SkipEvtxExport)" $lines += " SkipHashing = $($script:FotonSession.SkipHashing)" $lines += " LoadUserHives = $LoadUserHives" $lines += " IncludeFileTimeline = $($script:FotonSession.IncludeFileTimeline)" $lines += " IncludeUsnJournal = $($script:FotonSession.IncludeUsnJournal)" $lines += " Deep = $($script:FotonSession.Deep)" $lines += " NoZip = $NoZip" $lines += " RequireAdministrator = $RequireAdministrator" $lines += '' $lines += '----------------------------------------------------------------' $lines += ' METHODOLOGY DISCLOSURE' $lines += '----------------------------------------------------------------' $lines += 'This was a LIVE collection. Executing this tool altered the target' $lines += 'system state: it created a process, wrote files to the output path,' $lines += 'generated event log entries, updated prefetch/AmCache, and read' $lines += 'registry keys (updating last-access metadata on some artifacts).' $lines += 'Volatile data (RAM, live network state) was captured only to the' $lines += 'extent listed in the manifest. No memory image and no disk image' $lines += 'were produced. If either is required, capture them before or' $lines += 'independently of this collection.' $lines += '' if ($elevated) { # Written before collection runs, so this states the method, not the outcome. $lines += 'Loaded registry hives (SYSTEM, SOFTWARE, DEFAULT, and signed-in users' $lines += 'NTUSER.DAT/UsrClass.dat) are exported with reg save. The export files' $lines += 'in the output path are the only writes; no key is modified. Whether each' $lines += 'export succeeded is recorded per file in registry_hives_machine.csv and' $lines += 'registry_hives_user.csv (Status Saved / SaveError) and in the manifest.' $lines += 'SAM and SECURITY are not collected by design (credential material).' $lines += '' } if ($LoadUserHives -and $elevated) { $lines += 'The -LoadUserHives option was used: NTUSER.DAT hives for users not' $lines += 'logged on were mounted into HKEY_USERS and unloaded at the end' $lines += 'of collection. This is a registry write operation on the target.' $lines += '' } elseif ($LoadUserHives -and -not $elevated) { $lines += 'The -LoadUserHives option was requested but ignored: mounting NTUSER.DAT' $lines += 'requires an elevated token. Per-user keys are limited to hives already loaded.' $lines += '' } if (-not $elevated) { $lines += 'Coverage profile STANDARD USER. This process was not elevated. The package' $lines += 'contains what the current token could read (typically the interactive user''s' $lines += 'processes, HKCU persistence, readable HKLM values, network snapshot, and that' $lines += 'user''s profile artifacts). The Security event log, Prefetch/Amcache/SRUM copies,' $lines += 'VSS listing, auditpol, secedit export, and other users'' files were not collected (see' $lines += 'collection_coverage.json and manifest Status=SkippedNotElevated). Absence of' $lines += 'those artifacts is a visibility gap, not evidence they were empty on the host.' $lines += '' } $lines += 'SHA-256 hashes for every collected artifact are recorded in' $lines += 'hashes.csv, produced after collection completed. Verify these hashes' $lines += 'on receipt and at each transfer. Record custody transfers below.' $lines += '' $lines += 'Transfer Log:' $lines += ' [Date/Time UTC] --- from ______________ to ______________ purpose ______________' $lines += ' [Date/Time UTC] --- from ______________ to ______________ purpose ______________' $lines += '' $file = Join-Path $script:FotonSession.Dirs['Collection'] 'chain_of_custody.txt' $lines | Out-File -FilePath $file -Encoding UTF8 } |