mirror of
https://github.com/Yamato-Security/WELA.git
synced 2026-09-29 18:44:31 +02:00
* Add opt-in native 4688 validation component collector * Link native validation changelog to PR 413 * Reject contradictory native probe context observations * Resolve probe artifact paths against the PowerShell location
63 lines
4.5 KiB
PowerShell
63 lines
4.5 KiB
PowerShell
param([switch]$AllowDisposablePolicyWrite)
|
|
$ErrorActionPreference='Stop'
|
|
if ($env:OS -ne 'Windows_NT') { Write-Host 'Skipped: native Windows is required.'; exit 0 }
|
|
if (-not $AllowDisposablePolicyWrite -or $env:GITHUB_ACTIONS -ne 'true' -or $env:RUNNER_ENVIRONMENT -ne 'github-hosted') { throw 'This native event test requires explicit policy-write opt-in on a disposable GitHub-hosted runner.' }
|
|
$repo=Split-Path $PSScriptRoot -Parent
|
|
. (Join-Path $repo 'scripts/Configuration.ps1')
|
|
. (Join-Path $repo 'scripts/ControlApplicability.ps1')
|
|
. (Join-Path $repo 'scripts/NativeValidation.ps1')
|
|
Import-Module (Join-Path $repo 'modules/AuditProfiles.psm1') -Force
|
|
$guid='0cce922b-69ae-11d9-bed3-505054503030'
|
|
$controls=@(
|
|
[pscustomobject]@{Path='HKLM:\SYSTEM\CurrentControlSet\Control\Lsa';Name='SCENoApplyLegacyAuditPolicy'},
|
|
[pscustomobject]@{Path='HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit';Name='ProcessCreationIncludeCmdLine_Enabled'}
|
|
)
|
|
$beforeMask=(Get-WelaEffectiveAuditPolicy)[$guid]
|
|
foreach ($control in $controls) { $control | Add-Member NoteProperty Before (Get-WelaRegistryState -Path $control.Path -Name $control.Name) }
|
|
$root=Join-Path ([IO.Path]::GetTempPath()) ('wela-native-4688-'+[guid]::NewGuid().ToString('N'))
|
|
$null=New-Item -ItemType Directory -Path $root
|
|
$receipt=Join-Path $root 'policy-before.json'
|
|
[pscustomobject]@{AuditMask=$beforeMask;Controls=$controls} | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath $receipt -Encoding UTF8
|
|
$touched=$false; $restored=$false
|
|
try {
|
|
$touched=$true
|
|
foreach ($control in $controls) {
|
|
if (-not (Test-Path -LiteralPath $control.Path)) { $null=New-WelaRegistryKey -Path $control.Path }
|
|
$null=New-ItemProperty -LiteralPath $control.Path -Name $control.Name -Value 1 -PropertyType DWord -Force
|
|
}
|
|
Set-WelaEffectiveAuditPolicy -Guid $guid -Mask 1 -Mode minimum
|
|
$destination=Join-Path $root 'collection'
|
|
$result=Invoke-WelaNativeValidation -Action Run -OutputPath $destination -TimeoutSeconds 30
|
|
if ($result.ExitCode -ne 0 -or $result.Status -ne 'NativeEventObserved') { throw ($result | ConvertTo-Json -Depth 20) }
|
|
if ($result.ReadyRuleCredit -ne 0 -or $result.Artifacts.Count -ne 4) { throw 'Collector mislabeled incomplete evidence.' }
|
|
foreach ($artifact in $result.Artifacts) {
|
|
if ((Get-FileHash -LiteralPath (Join-Path $destination $artifact.path)).Hash.ToLowerInvariant() -cne $artifact.sha256) { throw 'Native artifact hash mismatch.' }
|
|
}
|
|
$event=[IO.File]::ReadAllText((Join-Path $destination 'event.xml'))
|
|
if (-not (Test-WelaProbeEvent $event $result.Process $result.BeforeState ([DateTime]::UtcNow))) { throw 'Native event cannot be independently matched.' }
|
|
Write-Host "Native 4688 event observed on $($result.BeforeState.context.role) $($result.BeforeState.context.patch) under PowerShell $($PSVersionTable.PSVersion). Complete-rule, backend and other-role validation remain pending."
|
|
} finally {
|
|
if ($touched) {
|
|
$errors=@()
|
|
try { Set-WelaEffectiveAuditPolicy -Guid $guid -Mask $beforeMask -Mode exact } catch { $errors+=$_.Exception.Message }
|
|
foreach ($control in $controls) {
|
|
try {
|
|
if ($control.Before.ValueExists) { $null=New-ItemProperty -LiteralPath $control.Path -Name $control.Name -Value $control.Before.Value -PropertyType $control.Before.Type -Force }
|
|
else { Remove-ItemProperty -LiteralPath $control.Path -Name $control.Name -ErrorAction SilentlyContinue }
|
|
if (-not $control.Before.KeyExists -and (Test-Path -LiteralPath $control.Path)) {
|
|
$key=Get-Item -LiteralPath $control.Path
|
|
if ($key.ValueCount -eq 0 -and $key.SubKeyCount -eq 0) { Remove-Item -LiteralPath $control.Path -ErrorAction Stop }
|
|
}
|
|
$after=Get-WelaRegistryState -Path $control.Path -Name $control.Name
|
|
if (($after | ConvertTo-Json -Compress) -cne ($control.Before | ConvertTo-Json -Compress)) { throw "Registry restoration differs: $($control.Name)" }
|
|
} catch { $errors+=$_.Exception.Message }
|
|
}
|
|
try { if ((Get-WelaEffectiveAuditPolicy)[$guid] -ne $beforeMask) { throw 'Audit mask restoration differs.' } } catch { $errors+=$_.Exception.Message }
|
|
$restored=$errors.Count -eq 0
|
|
if (-not $restored) { throw "Policy restoration failed; receipt retained at $receipt : $($errors -join '; ')" }
|
|
}
|
|
if ($restored) { Remove-Item -LiteralPath $root -Recurse -Force }
|
|
}
|
|
$global:LASTEXITCODE=0
|
|
Write-Host 'Native 4688 collection and exact policy restoration passed.'
|