mirror of
https://github.com/Yamato-Security/WELA.git
synced 2026-10-07 23:14:45 +02:00
test: bound token attribution worker and retain independent cleanup evidence
This commit is contained in:
1 parent
5bebb9a7a5
commit
495f12a30f
1 file changed
+34
-7
@@ -14,6 +14,31 @@ $guid='0CCE924A-69AE-11D9-BED3-505054503030';$auth='0CCE9231-69AE-11D9-BED3-5050
|
||||
$path='HKLM:\SYSTEM\CurrentControlSet\Control\Lsa';$name='SCENoApplyLegacyAuditPolicy'
|
||||
$beforeMasks=Get-WelaEffectiveAuditPolicy;$masks=Masks;$beforePrecedence=Get-WelaRegistryState $path $name;$beforeToken=[Wela.WmiProbe.Native]::Snapshot();$failure=$null;$errors=@()
|
||||
Save 'original.json' @{Masks=$beforeMasks;Precedence=$beforePrecedence;Token=$beforeToken;Head=$env:GITHUB_SHA;Engine=$PSVersionTable.PSVersion.ToString()}
|
||||
Add-Type -TypeDefinition @'
|
||||
using System;using System.IO;using System.Text;using System.Threading.Tasks;
|
||||
public static class WelaTokenFixturePipe {
|
||||
public static async Task<string> Read(TextReader reader) {
|
||||
var text=new StringBuilder();var buffer=new char[2048];while(true){int n=await reader.ReadAsync(buffer,0,buffer.Length).ConfigureAwait(false);if(n==0)return text.ToString();if(n>1048576-text.Length)throw new InvalidDataException("Fixture output exceeded one Mi characters.");text.Append(buffer,0,n);}
|
||||
}
|
||||
}
|
||||
'@
|
||||
function Worker([string]$Phase,[string]$Receipt){
|
||||
$all=@('-NoLogo','-NoProfile','-NonInteractive','-File',$worker,$repo,$Receipt)
|
||||
foreach($a in $all){if($a.Contains('"') -or $a.EndsWith('\') -or $a -match '[\x00-\x1f]'){throw 'Ambiguous fixture argument.'}}
|
||||
$info=[Diagnostics.ProcessStartInfo]::new();$info.FileName=(Get-Process -Id $PID).Path;$info.Arguments=(@($all|ForEach-Object{'"'+$_+'"'}) -join ' ');$info.UseShellExecute=$false;$info.CreateNoWindow=$true;$info.RedirectStandardOutput=$true;$info.RedirectStandardError=$true
|
||||
$process=[Diagnostics.Process]::new();$process.StartInfo=$info;$started=$false
|
||||
try{
|
||||
if(-not $process.Start()){throw 'Owned worker did not start.'};$started=$true
|
||||
$stdout=[WelaTokenFixturePipe]::Read($process.StandardOutput);$stderr=[WelaTokenFixturePipe]::Read($process.StandardError)
|
||||
if(-not $process.WaitForExit(90000)){throw 'Owned worker exceeded90seconds.'}
|
||||
if(-not [Threading.Tasks.Task]::WaitAll([Threading.Tasks.Task[]]@($stdout,$stderr),5000)){throw 'Owned worker drain exceeded5seconds.'}
|
||||
[IO.File]::WriteAllText((Join-Path $root ($Phase+'-worker.txt')),$stdout.Result+"`n"+$stderr.Result)
|
||||
if($process.ExitCode -ne 0){throw 'Owned native worker failed; see retained output.'}
|
||||
}finally{
|
||||
if($started){$exited=$false;try{$exited=$process.HasExited}catch{$script:errors+=$_.ToString()};if(-not $exited){try{$process.Kill()}catch{$script:errors+=$_.ToString()};try{$exited=$process.WaitForExit(5000)}catch{$script:errors+=$_.ToString()}};if(-not $exited){$script:errors+='Owned worker termination unconfirmed.'}}
|
||||
try{$process.Dispose()}catch{$script:errors+=$_.ToString()}
|
||||
}
|
||||
}
|
||||
$worker=Join-Path $root 'worker.ps1';$receipt=Join-Path $root 'worker.json'
|
||||
@'
|
||||
param($Repo,$Result)
|
||||
@@ -39,9 +64,7 @@ try{
|
||||
foreach($entry in $beforeMasks.Keys){$expected=$beforeMasks[$entry];if($entry -eq $guid){$expected=$phase.Token};if($entry -eq $auth){$expected=$phase.Authorization};if($prepared[$entry] -ne $expected){throw 'Prepared native policy differs from the exact selected two-mask change.'}}
|
||||
Save ($phase.Name+'-prepared.json') @{Phase=$phase;Masks=$prepared;Precedence=Get-WelaRegistryState $path $name}
|
||||
$receipt=Join-Path $root ($phase.Name+'-worker.json')
|
||||
$engine=(Get-Process -Id $PID).Path
|
||||
& $engine -NoLogo -NoProfile -NonInteractive -File $worker $repo $receipt
|
||||
if($LASTEXITCODE -ne 0){throw 'Native worker failed.'}
|
||||
Worker $phase.Name $receipt
|
||||
$result=Get-Content -Raw $receipt|ConvertFrom-Json
|
||||
$exactStart=[DateTime]::FromFileTimeUtc($result.Outcome.DisableStartedFileTime);$exactEnd=[DateTime]::FromFileTimeUtc($result.Outcome.RestoreReturnedFileTime)
|
||||
$start=$exactStart.AddSeconds(-2);$end=$exactEnd.AddSeconds(2)
|
||||
@@ -52,8 +75,9 @@ try{
|
||||
try{
|
||||
$nativeQuery=[System.Diagnostics.Eventing.Reader.EventLogQuery]::new('Security',[System.Diagnostics.Eventing.Reader.PathType]::LogName,$query)
|
||||
$reader=[System.Diagnostics.Eventing.Reader.EventLogReader]::new($nativeQuery)
|
||||
$statuses=@($reader.LogStatus);if($statuses.Count -ne 1 -or $statuses[0].LogName -cne 'Security' -or $statuses[0].StatusCode -ne 0){throw 'Native query lacks exactly one successful Security channel status.'}
|
||||
$count=0
|
||||
while($null -ne ($event=$reader.ReadEvent())){
|
||||
while($null -ne ($event=$reader.ReadEvent([TimeSpan]::FromSeconds(2)))){
|
||||
try{
|
||||
$count++;if($count -gt 512){throw 'Diagnostic candidate count exceeded512.'}
|
||||
$raw=$event.ToXml();if($raw.Length -gt 65536){throw 'Candidate XML exceeded64Ki characters.'}
|
||||
@@ -82,9 +106,12 @@ try{
|
||||
}catch{$failure=$_.ToString();throw}finally{
|
||||
foreach($restoreGuid in @($guid,$auth)){try{Set-WelaEffectiveAuditPolicy -Guid $restoreGuid -Mask $beforeMasks[$restoreGuid] -Mode exact}catch{$errors+=$_.ToString()}}
|
||||
try{if($beforePrecedence.ValueExists){Set-ItemProperty -LiteralPath $path -Name $name -Value $beforePrecedence.Value -Type $beforePrecedence.Type}else{Remove-ItemProperty -LiteralPath $path -Name $name -ErrorAction Stop}}catch{$errors+=$_.ToString()}
|
||||
$afterToken=[Wela.WmiProbe.Native]::Snapshot();$afterPrecedence=Get-WelaRegistryState $path $name
|
||||
$complete=$errors.Count -eq 0 -and (Masks) -ceq $masks -and (Key $afterPrecedence) -ceq (Key $beforePrecedence) -and ((Key $beforeToken) -ceq (Key $afterToken))
|
||||
Save 'cleanup.json' @{Complete=$complete;Errors=$errors;Failure=$failure;AfterToken=$afterToken;AfterMasks=Get-WelaEffectiveAuditPolicy;AfterPrecedence=$afterPrecedence}
|
||||
$afterToken=$null;$afterPrecedence=$null;$afterMasks=$null;$afterMaskKey=$null
|
||||
try{$afterToken=[Wela.WmiProbe.Native]::Snapshot()}catch{$errors+=$_.ToString()}
|
||||
try{$afterPrecedence=Get-WelaRegistryState $path $name}catch{$errors+=$_.ToString()}
|
||||
try{$afterMasks=Get-WelaEffectiveAuditPolicy;$afterMaskKey=@($afterMasks.Keys|Sort-Object|ForEach-Object{"$_=$($afterMasks[$_])"}) -join ';'}catch{$errors+=$_.ToString()}
|
||||
$complete=$errors.Count -eq 0 -and $afterMaskKey -ceq $masks -and (Key $afterPrecedence) -ceq (Key $beforePrecedence) -and ((Key $beforeToken) -ceq (Key $afterToken))
|
||||
Save 'cleanup.json' @{Complete=$complete;Errors=$errors;Failure=$failure;AfterToken=$afterToken;AfterMasks=$afterMasks;AfterPrecedence=$afterPrecedence}
|
||||
if(-not $complete){throw 'Native feasibility fixture cleanup failed.'}
|
||||
}
|
||||
$global:LASTEXITCODE=0
|
||||
Reference in new issue
Block a user