mirror of
https://github.com/Yamato-Security/WELA.git
synced 2026-10-01 03:54:44 +02:00
57 lines
5.8 KiB
PowerShell
57 lines
5.8 KiB
PowerShell
# Test-only strict correlation. This helper never changes WELA scoring or policy.
|
|
function Get-WelaTokenAttributionMatch {
|
|
param([string]$Text,$Context)
|
|
if($Text.Length -gt 65536){throw 'Event XML exceeds the fixture bound.'}
|
|
$settings=[Xml.XmlReaderSettings]::new();$settings.DtdProcessing=[Xml.DtdProcessing]::Prohibit;$settings.XmlResolver=$null;$settings.MaxCharactersInDocument=65536
|
|
$reader=[Xml.XmlReader]::Create([IO.StringReader]::new($Text),$settings);$xml=[Xml.XmlDocument]::new();$xml.XmlResolver=$null
|
|
try{$xml.Load($reader)}finally{$reader.Dispose()}
|
|
$ns=[Xml.XmlNamespaceManager]::new($xml.NameTable);$ns.AddNamespace('e','http://schemas.microsoft.com/win/2004/08/events/event')
|
|
if($xml.DocumentElement.LocalName -cne 'Event' -or $xml.DocumentElement.NamespaceURI -cne $ns.LookupNamespace('e') -or $xml.SelectNodes('/e:Event/e:System',$ns).Count -ne 1 -or $xml.SelectNodes('/e:Event/e:EventData',$ns).Count -ne 1){return $null}
|
|
$system=$xml.SelectSingleNode('/e:Event/e:System',$ns)
|
|
foreach($field in @('Provider','EventID','Version','Level','Task','Opcode','Keywords','TimeCreated','EventRecordID','Channel','Computer')){if($system.SelectNodes('e:'+$field,$ns).Count -ne 1){return $null}}
|
|
$p=$system.SelectSingleNode('e:Provider',$ns)
|
|
if($p.GetAttribute('Name') -cne 'Microsoft-Windows-Security-Auditing' -or $p.GetAttribute('Guid') -ine '{54849625-5478-4994-a5ba-3e3b0328c30d}'){return $null}
|
|
foreach($pair in @(@('EventID','4703'),@('Version','0'),@('Level','0'),@('Opcode','0'),@('Task',[string]$Context.Task),@('Keywords','0x8020000000000000'),@('Channel','Security'))){if($system.SelectSingleNode('e:'+$pair[0],$ns).InnerText -cne $pair[1]){return $null}}
|
|
if(@($Context.Computers|Where-Object{$_ -ieq $system.SelectSingleNode('e:Computer',$ns).InnerText}).Count -ne 1){return $null}
|
|
$record=0L;if(-not[long]::TryParse($system.SelectSingleNode('e:EventRecordID',$ns).InnerText,[ref]$record) -or $record -le $Context.Watermark){return $null}
|
|
$data=@{};$fields=$xml.SelectNodes('/e:Event/e:EventData/e:Data',$ns)
|
|
foreach($node in $fields){$name=$node.GetAttribute('Name');if(-not $name -or $data.ContainsKey($name)){return $null};$data[$name]=$node.InnerText}
|
|
foreach($field in @('SubjectUserSid','SubjectLogonId','TargetUserSid','TargetLogonId','ProcessName','ProcessId','EnabledPrivilegeList','DisabledPrivilegeList')){if(-not $data.ContainsKey($field)){return $null}}
|
|
if($data.SubjectUserSid -cne $Context.Sid -or $data.TargetUserSid -cne $Context.Sid -or $data.SubjectLogonId -ine $Context.AuthenticationId -or $data.TargetLogonId -ine $Context.AuthenticationId -or $data.ProcessName -ine $Context.ProcessName){return $null}
|
|
if($data.ProcessId -cnotmatch '^0x[0-9a-fA-F]+$' -or [Convert]::ToUInt64($data.ProcessId.Substring(2),16) -ne [uint64]$Context.ProcessId){return $null}
|
|
$direction=$null
|
|
if($data.DisabledPrivilegeList -ceq 'SeDebugPrivilege' -and $data.EnabledPrivilegeList -ceq '-'){$direction='Disable'}
|
|
if($data.EnabledPrivilegeList -ceq 'SeDebugPrivilege' -and $data.DisabledPrivilegeList -ceq '-'){$direction='Restore'}
|
|
if(-not $direction){return $null}
|
|
$textTime=$system.SelectSingleNode('e:TimeCreated',$ns).GetAttribute('SystemTime');if($textTime -cnotmatch '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,7})?Z$'){return $null}
|
|
$time=[DateTime]::Parse($textTime,[Globalization.CultureInfo]::InvariantCulture,[Globalization.DateTimeStyles]::RoundtripKind).ToFileTimeUtc()
|
|
if($time -lt $Context.DisableStartedFileTime -or $time -gt $Context.OperationCompletedFileTime){return $null}
|
|
[pscustomobject]@{RecordId=$record;Direction=$direction;Utc=$textTime;Data=$data}
|
|
}
|
|
function Assert-WelaTokenAttributionTimes {
|
|
param($Operation,[long]$Launched,[long]$Observed)
|
|
$previous=$Launched
|
|
foreach($name in @('DisableStartedFileTime','DisableReturnedFileTime','RestoreStartedFileTime','RestoreReturnedFileTime','PrivilegeVerificationCompletedFileTime','OperationCompletedFileTime')){
|
|
$value=$Operation.$name
|
|
if(($value -isnot [long] -and $value -isnot [int]) -or $value -le 0 -or $value -lt $previous -or $value -gt $Observed){throw 'Native operation timestamps must be typed, monotonic and within parent observations.'}
|
|
$previous=$value
|
|
}
|
|
if($Launched -gt $Observed -or ($Observed-$Launched) -gt 950000000){throw 'Parent operation envelope exceeds its bounded worker lifetime.'}
|
|
}
|
|
function Get-WelaTokenAttributionTask {
|
|
param($Definitions,[string]$PublisherXml)
|
|
$name='SE_ADT_DETAILEDTRACKING_TOKENRIGHTADJ'
|
|
$rows=@($Definitions|Where-Object{$_.Name -is [string] -and $_.Name -ceq $name})
|
|
if($rows.Count -ne 1 -or $rows[0].Value -isnot [int] -or $rows[0].Value -ne 13317){throw 'The independently installed token-right task definition is absent or differs.'}
|
|
if($PublisherXml.Length -gt 4194304){throw 'Publisher XML exceeds its fixture bound.'}
|
|
$settings=[Xml.XmlReaderSettings]::new();$settings.DtdProcessing=[Xml.DtdProcessing]::Prohibit;$settings.XmlResolver=$null;$settings.MaxCharactersInDocument=4194304
|
|
$reader=[Xml.XmlReader]::Create([IO.StringReader]::new($PublisherXml),$settings);$xml=[Xml.XmlDocument]::new();$xml.XmlResolver=$null
|
|
try{$xml.Load($reader)}finally{$reader.Dispose()}
|
|
$root=$xml.DocumentElement
|
|
if($root.LocalName -cne 'provider' -or $root.NamespaceURI -cne 'http://schemas.microsoft.com/win/2004/08/events' -or $root.GetAttribute('name') -cne 'Microsoft-Windows-Security-Auditing' -or $root.GetAttribute('guid') -ine '54849625-5478-4994-a5ba-3e3b0328c30d'){throw 'Native publisher identity differs.'}
|
|
$ns=[Xml.XmlNamespaceManager]::new($xml.NameTable);$ns.AddNamespace('p','http://schemas.microsoft.com/win/2004/08/events')
|
|
$tasks=@($root.SelectNodes('p:tasks/p:task',$ns)|Where-Object{$_.GetAttribute('name') -ceq $name})
|
|
if($tasks.Count -ne 1 -or $tasks[0].GetAttribute('value') -cne '13317'){throw 'Native publisher XML does not corroborate the fixed token-right task.'}
|
|
13317
|
|
}
|