Public/Invoke-TripwireAnalysis.ps1
|
<# .SYNOPSIS Correlate a set of touches into actors, then score every touch. .DESCRIPTION Fan-out is the only signal that cannot be computed from a single touch, so it is computed here, over the whole set, before anything is scored. The correlation is per actor and per sliding window: for each touch, count the DISTINCT decoys the same actor touched within CorrelationWindowMinutes either side. Distinct decoys, never events -- an attacker retrying one decoy fifty times must not look like a sweep across fifty decoys. Touches whose actor cannot be identified at all (no directory object id, no source address) are never correlated with anything. Bucketing anonymous events together would manufacture fan-out out of unrelated noise, and fan-out is what carries a trip into the band where containment becomes eligible. .PARAMETER Touch Normalised touches from Watch-TripwireActivity. .PARAMETER Decoy The decoy inventory. .PARAMETER Baseline Tenant baseline. Optional; without it the affected signals are withheld. .PARAMETER Policy Scoring policy. Defaults to Get-TripwirePolicy. .EXAMPLE Invoke-TripwireAnalysis -Touch $touches -Decoy (Get-TripwireDecoy) -Baseline (Get-TripwireBaseline) | Sort-Object Confidence -Descending | Format-Table Confidence, Band, DecoyName, ActorLabel #> function Invoke-TripwireAnalysis { [CmdletBinding()] [OutputType([pscustomobject])] param( [Parameter(Mandatory)] [AllowEmptyCollection()] [object[]] $Touch, [AllowEmptyCollection()] [object[]] $Decoy = @(), [AllowNull()] $Baseline, $Policy ) if (-not $Policy) { $Policy = Get-TripwirePolicy } $decoyById = @{} foreach ($d in $Decoy) { $decoyById[[string]$d.id] = $d } $window = [TimeSpan]::FromMinutes($Policy.CorrelationWindowMinutes) # Group by actor once; anonymous touches get a unique key each so they group alone. $byActor = @{} $anonymous = 0 foreach ($t in $Touch) { $key = Get-TripwireActorKey -Touch $t if ($null -eq $key) { $anonymous++ $key = "anon:$anonymous" } if (-not $byActor.ContainsKey($key)) { $byActor[$key] = [System.Collections.Generic.List[object]]::new() } $byActor[$key].Add($t) } foreach ($t in $Touch) { $key = Get-TripwireActorKey -Touch $t $distinct = 1 if ($null -ne $key -and $byActor.ContainsKey($key)) { $near = @($byActor[$key] | Where-Object { [Math]::Abs(((ConvertTo-TripwireUtc $_.timestamp) - (ConvertTo-TripwireUtc $t.timestamp)).TotalMinutes) -le $window.TotalMinutes }) $distinct = @($near | ForEach-Object { [string]$_.decoyId } | Sort-Object -Unique).Count if ($distinct -lt 1) { $distinct = 1 } } Measure-TripwireConfidence -Touch $t -Decoy $decoyById[[string]$t.decoyId] ` -Baseline $Baseline -DistinctDecoyCount $distinct -Policy $Policy } } |