mirror of
https://github.com/Yamato-Security/WELA.git
synced 2026-10-08 07:15:25 +02:00
Retain actual process identity for scoped logging and native attribution
This commit is contained in:
1 parent
e419b073fe
commit
adaf3f9681
4 files changed
+7
-5
No files matched your search
@@ -22,7 +22,7 @@
|
||||
-Auto -BackupPath C:\WELA-Recovery\new-run -ResultsPath new-result.json
|
||||
```
|
||||
|
||||
Use a native 64-bit Windows PowerShell 5.1 or PowerShell 7 host. The actual Windows role, build, patch and installed Windows PowerShell engine are read; caller role/build overrides are refused. Reviewed families are Windows 11 builds 22000, 22621, 22631, 26100 and 26200, and Server 2022/2025 builds 20348/26100. Native client, joined-member, DC and AD CS acceptance remains separate from hosted standalone-server tests. `Winmgmt` and `EventLog` must already run; the command starts no service. Configure requires elevation and a fresh recovery directory. Plan and Configure require explicit controls; there is no implicit enable-everything selection. Audit without selection inventories existing policy only.
|
||||
Use a native 64-bit Windows PowerShell 5.1 or PowerShell 7 host. The actual process SID, Windows role, build, patch and installed Windows PowerShell engine are read; impersonated callers are refused and caller role/build overrides are refused. Reviewed families are Windows 11 builds 22000, 22621, 22631, 26100 and 26200, and Server 2022/2025 builds 20348/26100. Native client, joined-member, DC and AD CS acceptance remains separate from hosted standalone-server tests. `Winmgmt` and `EventLog` must already run; the command starts no service. Configure requires elevation and a fresh recovery directory. Plan and Configure require explicit controls; there is no implicit enable-everything selection. Audit without selection inventories existing policy only.
|
||||
|
||||
The array examples are PowerShell syntax. When launching `powershell.exe -File` from another shell, use a reviewed PowerShell wrapper to bind multiple array elements correctly. Literal module names can contain ASCII letters, digits, dots, underscores and hyphens, up to 128 characters each. Up to 32 unique names can be selected. Paths and wildcard patterns are refused; the exact `*` value is accepted **only when explicitly supplied** to request all modules. Installation and execution of arbitrary selected modules are not performed or asserted.
|
||||
|
||||
|
||||
@@ -43,6 +43,8 @@ function Get-WelaPsLoggingSources {
|
||||
function Get-WelaPsLoggingSnapshot {
|
||||
if ($env:OS -ne 'Windows_NT' -or -not [Environment]::Is64BitProcess) {throw 'Use native 64-bit PowerShell on Windows.'}
|
||||
foreach($service in @('Winmgmt','EventLog')) {if((Get-Service -Name $service -ErrorAction Stop).Status -ne 'Running'){throw "$service must already be running; no service is started."}}
|
||||
$identity=[Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
try {if(-not $identity.User -or $identity.ImpersonationLevel -ne [Security.Principal.TokenImpersonationLevel]::None){throw 'An actual non-impersonated process identity is required.'};$operator=[pscustomobject]@{Sid=$identity.User.Value;ImpersonationLevel=[string]$identity.ImpersonationLevel}}finally{$identity.Dispose()}
|
||||
$os=Get-CimInstance Win32_OperatingSystem -Property BuildNumber,ProductType -ErrorAction Stop
|
||||
$computer=Get-CimInstance Win32_ComputerSystem -Property Name,Domain,DomainRole,PartOfDomain -ErrorAction Stop
|
||||
if ([string]$os.BuildNumber -notmatch '^\d+$' -or $computer.PartOfDomain -isnot [bool] -or $computer.DomainRole -notin @(0,1,2,3,4,5)) {throw 'Complete actual Windows role/build/join context is required.'}
|
||||
@@ -64,7 +66,7 @@ function Get-WelaPsLoggingSnapshot {
|
||||
try {$channel=Get-WinEvent -ListLog 'Microsoft-Windows-PowerShell/Operational' -ErrorAction Stop;$channelState=[pscustomobject]@{Name=[string]$channel.LogName;Enabled=[bool]$channel.IsEnabled;MaximumBytes=[long]$channel.MaximumSizeInBytes;Mode=[string]$channel.LogMode;Security=[string]$channel.SecurityDescriptor}}finally{if($channel -is [IDisposable]){$channel.Dispose()}}
|
||||
$patch=Get-WelaRegistryState 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' UBR
|
||||
if (-not $patch.ValueExists -or $patch.Type -ne 'DWord' -or $patch.Value -lt 0) {throw 'Exact native patch evidence is required.'}
|
||||
[pscustomobject][ordered]@{Host=[pscustomobject]@{Computer=[string]$computer.Name;Domain=[string]$computer.Domain;Build=$build;Patch=$patch.Value;ProductType=$product;DomainRole=$role;PartOfDomain=$joined;CertSvcPresent=[bool](Get-Service CertSvc -ErrorAction SilentlyContinue)};Engine=[pscustomobject]@{Target='Windows PowerShell 5.1';Version=$engine.Value;Path=$exe;Sha256=$engineHash;WelaHostVersion=$PSVersionTable.PSVersion.ToString()};Sources=@(Get-WelaPsLoggingSources);Machine=$machine;CurrentUser=$user;PowerShellCoreMachine=$coreMachine;PowerShellCoreUser=$coreUser;ProtectedEventLogging=$protected;Channel=$channelState}
|
||||
[pscustomobject][ordered]@{Operator=$operator;Host=[pscustomobject]@{Computer=[string]$computer.Name;Domain=[string]$computer.Domain;Build=$build;Patch=$patch.Value;ProductType=$product;DomainRole=$role;PartOfDomain=$joined;CertSvcPresent=[bool](Get-Service CertSvc -ErrorAction SilentlyContinue)};Engine=[pscustomobject]@{Target='Windows PowerShell 5.1';Version=$engine.Value;Path=$exe;Sha256=$engineHash;WelaHostVersion=$PSVersionTable.PSVersion.ToString()};Sources=@(Get-WelaPsLoggingSources);Machine=$machine;CurrentUser=$user;PowerShellCoreMachine=$coreMachine;PowerShellCoreUser=$coreUser;ProtectedEventLogging=$protected;Channel=$channelState}
|
||||
}
|
||||
function Get-WelaPsLoggingValue {
|
||||
param($Tree,[string]$Path,[string]$Name)
|
||||
|
||||
@@ -7,7 +7,7 @@ function Reject([scriptblock]$Action,[string]$Pattern){$message='';try{&$Action}
|
||||
function CloneFixture($Value){ConvertTo-WelaPsLoggingKey $Value|ConvertFrom-Json}
|
||||
function Row($Path,$Values=@(),$Children=@()){[pscustomobject]@{Path=$Path;Values=@($Values);Children=@($Children);Access='original-acl'}}
|
||||
function Fixture {
|
||||
[pscustomobject][ordered]@{Host=[pscustomobject]@{Computer='fixture';Build=20348};Engine=[pscustomobject]@{Target='Windows PowerShell 5.1'};Sources=@('sha');Machine=[pscustomobject]@{Exists=$true;Keys=@((Row '' @() @('ModuleLogging','ScriptBlockLogging','Transcription')),(Row 'ModuleLogging' @([pscustomobject]@{Name='EnableModuleLogging';Type='DWord';Value=0}) @('ModuleNames')),(Row 'ModuleLogging\ModuleNames' @([pscustomobject]@{Name='existing';Type='String';Value='Existing.Module'})),(Row 'ScriptBlockLogging' @([pscustomobject]@{Name='EnableScriptBlockLogging';Type='DWord';Value=0},[pscustomobject]@{Name='EnableScriptBlockInvocationLogging';Type='DWord';Value=1})),(Row 'Transcription' @([pscustomobject]@{Name='EnableTranscripting';Type='DWord';Value=1})))};CurrentUser=@('preserved-user');PowerShellCoreMachine=@('preserved-core');PowerShellCoreUser=@('preserved-core-user');ProtectedEventLogging=@('preserved-protected');Channel=@('preserved-channel')}
|
||||
[pscustomobject][ordered]@{Operator=[pscustomobject]@{Sid='S-1-5-21-1';ImpersonationLevel='None'};Host=[pscustomobject]@{Computer='fixture';Build=20348};Engine=[pscustomobject]@{Target='Windows PowerShell 5.1'};Sources=@('sha');Machine=[pscustomobject]@{Exists=$true;Keys=@((Row '' @() @('ModuleLogging','ScriptBlockLogging','Transcription')),(Row 'ModuleLogging' @([pscustomobject]@{Name='EnableModuleLogging';Type='DWord';Value=0}) @('ModuleNames')),(Row 'ModuleLogging\ModuleNames' @([pscustomobject]@{Name='existing';Type='String';Value='Existing.Module'})),(Row 'ScriptBlockLogging' @([pscustomobject]@{Name='EnableScriptBlockLogging';Type='DWord';Value=0},[pscustomobject]@{Name='EnableScriptBlockInvocationLogging';Type='DWord';Value=1})),(Row 'Transcription' @([pscustomobject]@{Name='EnableTranscripting';Type='DWord';Value=1})))};CurrentUser=@('preserved-user');PowerShellCoreMachine=@('preserved-core');PowerShellCoreUser=@('preserved-core-user');ProtectedEventLogging=@('preserved-protected');Channel=@('preserved-channel')}
|
||||
}
|
||||
function Mutate($Before,$Definition){
|
||||
$after=CloneFixture $Before;$after.Machine.Exists=$true
|
||||
@@ -61,7 +61,7 @@ try {
|
||||
Reset;$script:corrupt=$true;$failed=Invoke-WelaPowerShellLogging -Action Configure -Control Module,ScriptBlock -ModuleName Microsoft.PowerShell.Utility -Auto -BackupPath (Join-Path $root 'corrupt')
|
||||
Assert ($failed.ExitCode -eq 1 -and $script:writes -eq 1) 'Preservation failure stops later writes'
|
||||
Reset;$snapshot=CloneFixture $script:observed;$definition=$definitions[0];$after=Mutate $snapshot $definition;Assert-WelaPsLoggingTransition $snapshot $after $definition;Assert $true 'Exact additive transition accepted'
|
||||
foreach($property in @('Host','Sources','CurrentUser','PowerShellCoreMachine','PowerShellCoreUser','ProtectedEventLogging','Channel')){$changed=CloneFixture $after;$changed.$property='drift';Reject {Assert-WelaPsLoggingTransition $snapshot $changed $definition} 'Unselected state'}
|
||||
foreach($property in @('Operator','Host','Sources','CurrentUser','PowerShellCoreMachine','PowerShellCoreUser','ProtectedEventLogging','Channel')){$changed=CloneFixture $after;$changed.$property='drift';Reject {Assert-WelaPsLoggingTransition $snapshot $changed $definition} 'Unselected state'}
|
||||
$changed=CloneFixture $after;$changed.Machine.Keys[0].Access='new-acl';Reject {Assert-WelaPsLoggingTransition $snapshot $changed $definition} 'descriptor'
|
||||
$changed=CloneFixture $after;$changed.Machine.Keys=@($changed.Machine.Keys|Where-Object Path -ne Transcription);Reject {Assert-WelaPsLoggingTransition $snapshot $changed $definition} 'disappeared'
|
||||
$changed=CloneFixture $after;$changed.Machine.Keys+=Row 'extra';Reject {Assert-WelaPsLoggingTransition $snapshot $changed $definition} 'unrequested'
|
||||
|
||||
@@ -111,7 +111,7 @@ try{
|
||||
$id=[int]$system.SelectSingleNode('e:EventID',$ns).InnerText
|
||||
if($system.SelectSingleNode('e:Provider',$ns).GetAttribute('Name') -cne 'Microsoft-Windows-PowerShell' -or $system.SelectSingleNode('e:Provider',$ns).GetAttribute('Guid').Trim('{}') -ine 'a0c1853b-5c40-4b15-8766-3cf1c58f985a' -or [int]$system.SelectSingleNode('e:Execution',$ns).GetAttribute('ProcessID') -ne $process.Pid -or $system.SelectSingleNode('e:Channel',$ns).InnerText -cne 'Microsoft-Windows-PowerShell/Operational' -or $system.SelectSingleNode('e:Computer',$ns).InnerText -ine $env:COMPUTERNAME){continue}
|
||||
$time=[DateTimeOffset]::Parse($system.SelectSingleNode('e:TimeCreated',$ns).GetAttribute('SystemTime')).UtcDateTime;if($time -lt [DateTimeOffset]::Parse($process.StartedUtc).UtcDateTime -or $time -gt [DateTimeOffset]::Parse($process.ExitedUtc).UtcDateTime){continue}
|
||||
if($system.SelectSingleNode('e:Security',$ns).GetAttribute('UserID') -cne [Security.Principal.WindowsIdentity]::GetCurrent().User.Value){continue}
|
||||
if($system.SelectSingleNode('e:Security',$ns).GetAttribute('UserID') -cne $original.Operator.Sid){continue}
|
||||
if($id -eq 4104 -and $data.ScriptBlockText -ceq $workerText -and $data.Path -ieq $workerPath -and $data.MessageNumber -ceq '1' -and $data.MessageTotal -ceq '1' -and $data.ScriptBlockId -match '^[0-9a-f-]{36}$'){$selected['4104']=@($selected['4104'])+ $xml}
|
||||
if($id -eq 4103 -and $data.ContainsKey('Payload') -and $data.ContainsKey('ContextInfo') -and $data.Payload.Contains($nonce) -and $data.ContextInfo.Contains($workerPath)){$selected['4103']=@($selected['4103'])+ $xml}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user