feat(onboarding-diag): allowlist ACG's own stack; downgrade Defender-off w/ 3rd-party AV (3d886f1a)
The probe flagged ACG's own MSP tooling (ScreenConnect/ConnectWise Control, Splashtop, Syncro, Datto RMM, Datto EDR/AV) as CRITICAL "foreign agent" and flagged Defender-off as CRITICAL even when a 3rd-party AV had legitimately disabled it. Now: allowlisted tools emit an INFO "expected ACG tooling" finding (genuinely-foreign tools still CRITICAL); Defender-off is downgraded to INFO only when a 3rd-party AV is active. JSON contract + grading unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -316,14 +316,52 @@ Invoke-Check -Id 'sec.foreign_agents' -Category 'security' -Title 'Competitor /
|
||||
try { $svcRows = Get-Service -ErrorAction SilentlyContinue | Select-Object Name, DisplayName } catch { $svcRows = @() }
|
||||
}
|
||||
|
||||
# ACG's OWN management / remote-access / security stack. A match here is
|
||||
# EXPECTED tooling (we deploy it), so it is reported as INFO instead of the
|
||||
# CRITICAL "foreign agent" finding. Detection of genuinely-foreign agents is
|
||||
# NOT weakened: anything that matches a $patterns rule but is NOT on this
|
||||
# allowlist is still flagged CRITICAL exactly as before.
|
||||
#
|
||||
# Matching is the same signal the foreign-agent scan uses (installed program
|
||||
# DisplayName, service Name/DisplayName) plus the program Publisher, all
|
||||
# case-insensitive (-match is case-insensitive in PS). Keep the aliases
|
||||
# broad so common product/service-name variants are covered. To add a tool
|
||||
# later, append another regex string to this array.
|
||||
$acgOwnStack = @(
|
||||
# ConnectWise Control / ScreenConnect (our remote-access tool)
|
||||
'screenconnect|connectwise *control|connectwisecontrol',
|
||||
# Splashtop (our remote-access tool)
|
||||
'\bsplashtop\b',
|
||||
# Syncro (our RMM/PSA) - SyncroMSP, kabuto, RepairTech lineage
|
||||
'\bsyncro\b|syncromsp|\bkabuto\b|repairtech',
|
||||
# Datto RMM (our RMM) - CagService, AEMAgent, CentraStage lineage
|
||||
'datto *rmm|\bcagservice\b|\baemagent\b|centrastage',
|
||||
# Datto EDR / Datto AV (our endpoint protection) - incl. Infocyte lineage
|
||||
'datto *edr|datto *av|datto *antivirus|\bhuntress\b|infocyte|\brts\b'
|
||||
)
|
||||
|
||||
# Returns the matching allowlist regex (truthy) if any allowlist entry
|
||||
# matches the supplied text, else $null. Never throws.
|
||||
function Test-AcgOwnStack {
|
||||
param([string]$Text)
|
||||
if ([string]::IsNullOrEmpty($Text)) { return $null }
|
||||
foreach ($rx in $acgOwnStack) {
|
||||
try { if ($Text -match $rx) { return $rx } } catch { }
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
$hits = @()
|
||||
foreach ($pat in $patterns) {
|
||||
$rx = $pat.rx
|
||||
$matchEvidence = @()
|
||||
$isOurs = $false # true if ANY matching signal for this label is ACG's own stack
|
||||
|
||||
foreach ($prog in $installed) {
|
||||
if ($prog.Name -match $rx) {
|
||||
$matchEvidence += ("program: " + $prog.Name + " " + $prog.Version)
|
||||
# An install can be identified as ours by its DisplayName OR publisher.
|
||||
if ((Test-AcgOwnStack $prog.Name) -or (Test-AcgOwnStack $prog.Publisher)) { $isOurs = $true }
|
||||
}
|
||||
}
|
||||
foreach ($s in $svcRows) {
|
||||
@@ -333,18 +371,27 @@ Invoke-Check -Id 'sec.foreign_agents' -Category 'security' -Title 'Competitor /
|
||||
$st = ''
|
||||
try { $st = [string]$s.State } catch { }
|
||||
$matchEvidence += ("service: " + $sn + " (" + $sd + ") " + $st)
|
||||
if ((Test-AcgOwnStack $sn) -or (Test-AcgOwnStack $sd)) { $isOurs = $true }
|
||||
}
|
||||
}
|
||||
|
||||
if ($matchEvidence.Count -gt 0) {
|
||||
$hits += [pscustomobject]@{ Label = $pat.label; Evidence = ($matchEvidence | Select-Object -Unique) }
|
||||
$hits += [pscustomobject]@{
|
||||
Label = $pat.label
|
||||
Evidence = ($matchEvidence | Select-Object -Unique)
|
||||
IsOurs = $isOurs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set-Fact 'foreign_agents' ($hits | ForEach-Object { $_.Label })
|
||||
Set-Fact 'foreign_agents' ($hits | Where-Object { -not $_.IsOurs } | ForEach-Object { $_.Label })
|
||||
Set-Fact 'acg_managed_tools' ($hits | Where-Object { $_.IsOurs } | ForEach-Object { $_.Label })
|
||||
|
||||
if ($hits.Count -gt 0) {
|
||||
foreach ($h in $hits) {
|
||||
$foreignHits = @($hits | Where-Object { -not $_.IsOurs })
|
||||
$ourHits = @($hits | Where-Object { $_.IsOurs })
|
||||
|
||||
if ($foreignHits.Count -gt 0) {
|
||||
foreach ($h in $foreignHits) {
|
||||
Add-Finding -Id ('sec.foreign_agents.' + ($h.Label -replace '[^A-Za-z0-9]+','_').ToLower()) `
|
||||
-Category 'security' -Severity 'critical' `
|
||||
-Title ('Foreign management/remote-access agent: ' + $h.Label) `
|
||||
@@ -357,6 +404,16 @@ Invoke-Check -Id 'sec.foreign_agents' -Category 'security' -Title 'Competitor /
|
||||
-Detail 'No known competitor RMM or unmanaged remote-access agents found in installed programs or services.' `
|
||||
-Evidence 'Scanned uninstall hives (HKLM + WOW6432Node) and Win32_Service'
|
||||
}
|
||||
|
||||
# ACG's own stack is expected tooling. Report as INFO so it is visible in the
|
||||
# inventory without being treated as a control/security risk.
|
||||
foreach ($h in $ourHits) {
|
||||
Add-Finding -Id ('sec.foreign_agents.acg.' + ($h.Label -replace '[^A-Za-z0-9]+','_').ToLower()) `
|
||||
-Category 'security' -Severity 'info' `
|
||||
-Title ('Expected ACG management tooling present: ' + $h.Label) `
|
||||
-Detail 'This is Arizona Computer Guru managed/remote-access tooling that we deploy. Its presence is expected and not a foreign-agent risk.' `
|
||||
-Evidence ($h.Evidence -join "`n")
|
||||
}
|
||||
}
|
||||
|
||||
# --- Firewall profiles ---
|
||||
|
||||
Reference in New Issue
Block a user