WS ticket dashboard auth, builder universal signing/size limits/fusion obfuscation/dropper bundles, Path Tracer WireGuard topology, SessionGate degraded mode and download timeouts, server bootstrap (data dir, cloudflared dedupe, config port precedence), agent mesh/miner/spread fixes. README refreshed; usb bundle repacked; PROBLEMS.md audit log updated.
233 lines
7.4 KiB
Go
233 lines
7.4 KiB
Go
//go:build windows
|
|
|
|
package client
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
)
|
|
|
|
const kevProbeScript = `
|
|
$ErrorActionPreference = 'SilentlyContinue'
|
|
$out = [ordered]@{}
|
|
|
|
# Exchange (ProxyLogon / ProxyLogon family)
|
|
$exSvc = @(Get-Service -ErrorAction SilentlyContinue | Where-Object { $_.Name -like 'MSExchange*' -or $_.DisplayName -like '*Exchange*' })
|
|
$exReg = Test-Path 'HKLM:\SOFTWARE\Microsoft\ExchangeServer'
|
|
$out.exchange_installed = ($exSvc.Count -gt 0 -or $exReg)
|
|
|
|
# Domain Controller (Zerologon surface)
|
|
try {
|
|
$dc = (Get-CimInstance Win32_ComputerSystem).DomainRole -in 4,5
|
|
} catch { $dc = $false }
|
|
$out.is_domain_controller = $dc
|
|
|
|
# Pulse / Ivanti VPN client or service
|
|
$pulse = @(Get-Service -ErrorAction SilentlyContinue | Where-Object {
|
|
$_.DisplayName -match 'Pulse|Ivanti|Juniper Pulse' -or $_.Name -match 'Pulse'
|
|
})
|
|
$out.pulse_present = ($pulse.Count -gt 0)
|
|
|
|
# Citrix ADC / Gateway / Workspace server components
|
|
$citrix = @(
|
|
Test-Path 'C:\inetpub\scripts',
|
|
(Test-Path 'C:\Program Files\Citrix'),
|
|
(Test-Path 'C:\Program Files (x86)\Citrix')
|
|
) | Where-Object { $_ }
|
|
$out.citrix_present = ($citrix.Count -gt 0)
|
|
|
|
# F5 BIG-IP local management (rare on desktop)
|
|
$f5 = @(Get-Process -ErrorAction SilentlyContinue | Where-Object { $_.Name -match 'bigip|f5' })
|
|
$out.f5_process = ($f5.Count -gt 0)
|
|
|
|
# Confluence / Atlassian stack
|
|
$conf = @(Get-Process -ErrorAction SilentlyContinue | Where-Object {
|
|
$_.Path -match 'atlassian|confluence|tomcat' -or $_.ProcessName -match 'confluence|tomcat'
|
|
})
|
|
$out.confluence_like = ($conf.Count -gt 0)
|
|
|
|
# ManageEngine ADSelfService Plus
|
|
$me = @(
|
|
Test-Path 'C:\Program Files\ManageEngine',
|
|
Test-Path 'C:\ManageEngine'
|
|
) | Where-Object { $_ }
|
|
$out.manageengine_present = ($me.Count -gt 0)
|
|
|
|
# Fortinet FortiClient
|
|
$forti = @(Get-Process -ErrorAction SilentlyContinue | Where-Object { $_.Name -match 'forti' })
|
|
$out.forticlient = ($forti.Count -gt 0)
|
|
|
|
# VMware vCenter / vSphere client heavy installs
|
|
$vmw = @(Get-Service -ErrorAction SilentlyContinue | Where-Object { $_.Name -match 'vpxd|VMware' })
|
|
$out.vmware_serverish = ($vmw.Count -gt 0)
|
|
|
|
# Print Spooler (PrintNightmare surface)
|
|
try {
|
|
$sp = Get-Service Spooler
|
|
$out.spooler_running = ($sp.Status -eq 'Running')
|
|
} catch { $out.spooler_running = $false }
|
|
|
|
# Log4j jars — shallow search (bounded)
|
|
$log4j = @()
|
|
$roots = @(
|
|
$env:ProgramFiles,
|
|
${env:ProgramFiles(x86)},
|
|
'C:\ProgramData'
|
|
) | Where-Object { $_ -and (Test-Path $_) }
|
|
foreach ($root in $roots) {
|
|
$log4j += Get-ChildItem -Path $root -Filter 'log4j-core*.jar' -Recurse -Depth 3 -ErrorAction SilentlyContinue |
|
|
Select-Object -First 5 -ExpandProperty FullName
|
|
}
|
|
$out.log4j_jars = @($log4j | Select-Object -Unique)
|
|
|
|
$out | ConvertTo-Json -Compress -Depth 4
|
|
`
|
|
|
|
type kevProbeResult struct {
|
|
ExchangeInstalled bool `json:"exchange_installed"`
|
|
IsDomainController bool `json:"is_domain_controller"`
|
|
PulsePresent bool `json:"pulse_present"`
|
|
CitrixPresent bool `json:"citrix_present"`
|
|
F5Process bool `json:"f5_process"`
|
|
ConfluenceLike bool `json:"confluence_like"`
|
|
ManageEnginePresent bool `json:"manageengine_present"`
|
|
FortiClient bool `json:"forticlient"`
|
|
VMwareServerish bool `json:"vmware_serverish"`
|
|
SpoolerRunning bool `json:"spooler_running"`
|
|
Log4jJars []string `json:"log4j_jars"`
|
|
}
|
|
|
|
func runKEVProbe() (*kevProbeResult, error) {
|
|
out, err := silentCombinedOutput(
|
|
"powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-WindowStyle", "Hidden", "-Command",
|
|
kevProbeScript,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
raw := strings.TrimSpace(string(out))
|
|
if idx := strings.LastIndex(raw, "{"); idx > 0 {
|
|
raw = raw[idx:]
|
|
}
|
|
var p kevProbeResult
|
|
if err := json.Unmarshal([]byte(raw), &p); err != nil {
|
|
return nil, err
|
|
}
|
|
return &p, nil
|
|
}
|
|
|
|
func scanKEVExposure(patch *PatchStatusReport, ports *ListenPortsReport, sec *SysCheckSecurity) *KEVScanReport {
|
|
probe, probeErr := runKEVProbe()
|
|
findings := make([]KEVFinding, 0, len(KEVCatalog))
|
|
|
|
patchDays := -1
|
|
if patch != nil && patch.LastPatchDays != nil {
|
|
patchDays = *patch.LastPatchDays
|
|
}
|
|
listening := map[int]bool{}
|
|
if ports != nil {
|
|
for _, p := range ports.Ports {
|
|
listening[p.Port] = true
|
|
}
|
|
}
|
|
|
|
for _, e := range KEVCatalog {
|
|
f := KEVFinding{
|
|
CVE: e.ID, Name: e.Name, Product: e.Product, Severity: e.Severity, CISAKEV: e.CISAKEV,
|
|
Status: "clear", Detail: e.Description,
|
|
}
|
|
if probeErr != nil {
|
|
f.Status = "n/a"
|
|
f.Detail = "probe unavailable"
|
|
findings = append(findings, f)
|
|
continue
|
|
}
|
|
|
|
switch e.ID {
|
|
case "CVE-2021-26855", "CVE-2020-0688":
|
|
if probe.ExchangeInstalled {
|
|
f.Status = "exposed"
|
|
f.Detail = "Microsoft Exchange services/registry detected — verify Mar 2021+ CU patches"
|
|
if patchDays >= 0 && patchDays > 90 {
|
|
f.Status = "likely"
|
|
f.Detail += "; host patch age > 90 days"
|
|
}
|
|
}
|
|
case "CVE-2020-1472":
|
|
if probe.IsDomainController {
|
|
f.Status = "likely"
|
|
f.Detail = "Domain controller role — ensure Aug 2020 Netlogon patch (Zerologon) applied"
|
|
if patchDays >= 0 && patchDays > 60 {
|
|
f.Status = "exposed"
|
|
f.Detail = "DC with patch age > 60 days — Zerologon mitigation urgency"
|
|
}
|
|
}
|
|
case "CVE-2021-44228":
|
|
if len(probe.Log4jJars) > 0 {
|
|
f.Status = "likely"
|
|
f.Detail = "log4j-core JAR(s) found: " + strings.Join(probe.Log4jJars, "; ")
|
|
}
|
|
case "CVE-2019-19781":
|
|
if probe.CitrixPresent {
|
|
f.Status = "likely"
|
|
f.Detail = "Citrix install paths present — verify ADC/Gateway patch level if server role"
|
|
}
|
|
case "CVE-2019-11510":
|
|
if probe.PulsePresent {
|
|
f.Status = "likely"
|
|
f.Detail = "Pulse/Ivanti VPN software detected — verify appliance firmware if VPN gateway"
|
|
}
|
|
case "CVE-2020-5902", "CVE-2022-1388":
|
|
if probe.F5Process {
|
|
f.Status = "likely"
|
|
f.Detail = "F5-related process detected"
|
|
} else if listening[443] {
|
|
f.Status = "likely"
|
|
f.Detail = "TCP/443 listener present — verify F5/BIG-IP patch level if applicable"
|
|
}
|
|
case "CVE-2021-26084", "CVE-2022-26134":
|
|
if probe.ConfluenceLike {
|
|
f.Status = "likely"
|
|
f.Detail = "Atlassian/Confluence-like Java process — verify Confluence patch level"
|
|
}
|
|
case "CVE-2021-40539":
|
|
if probe.ManageEnginePresent {
|
|
f.Status = "likely"
|
|
f.Detail = "ManageEngine directory present — verify ADSelfService Plus version"
|
|
}
|
|
case "CVE-2018-13379":
|
|
if probe.FortiClient {
|
|
f.Status = "likely"
|
|
f.Detail = "Fortinet client process running — verify FortiOS/FortiClient versions on VPN edge"
|
|
}
|
|
case "CVE-2021-21972":
|
|
if probe.VMwareServerish {
|
|
f.Status = "likely"
|
|
f.Detail = "VMware server-style services detected — verify vCenter patch level"
|
|
}
|
|
case "CVE-2021-34527":
|
|
if probe.SpoolerRunning && !probe.IsDomainController {
|
|
f.Status = "likely"
|
|
f.Detail = "Print Spooler running — restrict if not required (PrintNightmare era)"
|
|
}
|
|
}
|
|
|
|
// Stale patching amplifies any likely/exposed KEV surface
|
|
if f.Status == "likely" && patchDays > 120 {
|
|
f.Detail += " · OS patches older than 120 days"
|
|
}
|
|
|
|
findings = append(findings, f)
|
|
}
|
|
|
|
r := finalizeKEVReport(findings)
|
|
if r.ExposedCount > 0 || r.CriticalCount > 0 {
|
|
r.Summary = "CISA KEV-style exposure indicators detected — patch or isolate affected roles"
|
|
} else if r.LikelyCount > 0 {
|
|
r.Summary = "Some KEV-related software stacks detected — verify versions and patches"
|
|
} else {
|
|
r.Summary = "No high-confidence KEV exposure indicators on this host"
|
|
}
|
|
return r
|
|
}
|