Add WiFi Audit, API Fuzzer, Cloud Scanner, Threat Intel, Log Correlator, Steganography, Anti-Forensics, BLE Scanner, Forensics, RFID/NFC, Malware Sandbox, Password Toolkit, Web Scanner, Report Engine, Net Mapper, and C2 Framework. Each module includes CLI interface, Flask routes, and web UI template. Also includes Go DNS server source + binary, IP Capture service, SYN Flood, Gone Fishing mail server, and hack hijack modules from v2.0 work. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
686 lines
38 KiB
HTML
686 lines
38 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}Offense - AUTARCH{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="page-header">
|
|
<h1>Offense</h1>
|
|
</div>
|
|
|
|
<!-- MSF Server Control -->
|
|
<div class="section">
|
|
<h2>Metasploit Server</h2>
|
|
<div style="display:flex;align-items:center;gap:1rem;flex-wrap:wrap">
|
|
<div class="status-indicator" id="msf-status">
|
|
<span class="status-dot inactive"></span>Checking...
|
|
</div>
|
|
<div id="msf-version" style="font-size:0.8rem;color:var(--text-muted)"></div>
|
|
<div style="flex:1"></div>
|
|
<button id="btn-connect" class="btn btn-primary btn-small" onclick="msfConnect()" style="display:none">Connect</button>
|
|
<button id="btn-disconnect" class="btn btn-small" onclick="msfDisconnect()" style="display:none">Disconnect</button>
|
|
<button id="btn-start-server" class="btn btn-small" onclick="toggleServerPanel()" style="display:none">Start Server</button>
|
|
<button id="btn-stop-server" class="btn btn-danger btn-small" onclick="msfStopServer()" style="display:none">Stop Server</button>
|
|
</div>
|
|
|
|
<!-- Server config panel (hidden by default) -->
|
|
<div id="server-panel" style="display:none;margin-top:0.75rem;padding:0.75rem;background:var(--surface);border:1px solid var(--border);border-radius:6px">
|
|
<div style="display:grid;grid-template-columns:1fr 80px 1fr 1fr;gap:0.5rem;align-items:end">
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="msf-host">Host</label>
|
|
<input type="text" id="msf-host" value="127.0.0.1">
|
|
</div>
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="msf-port">Port</label>
|
|
<input type="text" id="msf-port" value="55553">
|
|
</div>
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="msf-user">Username</label>
|
|
<input type="text" id="msf-user" value="msf">
|
|
</div>
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="msf-pass">Password</label>
|
|
<input type="password" id="msf-pass" placeholder="required">
|
|
</div>
|
|
</div>
|
|
<div style="display:flex;align-items:center;gap:0.75rem;margin-top:0.5rem">
|
|
<label style="font-size:0.85rem;display:flex;align-items:center;gap:0.3rem;cursor:pointer">
|
|
<input type="checkbox" id="msf-ssl" checked> SSL
|
|
</label>
|
|
<div style="flex:1"></div>
|
|
<button class="btn btn-small" onclick="msfSaveSettings()">Save Settings</button>
|
|
<button class="btn btn-primary btn-small" onclick="msfStartServer()">Start & Connect</button>
|
|
<button class="btn btn-small" onclick="msfConnectOnly()">Connect Only</button>
|
|
</div>
|
|
<div id="server-msg" style="font-size:0.8rem;color:var(--text-muted);margin-top:0.5rem"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Module Search -->
|
|
<div class="section">
|
|
<h2>Module Search</h2>
|
|
<div class="input-row">
|
|
<input type="text" id="msf-search" placeholder="Search modules (e.g., eternalblue, smb, ssh)" onkeypress="if(event.key==='Enter')searchMSFModules()">
|
|
<button id="btn-msf-search" class="btn btn-primary" onclick="searchMSFModules()">Search</button>
|
|
</div>
|
|
<div id="msf-search-results" class="results-stream" style="max-height:400px;overflow-y:auto">
|
|
<div class="empty-state">Search the offline module library or connected MSF instance.</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Run Module -->
|
|
<div class="section">
|
|
<h2>Run Module</h2>
|
|
<div class="tab-bar">
|
|
<button class="tab active" data-tab-group="run-tabs" data-tab="ssh" onclick="showTab('run-tabs','ssh')">SSH</button>
|
|
<button class="tab" data-tab-group="run-tabs" data-tab="portscan" onclick="showTab('run-tabs','portscan')">Port Scan</button>
|
|
<button class="tab" data-tab-group="run-tabs" data-tab="osdetect" onclick="showTab('run-tabs','osdetect')">OS Detect</button>
|
|
<button class="tab" data-tab-group="run-tabs" data-tab="vuln" onclick="showTab('run-tabs','vuln')">Vuln Scan</button>
|
|
<button class="tab" data-tab-group="run-tabs" data-tab="smb" onclick="showTab('run-tabs','smb')">SMB</button>
|
|
<button class="tab" data-tab-group="run-tabs" data-tab="http" onclick="showTab('run-tabs','http')">HTTP</button>
|
|
<button class="tab" data-tab-group="run-tabs" data-tab="exploit" onclick="showTab('run-tabs','exploit')">Exploit</button>
|
|
<button class="tab" data-tab-group="run-tabs" data-tab="custom" onclick="showTab('run-tabs','custom')">Custom</button>
|
|
</div>
|
|
|
|
<!-- SSH tab -->
|
|
<div class="tab-content active" data-tab-group="run-tabs" data-tab="ssh">
|
|
<div style="display:grid;grid-template-columns:1fr auto auto;gap:0.75rem;align-items:end;margin-top:0.75rem">
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="ssh-rhosts">Target(s)</label>
|
|
<input type="text" id="ssh-rhosts" placeholder="192.168.1.0/24 or 10.0.0.5">
|
|
</div>
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="ssh-rport">Port</label>
|
|
<input type="text" id="ssh-rport" value="22" style="width:70px">
|
|
</div>
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="ssh-threads">Threads</label>
|
|
<input type="text" id="ssh-threads" value="10" style="width:60px">
|
|
</div>
|
|
</div>
|
|
<div class="tool-actions" style="margin-top:0.75rem">
|
|
<button class="btn btn-primary" onclick="runFeaturedModule('ssh')">Run SSH Version Scan</button>
|
|
<button class="btn btn-secondary" onclick="runFeaturedModule('ssh-enum')">SSH Enum Users</button>
|
|
<button class="btn btn-secondary" onclick="toggleBruteRow()">SSH Brute-Force ↓</button>
|
|
</div>
|
|
<div id="ssh-brute-row" style="display:none;margin-top:0.5rem">
|
|
<div style="display:grid;grid-template-columns:1fr 1fr auto;gap:0.75rem;align-items:end">
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="ssh-username">Username</label>
|
|
<input type="text" id="ssh-username" placeholder="root">
|
|
</div>
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="ssh-password">Password</label>
|
|
<input type="text" id="ssh-password" placeholder="password">
|
|
</div>
|
|
<button class="btn btn-danger" onclick="runFeaturedModule('ssh-brute')">Run Brute-Force</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Port Scan tab -->
|
|
<div class="tab-content" data-tab-group="run-tabs" data-tab="portscan">
|
|
<div style="display:grid;grid-template-columns:1fr auto auto;gap:0.75rem;align-items:end;margin-top:0.75rem">
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="ps-rhosts">Target(s)</label>
|
|
<input type="text" id="ps-rhosts" placeholder="192.168.1.0/24 or 10.0.0.5">
|
|
</div>
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="ps-ports">Ports</label>
|
|
<input type="text" id="ps-ports" value="1-1024" style="width:100px">
|
|
</div>
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="ps-threads">Threads</label>
|
|
<input type="text" id="ps-threads" value="10" style="width:60px">
|
|
</div>
|
|
</div>
|
|
<div class="tool-actions" style="margin-top:0.75rem">
|
|
<button class="btn btn-primary" onclick="runFeaturedModule('tcp-scan')">TCP Scan</button>
|
|
<button class="btn btn-secondary" onclick="runFeaturedModule('syn-scan')">SYN Scan</button>
|
|
<button class="btn btn-secondary" onclick="runFeaturedModule('ack-scan')">ACK Scan</button>
|
|
<button class="btn btn-secondary" onclick="runFeaturedModule('udp-scan')">UDP Sweep</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- OS Detect tab -->
|
|
<div class="tab-content" data-tab-group="run-tabs" data-tab="osdetect">
|
|
<div style="margin-top:0.75rem">
|
|
<div class="form-group">
|
|
<label for="os-rhosts">Target(s)</label>
|
|
<input type="text" id="os-rhosts" placeholder="192.168.1.0/24 or 10.0.0.5">
|
|
</div>
|
|
</div>
|
|
<div class="tool-actions">
|
|
<button class="btn btn-primary" onclick="runFeaturedModule('smb-version')">SMB Version</button>
|
|
<button class="btn btn-secondary" onclick="runFeaturedModule('http-header')">HTTP Header</button>
|
|
<button class="btn btn-secondary" onclick="runFeaturedModule('ftp-version')">FTP Version</button>
|
|
<button class="btn btn-secondary" onclick="runFeaturedModule('telnet-version')">Telnet Version</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Vuln Scan tab -->
|
|
<div class="tab-content" data-tab-group="run-tabs" data-tab="vuln">
|
|
<div style="display:grid;grid-template-columns:1fr auto;gap:0.75rem;align-items:end;margin-top:0.75rem">
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="vuln-rhosts">Target(s)</label>
|
|
<input type="text" id="vuln-rhosts" placeholder="192.168.1.0/24 or 10.0.0.5">
|
|
</div>
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="vuln-threads">Threads</label>
|
|
<input type="text" id="vuln-threads" value="5" style="width:60px">
|
|
</div>
|
|
</div>
|
|
<div class="tool-actions" style="margin-top:0.75rem">
|
|
<button class="btn btn-danger" onclick="runFeaturedModule('eternalblue-check')">EternalBlue Check</button>
|
|
<button class="btn btn-danger" onclick="runFeaturedModule('bluekeep-check')">BlueKeep Check</button>
|
|
<button class="btn btn-secondary" onclick="runFeaturedModule('ssl-heartbleed')">Heartbleed Check</button>
|
|
<button class="btn btn-secondary" onclick="runFeaturedModule('shellshock-check')">Shellshock Check</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- SMB tab -->
|
|
<div class="tab-content" data-tab-group="run-tabs" data-tab="smb">
|
|
<div style="display:grid;grid-template-columns:1fr auto auto;gap:0.75rem;align-items:end;margin-top:0.75rem">
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="smb-rhosts">Target(s)</label>
|
|
<input type="text" id="smb-rhosts" placeholder="192.168.1.0/24 or 10.0.0.5">
|
|
</div>
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="smb-user">Username</label>
|
|
<input type="text" id="smb-user" placeholder="admin" style="width:100px">
|
|
</div>
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="smb-pass">Password</label>
|
|
<input type="text" id="smb-pass" placeholder="" style="width:100px">
|
|
</div>
|
|
</div>
|
|
<div class="tool-actions" style="margin-top:0.75rem">
|
|
<button class="btn btn-primary" onclick="runFeaturedModule('smb-enum-shares')">Enum Shares</button>
|
|
<button class="btn btn-secondary" onclick="runFeaturedModule('smb-enum-users')">Enum Users</button>
|
|
<button class="btn btn-secondary" onclick="runFeaturedModule('smb-login')">SMB Login</button>
|
|
<button class="btn btn-secondary" onclick="runFeaturedModule('smb-pipe-auditor')">Pipe Auditor</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- HTTP tab -->
|
|
<div class="tab-content" data-tab-group="run-tabs" data-tab="http">
|
|
<div style="display:grid;grid-template-columns:1fr auto auto;gap:0.75rem;align-items:end;margin-top:0.75rem">
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="http-rhosts">Target(s)</label>
|
|
<input type="text" id="http-rhosts" placeholder="192.168.1.0/24 or example.com">
|
|
</div>
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="http-rport">Port</label>
|
|
<input type="text" id="http-rport" value="80" style="width:70px">
|
|
</div>
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="http-threads">Threads</label>
|
|
<input type="text" id="http-threads" value="5" style="width:60px">
|
|
</div>
|
|
</div>
|
|
<div style="margin-top:0.5rem">
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="http-targeturi">Target URI</label>
|
|
<input type="text" id="http-targeturi" value="/" placeholder="/">
|
|
</div>
|
|
</div>
|
|
<div class="tool-actions" style="margin-top:0.75rem">
|
|
<button class="btn btn-primary" onclick="runFeaturedModule('http-dir-scanner')">Dir Scanner</button>
|
|
<button class="btn btn-secondary" onclick="runFeaturedModule('http-title')">HTTP Title</button>
|
|
<button class="btn btn-secondary" onclick="runFeaturedModule('http-robots')">robots.txt</button>
|
|
<button class="btn btn-secondary" onclick="runFeaturedModule('http-cert')">SSL Cert</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Exploit tab -->
|
|
<div class="tab-content" data-tab-group="run-tabs" data-tab="exploit">
|
|
<div style="display:grid;grid-template-columns:1fr 1fr;gap:0.75rem;align-items:end;margin-top:0.75rem">
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="exp-rhosts">Target (RHOSTS)</label>
|
|
<input type="text" id="exp-rhosts" placeholder="192.168.1.5">
|
|
</div>
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="exp-lhost">Your IP (LHOST)</label>
|
|
<input type="text" id="exp-lhost" placeholder="192.168.1.100">
|
|
</div>
|
|
</div>
|
|
<div style="display:grid;grid-template-columns:1fr auto auto;gap:0.75rem;align-items:end;margin-top:0.5rem">
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="exp-module">Exploit Module</label>
|
|
<input type="text" id="exp-module" placeholder="exploit/windows/smb/ms17_010_eternalblue">
|
|
</div>
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="exp-payload">Payload</label>
|
|
<input type="text" id="exp-payload" placeholder="windows/x64/meterpreter/reverse_tcp" style="width:250px">
|
|
</div>
|
|
<div class="form-group" style="margin-bottom:0">
|
|
<label for="exp-lport">LPORT</label>
|
|
<input type="text" id="exp-lport" value="4444" style="width:70px">
|
|
</div>
|
|
</div>
|
|
<div class="tool-actions" style="margin-top:0.75rem">
|
|
<button class="btn btn-danger" onclick="runFeaturedModule('exploit-run')">Launch Exploit</button>
|
|
</div>
|
|
<p style="font-size:0.75rem;color:var(--text-muted);margin-top:0.5rem">Exploits run as background jobs. Check Active Sessions for shells.</p>
|
|
</div>
|
|
|
|
<!-- Custom tab -->
|
|
<div class="tab-content" data-tab-group="run-tabs" data-tab="custom">
|
|
<div style="margin-top:0.75rem">
|
|
<div class="form-group">
|
|
<label for="custom-module">Module Path</label>
|
|
<input type="text" id="custom-module" placeholder="auxiliary/scanner/ssh/ssh_version">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="custom-options">Options (JSON)</label>
|
|
<input type="text" id="custom-options" placeholder='{"RHOSTS":"10.0.0.1","RPORT":22}'>
|
|
</div>
|
|
</div>
|
|
<div class="tool-actions">
|
|
<button class="btn btn-primary" onclick="runFeaturedModule('custom')">Run Module</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Shared output area -->
|
|
<div style="margin-top:0.75rem;display:flex;align-items:center;gap:0.75rem;padding-top:0.5rem;border-top:1px solid var(--border)">
|
|
<span id="run-status" style="font-size:0.85rem;color:var(--text-secondary);flex:1"></span>
|
|
<button id="run-stop-btn" class="btn btn-sm btn-danger" style="display:none" onclick="stopCurrentModule()">Stop</button>
|
|
</div>
|
|
<div id="module-output" class="results-stream" style="min-height:140px;margin-top:0.5rem"></div>
|
|
</div>
|
|
|
|
<!-- Module Browser -->
|
|
<div class="section">
|
|
<h2>Module Browser</h2>
|
|
<div class="tab-bar">
|
|
<button class="tab active" data-tab-group="msf-browse" data-tab="auxiliary" onclick="showTab('msf-browse','auxiliary');browseMSFModules('auxiliary')">Scanners</button>
|
|
<button class="tab" data-tab-group="msf-browse" data-tab="exploit" onclick="showTab('msf-browse','exploit');browseMSFModules('exploit')">Exploits</button>
|
|
<button class="tab" data-tab-group="msf-browse" data-tab="post" onclick="showTab('msf-browse','post');browseMSFModules('post')">Post</button>
|
|
<button class="tab" data-tab-group="msf-browse" data-tab="payload" onclick="showTab('msf-browse','payload');browseMSFModules('payload')">Payloads</button>
|
|
</div>
|
|
<input type="hidden" id="msf-page-auxiliary" value="1">
|
|
<input type="hidden" id="msf-page-exploit" value="1">
|
|
<input type="hidden" id="msf-page-post" value="1">
|
|
<input type="hidden" id="msf-page-payload" value="1">
|
|
<div class="tab-content active" data-tab-group="msf-browse" data-tab="auxiliary" id="msf-modules-auxiliary">
|
|
<div class="empty-state">Click a tab to browse modules.</div>
|
|
</div>
|
|
<div class="tab-content" data-tab-group="msf-browse" data-tab="exploit" id="msf-modules-exploit"></div>
|
|
<div class="tab-content" data-tab-group="msf-browse" data-tab="post" id="msf-modules-post"></div>
|
|
<div class="tab-content" data-tab-group="msf-browse" data-tab="payload" id="msf-modules-payload"></div>
|
|
</div>
|
|
|
|
<!-- Sessions & Jobs -->
|
|
<div class="section">
|
|
<h2>Active Sessions & Jobs</h2>
|
|
<div class="tool-actions">
|
|
<button class="btn btn-small" onclick="loadMSFSessions()">Refresh Sessions</button>
|
|
<button class="btn btn-small" onclick="loadMSFJobs()">Refresh Jobs</button>
|
|
</div>
|
|
<div id="msf-sessions">
|
|
<div class="empty-state">Click "Refresh" to check for active sessions and jobs.</div>
|
|
</div>
|
|
<div id="msf-jobs" style="margin-top:0.5rem"></div>
|
|
</div>
|
|
|
|
{% if modules %}
|
|
<div class="section">
|
|
<h2>Offense Modules</h2>
|
|
<ul class="module-list">
|
|
{% for name, info in modules.items() %}
|
|
<li class="module-item">
|
|
<div>
|
|
<div class="module-name">{{ name }}</div>
|
|
<div class="module-desc">{{ info.description }}</div>
|
|
</div>
|
|
<div class="module-meta">v{{ info.version }}</div>
|
|
</li>
|
|
{% endfor %}
|
|
</ul>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Agent Hal -->
|
|
<div class="section">
|
|
<h2>Agent Hal — Autonomous Mode</h2>
|
|
<p style="font-size:0.85rem;color:var(--text-secondary);margin-bottom:0.75rem">Give Hal a security task and watch it execute step by step using MSF and other tools.</p>
|
|
<div class="input-row">
|
|
<input type="text" id="agent-task" placeholder="e.g. scan 10.0.0.5 for open SSH ports and identify the service version">
|
|
<button class="btn btn-primary" onclick="runHalTask()">Run</button>
|
|
<button id="agent-stop-btn" class="btn btn-danger" style="display:none" onclick="stopHalTask()">Stop</button>
|
|
</div>
|
|
<div id="agent-output" class="results-stream" style="min-height:120px"></div>
|
|
</div>
|
|
|
|
<script>
|
|
let _currentJobId = null;
|
|
let _currentRunId = null;
|
|
|
|
// Check MSF status on page load
|
|
document.addEventListener('DOMContentLoaded', function() { checkMSFStatus(); });
|
|
|
|
/* ── Featured Module Definitions ───────────────────────────────── */
|
|
const _FEATURED = {
|
|
// SSH
|
|
'ssh': {path: 'auxiliary/scanner/ssh/ssh_version', opts: () => ({RHOSTS: v('ssh-rhosts'), RPORT: parseInt(v('ssh-rport')) || 22, THREADS: parseInt(v('ssh-threads')) || 10})},
|
|
'ssh-enum': {path: 'auxiliary/scanner/ssh/ssh_enumusers', opts: () => ({RHOSTS: v('ssh-rhosts'), RPORT: parseInt(v('ssh-rport')) || 22, THREADS: parseInt(v('ssh-threads')) || 10})},
|
|
'ssh-brute': {path: 'auxiliary/scanner/ssh/ssh_login', opts: () => ({RHOSTS: v('ssh-rhosts'), RPORT: parseInt(v('ssh-rport')) || 22, USERNAME: v('ssh-username'), PASSWORD: v('ssh-password')})},
|
|
// Port Scan
|
|
'tcp-scan': {path: 'auxiliary/scanner/portscan/tcp', opts: () => ({RHOSTS: v('ps-rhosts'), PORTS: v('ps-ports') || '1-1024', THREADS: parseInt(v('ps-threads')) || 10})},
|
|
'syn-scan': {path: 'auxiliary/scanner/portscan/syn', opts: () => ({RHOSTS: v('ps-rhosts'), PORTS: v('ps-ports') || '1-1024', THREADS: parseInt(v('ps-threads')) || 10})},
|
|
'ack-scan': {path: 'auxiliary/scanner/portscan/ack', opts: () => ({RHOSTS: v('ps-rhosts'), PORTS: v('ps-ports') || '1-1024', THREADS: parseInt(v('ps-threads')) || 10})},
|
|
'udp-scan': {path: 'auxiliary/scanner/discovery/udp_sweep', opts: () => ({RHOSTS: v('ps-rhosts'), THREADS: parseInt(v('ps-threads')) || 10})},
|
|
// OS Detect
|
|
'smb-version': {path: 'auxiliary/scanner/smb/smb_version', opts: () => ({RHOSTS: v('os-rhosts')})},
|
|
'http-header': {path: 'auxiliary/scanner/http/http_header', opts: () => ({RHOSTS: v('os-rhosts')})},
|
|
'ftp-version': {path: 'auxiliary/scanner/ftp/ftp_version', opts: () => ({RHOSTS: v('os-rhosts')})},
|
|
'telnet-version':{path: 'auxiliary/scanner/telnet/telnet_version', opts: () => ({RHOSTS: v('os-rhosts')})},
|
|
// Vuln Scan
|
|
'eternalblue-check': {path: 'auxiliary/scanner/smb/smb_ms17_010', opts: () => ({RHOSTS: v('vuln-rhosts'), THREADS: parseInt(v('vuln-threads')) || 5})},
|
|
'bluekeep-check': {path: 'auxiliary/scanner/rdp/cve_2019_0708_bluekeep', opts: () => ({RHOSTS: v('vuln-rhosts'), THREADS: parseInt(v('vuln-threads')) || 5})},
|
|
'ssl-heartbleed': {path: 'auxiliary/scanner/ssl/openssl_heartbleed', opts: () => ({RHOSTS: v('vuln-rhosts'), THREADS: parseInt(v('vuln-threads')) || 5})},
|
|
'shellshock-check': {path: 'auxiliary/scanner/http/apache_mod_cgi_bash_env', opts: () => ({RHOSTS: v('vuln-rhosts'), THREADS: parseInt(v('vuln-threads')) || 5})},
|
|
// SMB
|
|
'smb-enum-shares': {path: 'auxiliary/scanner/smb/smb_enumshares', opts: () => ({RHOSTS: v('smb-rhosts'), SMBUser: v('smb-user'), SMBPass: v('smb-pass')})},
|
|
'smb-enum-users': {path: 'auxiliary/scanner/smb/smb_enumusers', opts: () => ({RHOSTS: v('smb-rhosts'), SMBUser: v('smb-user'), SMBPass: v('smb-pass')})},
|
|
'smb-login': {path: 'auxiliary/scanner/smb/smb_login', opts: () => ({RHOSTS: v('smb-rhosts'), SMBUser: v('smb-user'), SMBPass: v('smb-pass')})},
|
|
'smb-pipe-auditor':{path: 'auxiliary/scanner/smb/pipe_auditor', opts: () => ({RHOSTS: v('smb-rhosts'), SMBUser: v('smb-user'), SMBPass: v('smb-pass')})},
|
|
// HTTP
|
|
'http-dir-scanner': {path: 'auxiliary/scanner/http/dir_scanner', opts: () => ({RHOSTS: v('http-rhosts'), RPORT: parseInt(v('http-rport')) || 80, THREADS: parseInt(v('http-threads')) || 5, PATH: v('http-targeturi') || '/'})},
|
|
'http-title': {path: 'auxiliary/scanner/http/title', opts: () => ({RHOSTS: v('http-rhosts'), RPORT: parseInt(v('http-rport')) || 80})},
|
|
'http-robots': {path: 'auxiliary/scanner/http/robots_txt', opts: () => ({RHOSTS: v('http-rhosts'), RPORT: parseInt(v('http-rport')) || 80})},
|
|
'http-cert': {path: 'auxiliary/scanner/http/cert', opts: () => ({RHOSTS: v('http-rhosts'), RPORT: parseInt(v('http-rport')) || 443})},
|
|
// Exploit
|
|
'exploit-run': {path: null, opts: () => {
|
|
const o = {RHOSTS: v('exp-rhosts'), LHOST: v('exp-lhost'), LPORT: parseInt(v('exp-lport')) || 4444};
|
|
const payload = v('exp-payload');
|
|
if (payload) o.PAYLOAD = payload;
|
|
return o;
|
|
}},
|
|
// Custom
|
|
'custom': {path: null, opts: () => {try{return JSON.parse(v('custom-options') || '{}')}catch(e){return {}}}},
|
|
};
|
|
|
|
function v(id) { const el = document.getElementById(id); return el ? el.value.trim() : ''; }
|
|
|
|
/* ── Server Control ─────────────────────────────────────────────── */
|
|
function checkMSFStatus() {
|
|
fetch('/offense/status').then(r => r.json()).then(d => {
|
|
const el = document.getElementById('msf-status');
|
|
const ver = document.getElementById('msf-version');
|
|
const btnConnect = document.getElementById('btn-connect');
|
|
const btnDisconnect = document.getElementById('btn-disconnect');
|
|
const btnStart = document.getElementById('btn-start-server');
|
|
const btnStop = document.getElementById('btn-stop-server');
|
|
|
|
if (d.connected) {
|
|
el.innerHTML = '<span class="status-dot active"></span>Connected';
|
|
ver.textContent = d.version ? 'Metasploit ' + d.version : '';
|
|
btnConnect.style.display = 'none';
|
|
btnDisconnect.style.display = '';
|
|
btnStop.style.display = d.server_running ? '' : 'none';
|
|
btnStart.style.display = 'none';
|
|
} else if (d.server_running) {
|
|
el.innerHTML = '<span class="status-dot" style="background:var(--warning)"></span>Server running (not connected)';
|
|
ver.textContent = '';
|
|
btnConnect.style.display = '';
|
|
btnDisconnect.style.display = 'none';
|
|
btnStop.style.display = '';
|
|
btnStart.style.display = 'none';
|
|
} else {
|
|
el.innerHTML = '<span class="status-dot inactive"></span>Not running';
|
|
ver.textContent = '';
|
|
btnConnect.style.display = 'none';
|
|
btnDisconnect.style.display = 'none';
|
|
btnStop.style.display = 'none';
|
|
btnStart.style.display = '';
|
|
}
|
|
|
|
// Populate settings panel
|
|
if (d.host) document.getElementById('msf-host').value = d.host;
|
|
if (d.port) document.getElementById('msf-port').value = d.port;
|
|
if (d.username) document.getElementById('msf-user').value = d.username;
|
|
document.getElementById('msf-ssl').checked = d.ssl !== false;
|
|
}).catch(() => {
|
|
document.getElementById('msf-status').innerHTML = '<span class="status-dot inactive"></span>Error checking status';
|
|
});
|
|
}
|
|
|
|
function toggleServerPanel() {
|
|
const panel = document.getElementById('server-panel');
|
|
panel.style.display = panel.style.display === 'none' ? '' : 'none';
|
|
}
|
|
|
|
function _getServerSettings() {
|
|
return {
|
|
host: v('msf-host') || '127.0.0.1',
|
|
port: parseInt(v('msf-port')) || 55553,
|
|
username: v('msf-user') || 'msf',
|
|
password: v('msf-pass'),
|
|
ssl: document.getElementById('msf-ssl').checked,
|
|
};
|
|
}
|
|
|
|
function msfStartServer() {
|
|
const settings = _getServerSettings();
|
|
if (!settings.password) { alert('Password is required'); return; }
|
|
const msg = document.getElementById('server-msg');
|
|
msg.textContent = 'Starting server...';
|
|
|
|
fetch('/offense/server/start', {
|
|
method: 'POST', headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify(settings)
|
|
}).then(r => r.json()).then(d => {
|
|
msg.textContent = d.ok ? (d.message || 'Started') : ('Error: ' + (d.error || 'unknown'));
|
|
if (d.ok) { document.getElementById('server-panel').style.display = 'none'; checkMSFStatus(); }
|
|
}).catch(e => { msg.textContent = 'Error: ' + e.message; });
|
|
}
|
|
|
|
function msfConnectOnly() {
|
|
const settings = _getServerSettings();
|
|
if (!settings.password) { alert('Password is required'); return; }
|
|
const msg = document.getElementById('server-msg');
|
|
msg.textContent = 'Connecting...';
|
|
|
|
fetch('/offense/connect', {
|
|
method: 'POST', headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify({password: settings.password})
|
|
}).then(r => r.json()).then(d => {
|
|
msg.textContent = d.ok ? 'Connected' : ('Error: ' + (d.error || 'unknown'));
|
|
if (d.ok) { document.getElementById('server-panel').style.display = 'none'; checkMSFStatus(); }
|
|
}).catch(e => { msg.textContent = 'Error: ' + e.message; });
|
|
}
|
|
|
|
function msfConnect() {
|
|
// Quick connect using saved password
|
|
fetch('/offense/connect', {
|
|
method: 'POST', headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify({})
|
|
}).then(r => r.json()).then(d => {
|
|
if (d.ok) { checkMSFStatus(); }
|
|
else { toggleServerPanel(); document.getElementById('server-msg').textContent = d.error || 'Connection failed — enter password'; }
|
|
});
|
|
}
|
|
|
|
function msfDisconnect() {
|
|
fetch('/offense/disconnect', {method: 'POST'}).then(() => checkMSFStatus());
|
|
}
|
|
|
|
function msfStopServer() {
|
|
if (!confirm('Stop the MSF RPC server?')) return;
|
|
fetch('/offense/server/stop', {method: 'POST'}).then(() => checkMSFStatus());
|
|
}
|
|
|
|
function msfSaveSettings() {
|
|
const settings = _getServerSettings();
|
|
fetch('/offense/settings', {
|
|
method: 'POST', headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify(settings)
|
|
}).then(r => r.json()).then(d => {
|
|
document.getElementById('server-msg').textContent = d.ok ? 'Settings saved' : ('Error: ' + d.error);
|
|
});
|
|
}
|
|
|
|
/* ── Module Execution ───────────────────────────────────────────── */
|
|
function toggleBruteRow() {
|
|
var row = document.getElementById('ssh-brute-row');
|
|
row.style.display = row.style.display === 'none' ? '' : 'none';
|
|
}
|
|
|
|
function runFeaturedModule(key) {
|
|
const cfg = _FEATURED[key];
|
|
if (!cfg) return;
|
|
let path;
|
|
if (key === 'custom') {
|
|
path = v('custom-module');
|
|
} else if (key === 'exploit-run') {
|
|
path = v('exp-module');
|
|
} else {
|
|
path = cfg.path;
|
|
}
|
|
if (!path) { alert('Enter a module path'); return; }
|
|
const opts = cfg.opts();
|
|
// Remove empty string values
|
|
Object.keys(opts).forEach(k => { if (opts[k] === '' || opts[k] === undefined) delete opts[k]; });
|
|
if (!opts.RHOSTS && !['custom'].includes(key)) { alert('Enter a target'); return; }
|
|
runModule(path, opts);
|
|
}
|
|
|
|
function runModule(module_path, options) {
|
|
const out = document.getElementById('module-output');
|
|
const status = document.getElementById('run-status');
|
|
const stopBtn = document.getElementById('run-stop-btn');
|
|
out.innerHTML = '';
|
|
status.textContent = 'Starting ' + module_path + '...';
|
|
stopBtn.style.display = '';
|
|
_currentJobId = null;
|
|
|
|
fetch('/offense/module/run', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify({module_path, options})
|
|
}).then(res => {
|
|
const reader = res.body.getReader();
|
|
const dec = new TextDecoder();
|
|
let buf = '';
|
|
function pump() {
|
|
reader.read().then(({done, value}) => {
|
|
if (done) { status.textContent = 'Finished.'; stopBtn.style.display = 'none'; return; }
|
|
buf += dec.decode(value, {stream: true});
|
|
const parts = buf.split('\n\n');
|
|
buf = parts.pop();
|
|
parts.forEach(part => {
|
|
const line = part.replace(/^data:\s*/, '').trim();
|
|
if (!line) return;
|
|
try {
|
|
const d = JSON.parse(line);
|
|
if (d.job_id) { _currentJobId = d.job_id; status.textContent = 'Running ' + module_path + '…'; }
|
|
if (d.error) { out.innerHTML += '<div class="err">Error: ' + escapeHtml(d.error) + '</div>'; stopBtn.style.display = 'none'; }
|
|
if (d.line) {
|
|
let cls = '';
|
|
if (d.line.includes('[+]')) cls = 'success';
|
|
else if (d.line.includes('[-]') || d.line.includes('Error')) cls = 'err';
|
|
else if (d.line.includes('[!]')) cls = 'warn';
|
|
out.innerHTML += '<div class="' + cls + '">' + escapeHtml(d.line) + '</div>';
|
|
out.scrollTop = out.scrollHeight;
|
|
}
|
|
if (d.done) {
|
|
status.textContent = 'Done.';
|
|
stopBtn.style.display = 'none';
|
|
if (d.open_ports && d.open_ports.length) {
|
|
out.innerHTML += '<div class="success" style="margin-top:0.5rem;font-weight:600">Open ports: ' + d.open_ports.map(p => escapeHtml(String(p.port || p))).join(', ') + '</div>';
|
|
}
|
|
if (d.services && d.services.length) {
|
|
let html = '<div style="margin-top:0.5rem;font-weight:600;color:var(--accent)">Services detected:</div>';
|
|
d.services.forEach(s => { html += '<div class="success">' + escapeHtml(s.ip + ':' + s.port + ' — ' + s.info) + '</div>'; });
|
|
out.innerHTML += html;
|
|
}
|
|
}
|
|
} catch(e) {}
|
|
});
|
|
pump();
|
|
}).catch(e => { status.textContent = 'Error.'; out.innerHTML += '<div class="err">' + escapeHtml(e.message) + '</div>'; stopBtn.style.display = 'none'; });
|
|
}
|
|
pump();
|
|
}).catch(e => { status.textContent = 'Failed.'; out.innerHTML = '<div class="err">' + escapeHtml(e.message) + '</div>'; stopBtn.style.display = 'none'; });
|
|
}
|
|
|
|
function stopCurrentModule() {
|
|
if (!_currentJobId) return;
|
|
fetch('/offense/module/stop', {method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({job_id: _currentJobId})});
|
|
document.getElementById('run-stop-btn').style.display = 'none';
|
|
document.getElementById('run-status').textContent = 'Stopped.';
|
|
}
|
|
|
|
/* ── Sessions & Jobs ────────────────────────────────────────────── */
|
|
function loadMSFSessions() {
|
|
const el = document.getElementById('msf-sessions');
|
|
fetch('/offense/sessions').then(r => r.json()).then(d => {
|
|
if (d.error) { el.innerHTML = '<div class="empty-state">' + escapeHtml(d.error) + '</div>'; return; }
|
|
const sessions = d.sessions || {};
|
|
const keys = Object.keys(sessions);
|
|
if (!keys.length) { el.innerHTML = '<div class="empty-state">No active sessions.</div>'; return; }
|
|
let html = '<table style="width:100%;font-size:0.85rem"><tr><th>ID</th><th>Type</th><th>Target</th><th>Info</th></tr>';
|
|
keys.forEach(sid => {
|
|
const s = sessions[sid];
|
|
html += '<tr><td>' + escapeHtml(sid) + '</td><td>' + escapeHtml(s.type || '') + '</td><td>' + escapeHtml(s.tunnel_peer || s.target_host || '') + '</td><td>' + escapeHtml(s.info || '') + '</td></tr>';
|
|
});
|
|
html += '</table>';
|
|
el.innerHTML = html;
|
|
}).catch(() => { el.innerHTML = '<div class="empty-state">Failed to load sessions.</div>'; });
|
|
}
|
|
|
|
function loadMSFJobs() {
|
|
const el = document.getElementById('msf-jobs');
|
|
fetch('/offense/jobs').then(r => r.json()).then(d => {
|
|
if (d.error) { el.innerHTML = '<div class="empty-state">' + escapeHtml(d.error) + '</div>'; return; }
|
|
const jobs = d.jobs || {};
|
|
const keys = Object.keys(jobs);
|
|
if (!keys.length) { el.innerHTML = '<div class="empty-state">No running jobs.</div>'; return; }
|
|
let html = '<table style="width:100%;font-size:0.85rem"><tr><th>ID</th><th>Name</th><th></th></tr>';
|
|
keys.forEach(jid => {
|
|
html += '<tr><td>' + escapeHtml(jid) + '</td><td>' + escapeHtml(String(jobs[jid])) + '</td><td><button class="btn btn-sm btn-danger" onclick="stopMSFJob(\'' + escapeHtml(jid) + '\')">Stop</button></td></tr>';
|
|
});
|
|
html += '</table>';
|
|
el.innerHTML = html;
|
|
}).catch(() => { el.innerHTML = '<div class="empty-state">Failed to load jobs.</div>'; });
|
|
}
|
|
|
|
function stopMSFJob(jobId) {
|
|
fetch('/offense/jobs/' + jobId + '/stop', {method:'POST'}).then(() => loadMSFJobs());
|
|
}
|
|
|
|
/* ── Agent Hal ──────────────────────────────────────────────────── */
|
|
async function runHalTask() {
|
|
const task = v('agent-task');
|
|
if (!task) return;
|
|
const out = document.getElementById('agent-output');
|
|
out.innerHTML = '';
|
|
document.getElementById('agent-stop-btn').style.display = '';
|
|
const res = await fetch('/api/agent/run', {method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({task})});
|
|
const data = await res.json();
|
|
if (data.error) { out.innerHTML = '<div class="err">' + escapeHtml(data.error) + '</div>'; document.getElementById('agent-stop-btn').style.display = 'none'; return; }
|
|
_currentRunId = data.run_id;
|
|
streamAgentSteps(data.run_id);
|
|
}
|
|
|
|
function streamAgentSteps(run_id) {
|
|
const out = document.getElementById('agent-output');
|
|
const es = new EventSource('/api/agent/stream/' + run_id);
|
|
es.onmessage = function(e) {
|
|
try {
|
|
const d = JSON.parse(e.data);
|
|
if (d.done) { es.close(); document.getElementById('agent-stop-btn').style.display = 'none'; return; }
|
|
if (d.error) { out.innerHTML += '<div class="err">[error] ' + escapeHtml(d.error) + '</div>'; es.close(); document.getElementById('agent-stop-btn').style.display = 'none'; return; }
|
|
const cls = d.type === 'thought' ? 'dim' : d.type === 'action' ? 'info' : d.type === 'result' ? 'warn' : '';
|
|
out.innerHTML += '<div class="' + cls + '">[' + escapeHtml(d.type || '') + '] ' + escapeHtml(d.content || '') + '</div>';
|
|
out.scrollTop = out.scrollHeight;
|
|
} catch(err) {}
|
|
};
|
|
}
|
|
|
|
async function stopHalTask() {
|
|
if (_currentRunId) await fetch('/api/agent/stop/' + _currentRunId, {method:'POST'});
|
|
document.getElementById('agent-stop-btn').style.display = 'none';
|
|
}
|
|
</script>
|
|
{% endblock %}
|