From e8b018d5c984c4277670029a645d03ae6081bb5d Mon Sep 17 00:00:00 2001 From: Shirofune-Security <43838376+Shirofune-Security@users.noreply.github.com> Date: Mon, 21 Sep 2026 17:56:45 +0900 Subject: [PATCH] Refuse ambiguous Windows path aliases during recovery --- scripts/FirewallLoggingRecovery.ps1 | 3 +++ tests/FirewallLoggingRecovery.Tests.ps1 | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/FirewallLoggingRecovery.ps1 b/scripts/FirewallLoggingRecovery.ps1 index 9db87b1e..b4b224bd 100644 --- a/scripts/FirewallLoggingRecovery.ps1 +++ b/scripts/FirewallLoggingRecovery.ps1 @@ -21,6 +21,9 @@ function Resolve-WelaFirewallRecoveryLogPath { # Only native Windows directory variables have reviewed meaning in old paths. $expanded=[regex]::Replace($Path,'(?i)%(systemroot|windir)%',[Text.RegularExpressions.MatchEvaluator]{param($m) [Environment]::GetFolderPath([Environment+SpecialFolder]::Windows)}) if($expanded -notmatch '^[A-Za-z]:\\' -or $expanded -match '%' -or $expanded.Substring(2).Contains(':') -or $expanded.EndsWith('\') -or $expanded.Contains('/')){throw 'UNC/device/relative paths, unknown variables and alternate streams are unsupported.'} + foreach($segment in $expanded.Substring(3).Split([char]'\')){ + if(-not $segment -or $segment -match '[ .]$' -or $segment -match '^(?i:CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(?:\.|$)'){throw 'Ambiguous path segments and Windows device aliases are unsupported.'} + } if([Environment]::OSVersion.Platform -eq [PlatformID]::Win32NT){$null=Resolve-WelaArrivalPath $expanded} $expanded } diff --git a/tests/FirewallLoggingRecovery.Tests.ps1 b/tests/FirewallLoggingRecovery.Tests.ps1 index 0d1ef01a..f63a160d 100644 --- a/tests/FirewallLoggingRecovery.Tests.ps1 +++ b/tests/FirewallLoggingRecovery.Tests.ps1 @@ -68,7 +68,7 @@ try { } foreach($bad in @('NotConfigured','true','1')){$v=Copy-Fixture $e.RecoverTo;$v.LogAllowed=$bad;Throws {ConvertTo-WelaFirewallRecoveryTuple $v} 'True/False'} foreach($bad in @('4096',0,32768,$true,1.5)){$v=Copy-Fixture $e.RecoverTo;$v.LogMaxSizeKilobytes=$bad;Throws {ConvertTo-WelaFirewallRecoveryTuple $v} 'integer'} - foreach($path in @('\\host\share\log','C:\Logs\..\other.log','C:\Logs\log:stream','C:\Logs\*.log','%TEMP%\log','C:relative.log','C:\Logs\')){Throws {Resolve-WelaFirewallRecoveryLogPath $path} 'path|unsupported|streams'} + foreach($path in @('\\host\share\log','C:\Logs\..\other.log','C:\Logs\log:stream','C:\Logs\*.log','%TEMP%\log','C:relative.log','C:\Logs\','C:\Logs\CON.log','C:\Logs\log.','C:\Logs\log ','C:\Logs\\log')){Throws {Resolve-WelaFirewallRecoveryLogPath $path} 'path|unsupported|streams'} $v=Copy-Fixture $e.RecoverTo;$v|Add-Member Extra 1;Throws {ConvertTo-WelaFirewallRecoveryTuple $v} 'Unexpected' foreach($change in @( {$script:row.Status='Failed'},{$script:entry.Target.PolicyStore='ActiveStore';$script:row.Target=Copy-Fixture $entry.Target},