From 83ab9c875239d426f26f93e283122f635b27cbce Mon Sep 17 00:00:00 2001 From: Shirofune-Security <43838376+Shirofune-Security@users.noreply.github.com> Date: Mon, 21 Sep 2026 18:15:02 +0900 Subject: [PATCH] Require running firewall providers before recovery observations --- docs/firewall-logging-recovery.md | 2 +- scripts/FirewallLoggingRecovery.ps1 | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/firewall-logging-recovery.md b/docs/firewall-logging-recovery.md index 4dfcaba8..370b57ba 100644 --- a/docs/firewall-logging-recovery.md +++ b/docs/firewall-logging-recovery.md @@ -8,7 +8,7 @@ The restored fields are `LogAllowed`, `LogBlocked`, `LogMaxSizeKilobytes` and `L Keep the genuine original `before.jsonl` and final results from [firewall logging configuration](firewall-logging.md). The selected row must have final status `Applied`, dedicated scope `firewall-text-logging-only`, a matching version-1 journal entry and matching original Before/Desired/Target values. Failed, partial, ambiguous and no-op operations are not automatically recoverable. -Use elevated native 64-bit Windows PowerShell 5.1 or PowerShell 7 on reviewed Windows 11 builds 22000/22621/22631/26100/26200 or Server 2022/2025 builds 20348/26100. The plan and restoration must use the same engine version, machine identity and actual elevated operator/logon context. Impersonation is refused. Original version-1 configuration journals recorded only the computer name, so they do **not** prove historical MachineGuid or operator identity. The operator must establish that the original evidence belongs to this installation; current identity binding starts with the recovery plan. +Use elevated native 64-bit Windows PowerShell 5.1 or PowerShell 7 on reviewed Windows 11 builds 22000/22621/22631/26100/26200 or Server 2022/2025 builds 20348/26100. Winmgmt, MpsSvc and BFE must already be running before native provider reads. The plan and restoration must use the same engine version, machine identity and actual elevated operator/logon context. Impersonation is refused. Original version-1 configuration journals recorded only the computer name, so they do **not** prove historical MachineGuid or operator identity. The operator must establish that the original evidence belongs to this installation; current identity binding starts with the recovery plan. Create new local output directories under an existing parent, outside the WELA source tree. WELA applies private output permissions and never overwrites an old evidence directory. diff --git a/scripts/FirewallLoggingRecovery.ps1 b/scripts/FirewallLoggingRecovery.ps1 index ae70db7b..06926410 100644 --- a/scripts/FirewallLoggingRecovery.ps1 +++ b/scripts/FirewallLoggingRecovery.ps1 @@ -39,6 +39,10 @@ function Get-WelaFirewallRecoverySources { function Get-WelaFirewallRecoveryContext { $reader=Get-WelaChannelReader if(-not $reader.ElevatedAdministrator){throw 'Firewall recovery requires the actual non-impersonated elevated administrator.'} + # Observe service state before connecting to native WMI/NetSecurity providers. + # A read must not be used to start prerequisites implicitly. + $services=@(Get-Service -Name Winmgmt,MpsSvc,BFE -ErrorAction Stop | Sort-Object Name | ForEach-Object {[pscustomobject]@{Name=$_.Name;Status=[string]$_.Status}}) + if($services.Count -ne 3 -or @($services | Where-Object Status -cne 'Running').Count){throw 'Winmgmt, MpsSvc and BFE must already be running; recovery starts no services.'} $os=Get-CimInstance Win32_OperatingSystem -ErrorAction Stop $computer=Get-CimInstance Win32_ComputerSystem -ErrorAction Stop $build=[int]$os.BuildNumber @@ -48,7 +52,7 @@ function Get-WelaFirewallRecoveryContext { $guid=[guid]::Empty if(-not $machine.ValueExists -or $machine.Type -cne 'String' -or -not [guid]::TryParse([string]$machine.Value,[ref]$guid) -or $guid -eq [guid]::Empty){throw 'Actual machine identity is unavailable.'} $revision=Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name UBR -ErrorAction Stop - [pscustomobject][ordered]@{Computer=[Environment]::MachineName;MachineGuid=$guid.ToString();Build=$build;UBR=$revision.UBR;ProductType=[int]$os.ProductType;DomainRole=[int]$computer.DomainRole;Domain=[string]$computer.Domain;DomainJoined=[bool]$computer.PartOfDomain + [pscustomobject][ordered]@{Computer=[Environment]::MachineName;MachineGuid=$guid.ToString();Build=$build;UBR=$revision.UBR;ProductType=[int]$os.ProductType;DomainRole=[int]$computer.DomainRole;Domain=[string]$computer.Domain;DomainJoined=[bool]$computer.PartOfDomain;Services=$services Reader=[pscustomobject]@{UserSid=$reader.UserSid;UserName=$reader.UserName;AuthenticationId=$reader.AuthenticationId;GroupSids=$reader.GroupSids;ElevatedAdministrator=$reader.ElevatedAdministrator;Impersonation=$reader.Impersonation} Engine=$PSVersionTable.PSVersion.ToString()} }