No One Can Stop Me Now
This commit is contained in:
@@ -29,6 +29,7 @@
|
||||
<div class="nav-section">
|
||||
<ul class="nav-links">
|
||||
<li><a href="{{ url_for('dashboard.index') }}" class="{% if request.endpoint == 'dashboard.index' %}active{% endif %}">Dashboard</a></li>
|
||||
<li><a href="{{ url_for('port_scanner.index') }}" class="{% if request.blueprint == 'port_scanner' %}active{% endif %}">🔍 Port Scanner</a></li>
|
||||
<li><a href="{{ url_for('targets.index') }}" class="{% if request.blueprint == 'targets' %}active{% endif %}">Targets</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -97,7 +97,7 @@ let refreshTimer=null;
|
||||
function switchTab(name){
|
||||
document.querySelectorAll('.tab').forEach((t,i)=>t.classList.toggle('active',['dashboard','agents','generate'][i]===name));
|
||||
document.querySelectorAll('.tab-content').forEach(c=>c.style.display='none');
|
||||
document.getElementById('tab-'+name).style.display='';
|
||||
document.getElementById('tab-'+name).style.display='block';
|
||||
if(name==='dashboard'||name==='agents') refreshDashboard();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Linux Defense - AUTARCH{% endblock %}
|
||||
{% block title %}Linux Defense — AUTARCH{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="page-header" style="display:flex;align-items:center;gap:1rem;flex-wrap:wrap">
|
||||
<div>
|
||||
<h1>Linux Defense</h1>
|
||||
<p style="margin:0;font-size:0.85rem;color:var(--text-secondary)">
|
||||
Linux system hardening, iptables firewall management, and log analysis.
|
||||
System hardening, iptables firewall management, and log analysis
|
||||
</p>
|
||||
</div>
|
||||
<a href="{{ url_for('defense.index') }}" class="btn btn-sm" style="margin-left:auto">← Defense</a>
|
||||
</div>
|
||||
|
||||
<!-- Security Audit -->
|
||||
<div class="section">
|
||||
<h2>Security Audit</h2>
|
||||
<div class="tool-actions">
|
||||
<button id="btn-audit" class="btn btn-primary" onclick="linuxRunAudit()">Run Full Audit</button>
|
||||
<div class="card">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1rem;flex-wrap:wrap;gap:0.5rem">
|
||||
<h3 style="margin:0">Security Audit</h3>
|
||||
<button id="btn-audit" class="btn btn-primary btn-sm" onclick="linuxRunAudit()">Run Full Audit</button>
|
||||
</div>
|
||||
<div style="display:flex;gap:24px;align-items:flex-start;flex-wrap:wrap">
|
||||
<div class="score-display">
|
||||
<div class="score-value" id="audit-score">--</div>
|
||||
<div class="score-label">Security Score</div>
|
||||
<div style="text-align:center;padding:12px 20px;background:var(--bg-primary);border:1px solid var(--border);border-radius:var(--radius);min-width:120px">
|
||||
<div id="audit-score" style="font-size:2.5rem;font-weight:700;line-height:1">--</div>
|
||||
<div style="font-size:0.78rem;color:var(--text-secondary);margin-top:4px">Security Score</div>
|
||||
</div>
|
||||
<div style="flex:1;min-width:300px">
|
||||
<div style="flex:1;min-width:280px">
|
||||
<table class="data-table">
|
||||
<thead><tr><th>Check</th><th>Status</th><th>Details</th></tr></thead>
|
||||
<tbody id="audit-results">
|
||||
@@ -34,94 +34,53 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Individual Checks -->
|
||||
<div class="section">
|
||||
<h2>Quick Checks</h2>
|
||||
<div class="tool-grid">
|
||||
<div class="tool-card">
|
||||
<h4>Firewall</h4>
|
||||
<p>Check iptables/ufw/firewalld status</p>
|
||||
<button class="btn btn-small" onclick="linuxRunCheck('firewall')">Run</button>
|
||||
<pre class="output-panel tool-result" id="check-result-firewall"></pre>
|
||||
</div>
|
||||
<div class="tool-card">
|
||||
<h4>SSH Config</h4>
|
||||
<p>Check SSH hardening settings</p>
|
||||
<button class="btn btn-small" onclick="linuxRunCheck('ssh')">Run</button>
|
||||
<pre class="output-panel tool-result" id="check-result-ssh"></pre>
|
||||
</div>
|
||||
<div class="tool-card">
|
||||
<h4>Open Ports</h4>
|
||||
<p>Scan for high-risk listening ports</p>
|
||||
<button class="btn btn-small" onclick="linuxRunCheck('ports')">Run</button>
|
||||
<pre class="output-panel tool-result" id="check-result-ports"></pre>
|
||||
</div>
|
||||
<div class="tool-card">
|
||||
<h4>Users</h4>
|
||||
<p>Check UID 0 users and empty passwords</p>
|
||||
<button class="btn btn-small" onclick="linuxRunCheck('users')">Run</button>
|
||||
<pre class="output-panel tool-result" id="check-result-users"></pre>
|
||||
</div>
|
||||
<div class="tool-card">
|
||||
<h4>Permissions</h4>
|
||||
<p>Check critical file permissions</p>
|
||||
<button class="btn btn-small" onclick="linuxRunCheck('permissions')">Run</button>
|
||||
<pre class="output-panel tool-result" id="check-result-permissions"></pre>
|
||||
</div>
|
||||
<div class="tool-card">
|
||||
<h4>Services</h4>
|
||||
<p>Check for dangerous services</p>
|
||||
<button class="btn btn-small" onclick="linuxRunCheck('services')">Run</button>
|
||||
<pre class="output-panel tool-result" id="check-result-services"></pre>
|
||||
<!-- Quick Checks -->
|
||||
<div class="card">
|
||||
<h3>Quick Checks</h3>
|
||||
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:10px">
|
||||
{% for check_id, check_name, check_desc in [
|
||||
('firewall', 'Firewall', 'Check iptables/ufw/firewalld status'),
|
||||
('ssh', 'SSH Config', 'Check SSH hardening settings'),
|
||||
('ports', 'Open Ports', 'Scan for high-risk listening ports'),
|
||||
('users', 'Users', 'Check UID 0 users and empty passwords'),
|
||||
('permissions', 'Permissions', 'Check critical file permissions'),
|
||||
('services', 'Services', 'Check for dangerous services')
|
||||
] %}
|
||||
<div style="background:var(--bg-primary);border:1px solid var(--border);border-radius:var(--radius);padding:14px">
|
||||
<div style="font-weight:600;font-size:0.88rem;margin-bottom:4px">{{ check_name }}</div>
|
||||
<div style="color:var(--text-secondary);font-size:0.78rem;margin-bottom:10px">{{ check_desc }}</div>
|
||||
<button class="btn btn-sm" style="width:100%" onclick="linuxRunCheck('{{ check_id }}')">Run</button>
|
||||
<pre class="output-panel tool-result" id="check-result-{{ check_id }}" style="display:none;margin-top:10px;font-size:0.75rem;min-height:0"></pre>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Firewall Manager -->
|
||||
<div class="section">
|
||||
<h2>Firewall Manager (iptables)</h2>
|
||||
<div class="tool-actions">
|
||||
<button class="btn btn-small" onclick="linuxLoadFwRules()">Refresh Rules</button>
|
||||
<div class="card">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1rem;flex-wrap:wrap;gap:0.5rem">
|
||||
<h3 style="margin:0">Firewall Manager (iptables)</h3>
|
||||
<button class="btn btn-sm" onclick="linuxLoadFwRules()">Refresh Rules</button>
|
||||
</div>
|
||||
<pre class="output-panel scrollable" id="fw-rules">Click "Refresh Rules" to load current iptables rules.</pre>
|
||||
<div style="margin-top:12px">
|
||||
<div class="input-row">
|
||||
<input type="text" id="block-ip" placeholder="IP address to block">
|
||||
<button class="btn btn-danger btn-small" onclick="linuxBlockIP()">Block IP</button>
|
||||
<button class="btn btn-small" onclick="linuxUnblockIP()">Unblock IP</button>
|
||||
</div>
|
||||
<pre class="output-panel" id="fw-result" style="min-height:0"></pre>
|
||||
<pre class="output-panel" id="fw-rules" style="max-height:300px;overflow-y:auto">Click "Refresh Rules" to load current iptables rules.</pre>
|
||||
<div style="display:flex;gap:8px;margin-top:12px;flex-wrap:wrap">
|
||||
<input type="text" id="block-ip" class="form-control" placeholder="IP address to block" style="flex:1;min-width:180px">
|
||||
<button class="btn btn-sm btn-danger" onclick="linuxBlockIP()">Block IP</button>
|
||||
<button class="btn btn-sm" onclick="linuxUnblockIP()">Unblock IP</button>
|
||||
</div>
|
||||
<pre class="output-panel" id="fw-result" style="min-height:0;margin-top:8px"></pre>
|
||||
</div>
|
||||
|
||||
<!-- Log Analysis -->
|
||||
<div class="section">
|
||||
<h2>Log Analysis</h2>
|
||||
<div class="tool-actions">
|
||||
<button id="btn-logs" class="btn btn-primary" onclick="linuxAnalyzeLogs()">Analyze Logs</button>
|
||||
<div class="card">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1rem;flex-wrap:wrap;gap:0.5rem">
|
||||
<h3 style="margin:0">Log Analysis</h3>
|
||||
<button id="btn-logs" class="btn btn-primary btn-sm" onclick="linuxAnalyzeLogs()">Analyze Logs</button>
|
||||
</div>
|
||||
<pre class="output-panel scrollable" id="log-output">Click "Analyze Logs" to parse auth and web server logs.</pre>
|
||||
<pre class="output-panel" id="log-output" style="max-height:350px;overflow-y:auto">Click "Analyze Logs" to parse auth and web server logs.</pre>
|
||||
</div>
|
||||
|
||||
{% if modules %}
|
||||
<div class="section">
|
||||
<h2>Defense 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 %}
|
||||
|
||||
<script>
|
||||
/* ── Linux Defense (routes prefixed with /defense/linux/) ── */
|
||||
function linuxRunAudit() {
|
||||
var btn = document.getElementById('btn-audit');
|
||||
setLoading(btn, true);
|
||||
|
||||
@@ -15,29 +15,62 @@
|
||||
|
||||
<!-- Scan Tab -->
|
||||
<div id="tab-scan" class="tab-content active">
|
||||
<div class="card" style="max-width:700px">
|
||||
<h3>Target Scan</h3>
|
||||
<div class="form-group">
|
||||
<label>Target IP Address</label>
|
||||
<input type="text" id="hh-target" class="form-control" placeholder="192.168.1.100">
|
||||
<div style="display:grid;grid-template-columns:360px 1fr;gap:1.5rem;align-items:start">
|
||||
<!-- Config panel -->
|
||||
<div class="card">
|
||||
<h3>Target Scan</h3>
|
||||
<div class="form-group">
|
||||
<label>Target IP Address</label>
|
||||
<input type="text" id="hh-target" class="form-control" placeholder="192.168.1.100">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Scan Type</label>
|
||||
<select id="hh-scan-type" class="form-control" onchange="toggleCustomPorts()">
|
||||
<option value="quick">Quick — Backdoor signature ports only (~30 ports)</option>
|
||||
<option value="full">Full — All suspicious ports (~70 ports)</option>
|
||||
<option value="nmap">Nmap Deep — Service version + OS detection (requires nmap)</option>
|
||||
<option value="custom">Custom — Specify ports</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" id="custom-ports-group" style="display:none">
|
||||
<label>Custom Ports (comma-separated)</label>
|
||||
<input type="text" id="hh-custom-ports" class="form-control" placeholder="22,80,443,445,4444,8080">
|
||||
</div>
|
||||
<div style="display:flex;gap:0.5rem">
|
||||
<button id="hh-scan-btn" class="btn btn-primary" onclick="startScan()" style="flex:1">Scan for Compromises</button>
|
||||
<button id="hh-cancel-btn" class="btn" style="display:none;background:var(--danger);color:#fff" onclick="cancelScan()">Cancel</button>
|
||||
</div>
|
||||
|
||||
<!-- Progress bar -->
|
||||
<div id="hh-progress-wrap" style="display:none;margin-top:1rem">
|
||||
<div style="display:flex;justify-content:space-between;font-size:0.8rem;margin-bottom:4px">
|
||||
<span id="hh-prog-label">Scanning…</span>
|
||||
<span id="hh-prog-pct">0%</span>
|
||||
</div>
|
||||
<div style="background:var(--border);border-radius:4px;height:6px;overflow:hidden">
|
||||
<div id="hh-prog-bar" style="height:100%;background:var(--accent);transition:width 0.3s;width:0"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Scan Type</label>
|
||||
<select id="hh-scan-type" class="form-control" onchange="toggleCustomPorts()">
|
||||
<option value="quick">Quick — Backdoor signature ports only (~30 ports)</option>
|
||||
<option value="full">Full — All suspicious ports (~70 ports)</option>
|
||||
<option value="nmap">Nmap Deep — Service version + OS detection (requires nmap)</option>
|
||||
<option value="custom">Custom — Specify ports</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" id="custom-ports-group" style="display:none">
|
||||
<label>Custom Ports (comma-separated)</label>
|
||||
<input type="text" id="hh-custom-ports" class="form-control" placeholder="22,80,443,445,4444,8080">
|
||||
</div>
|
||||
<button id="hh-scan-btn" class="btn btn-primary" onclick="startScan()">Scan for Compromises</button>
|
||||
<div id="hh-scan-status" style="margin-top:1rem;display:none">
|
||||
<div class="spinner-inline"></div>
|
||||
<span id="hh-scan-msg">Scanning...</span>
|
||||
|
||||
<!-- Live output -->
|
||||
<div class="card" style="display:flex;flex-direction:column">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:0.5rem">
|
||||
<h3 style="margin:0">Live Output</h3>
|
||||
<button class="btn btn-sm" onclick="clearOutput()">Clear</button>
|
||||
</div>
|
||||
<pre id="hh-output" style="background:#0d0d14;color:#c9d1d9;font-family:monospace;font-size:0.78rem;
|
||||
padding:12px;border-radius:var(--radius);height:340px;overflow-y:auto;
|
||||
white-space:pre-wrap;word-break:break-all;margin:0;border:1px solid var(--border)">Ready. Enter target and click Scan.</pre>
|
||||
|
||||
<!-- Live found ports mini-table -->
|
||||
<div id="hh-live-ports" style="margin-top:0.75rem;display:none">
|
||||
<h4 style="font-size:0.8rem;color:var(--text-secondary);margin-bottom:6px">Live Discovered Ports</h4>
|
||||
<table class="data-table" style="font-size:0.78rem">
|
||||
<thead><tr><th>Port</th><th>Service</th><th>Banner</th></tr></thead>
|
||||
<tbody id="hh-live-ports-body"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -141,8 +174,6 @@
|
||||
.conf-high{color:var(--danger);font-weight:700}
|
||||
.conf-medium{color:#f59e0b;font-weight:600}
|
||||
.conf-low{color:var(--text-muted)}
|
||||
.spinner-inline{display:inline-block;width:14px;height:14px;border:2px solid var(--border);border-top-color:var(--accent);border-radius:50%;animation:spin 0.8s linear infinite;vertical-align:middle;margin-right:6px}
|
||||
@keyframes spin{to{transform:rotate(360deg)}}
|
||||
.cat-eternalblue{color:var(--danger)}
|
||||
.cat-rat{color:#f59e0b}
|
||||
.cat-shell{color:#6366f1}
|
||||
@@ -150,18 +181,26 @@
|
||||
.cat-proxy{color:#8b5cf6}
|
||||
.cat-miner{color:#06b6d4}
|
||||
.cat-generic{color:var(--text-secondary)}
|
||||
/* output line colors */
|
||||
#hh-output .ln-status{color:#7dd3fc}
|
||||
#hh-output .ln-open{color:#4ade80;font-weight:700}
|
||||
#hh-output .ln-warn{color:#fbbf24}
|
||||
#hh-output .ln-error{color:#f87171}
|
||||
#hh-output .ln-done{color:#a78bfa;font-weight:700}
|
||||
#hh-output .ln-prog{color:#6b7280}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
let currentScanResult = null;
|
||||
let currentSessionId = null;
|
||||
let pollTimer = null;
|
||||
let activeStream = null;
|
||||
let currentJobId = null;
|
||||
|
||||
function switchTab(name){
|
||||
document.querySelectorAll('.tab').forEach((t,i)=>t.classList.toggle('active',
|
||||
['scan','results','sessions','history'][i]===name));
|
||||
document.querySelectorAll('.tab-content').forEach(c=>c.style.display='none');
|
||||
document.getElementById('tab-'+name).style.display='';
|
||||
document.getElementById('tab-'+name).style.display='block';
|
||||
if(name==='sessions') loadSessions();
|
||||
if(name==='history') loadHistory();
|
||||
}
|
||||
@@ -171,57 +210,148 @@ function toggleCustomPorts(){
|
||||
document.getElementById('hh-scan-type').value==='custom'?'':'none';
|
||||
}
|
||||
|
||||
function appendOutput(text, cls){
|
||||
const out = document.getElementById('hh-output');
|
||||
const line = document.createElement('span');
|
||||
if(cls) line.className = cls;
|
||||
line.textContent = text + '\n';
|
||||
out.appendChild(line);
|
||||
out.scrollTop = out.scrollHeight;
|
||||
}
|
||||
|
||||
function clearOutput(){
|
||||
document.getElementById('hh-output').textContent = '';
|
||||
}
|
||||
|
||||
function startScan(){
|
||||
const target=document.getElementById('hh-target').value.trim();
|
||||
if(!target){alert('Enter a target IP');return}
|
||||
const scanType=document.getElementById('hh-scan-type').value;
|
||||
let customPorts=[];
|
||||
if(scanType==='custom'){
|
||||
customPorts=document.getElementById('hh-custom-ports').value
|
||||
const target = document.getElementById('hh-target').value.trim();
|
||||
if(!target){ alert('Enter a target IP'); return; }
|
||||
const scanType = document.getElementById('hh-scan-type').value;
|
||||
let customPorts = [];
|
||||
if(scanType === 'custom'){
|
||||
customPorts = document.getElementById('hh-custom-ports').value
|
||||
.split(',').map(p=>parseInt(p.trim())).filter(p=>p>0&&p<65536);
|
||||
if(!customPorts.length){alert('Enter valid ports');return}
|
||||
if(!customPorts.length){ alert('Enter valid ports'); return; }
|
||||
}
|
||||
document.getElementById('hh-scan-btn').disabled=true;
|
||||
document.getElementById('hh-scan-status').style.display='';
|
||||
document.getElementById('hh-scan-msg').textContent='Scanning '+target+'...';
|
||||
|
||||
fetch('/hack-hijack/scan',{method:'POST',headers:{'Content-Type':'application/json'},
|
||||
body:JSON.stringify({target,scan_type:scanType,custom_ports:customPorts})})
|
||||
// Reset UI
|
||||
clearOutput();
|
||||
document.getElementById('hh-live-ports').style.display = 'none';
|
||||
document.getElementById('hh-live-ports-body').innerHTML = '';
|
||||
document.getElementById('hh-scan-btn').disabled = true;
|
||||
document.getElementById('hh-cancel-btn').style.display = '';
|
||||
document.getElementById('hh-progress-wrap').style.display = '';
|
||||
document.getElementById('hh-prog-bar').style.width = '0';
|
||||
document.getElementById('hh-prog-pct').textContent = '0%';
|
||||
document.getElementById('hh-prog-label').textContent = 'Starting…';
|
||||
appendOutput(`[*] Starting ${scanType} scan on ${target}…`, 'ln-status');
|
||||
|
||||
fetch('/hack-hijack/scan', {method:'POST', headers:{'Content-Type':'application/json'},
|
||||
body: JSON.stringify({target, scan_type: scanType, custom_ports: customPorts})})
|
||||
.then(r=>r.json()).then(d=>{
|
||||
if(!d.ok){showScanError(d.error);return}
|
||||
pollScan(d.job_id);
|
||||
}).catch(e=>showScanError(e.message));
|
||||
if(!d.ok){ scanDone(false, d.error); return; }
|
||||
currentJobId = d.job_id;
|
||||
openStream(d.job_id);
|
||||
}).catch(e=>scanDone(false, e.message));
|
||||
}
|
||||
|
||||
function pollScan(jobId){
|
||||
if(pollTimer) clearInterval(pollTimer);
|
||||
pollTimer=setInterval(()=>{
|
||||
fetch('/hack-hijack/scan/'+jobId).then(r=>r.json()).then(d=>{
|
||||
if(!d.done) return;
|
||||
clearInterval(pollTimer);pollTimer=null;
|
||||
document.getElementById('hh-scan-btn').disabled=false;
|
||||
document.getElementById('hh-scan-status').style.display='none';
|
||||
if(!d.ok){showScanError(d.error);return}
|
||||
currentScanResult=d.result;
|
||||
renderResults(d.result);
|
||||
switchTab('results');
|
||||
}).catch(()=>{});
|
||||
},1500);
|
||||
function openStream(jobId){
|
||||
if(activeStream){ activeStream.close(); activeStream = null; }
|
||||
const es = new EventSource('/hack-hijack/scan/' + jobId + '/stream');
|
||||
activeStream = es;
|
||||
|
||||
es.onmessage = function(e){
|
||||
try{ handleEvent(JSON.parse(e.data)); } catch(ex){}
|
||||
};
|
||||
es.onerror = function(){
|
||||
es.close(); activeStream = null;
|
||||
appendOutput('[!] Stream connection lost', 'ln-error');
|
||||
scanDone(false, 'Stream disconnected');
|
||||
};
|
||||
}
|
||||
|
||||
function showScanError(msg){
|
||||
document.getElementById('hh-scan-btn').disabled=false;
|
||||
document.getElementById('hh-scan-status').style.display='none';
|
||||
alert('Scan error: '+msg);
|
||||
function handleEvent(ev){
|
||||
switch(ev.type){
|
||||
case 'progress': {
|
||||
const pct = ev.pct || 0;
|
||||
document.getElementById('hh-prog-bar').style.width = pct + '%';
|
||||
document.getElementById('hh-prog-pct').textContent = pct + '%';
|
||||
if(ev.msg) document.getElementById('hh-prog-label').textContent = ev.msg;
|
||||
if(ev.msg) appendOutput('[~] ' + ev.msg, 'ln-prog');
|
||||
break;
|
||||
}
|
||||
case 'status':
|
||||
appendOutput('[*] ' + ev.msg, 'ln-status');
|
||||
document.getElementById('hh-prog-label').textContent = ev.msg;
|
||||
break;
|
||||
case 'port_found': {
|
||||
const svc = ev.service ? ` (${ev.service})` : '';
|
||||
const banner = ev.banner ? ` "${ev.banner.slice(0,60)}"` : '';
|
||||
appendOutput(`[+] OPEN ${ev.port}/tcp${svc}${banner}`, 'ln-open');
|
||||
addLivePort(ev.port, ev.service, ev.banner);
|
||||
break;
|
||||
}
|
||||
case 'error':
|
||||
appendOutput('[!] ' + ev.msg, 'ln-error');
|
||||
break;
|
||||
case 'done':
|
||||
if(activeStream){ activeStream.close(); activeStream = null; }
|
||||
document.getElementById('hh-prog-bar').style.width = '100%';
|
||||
document.getElementById('hh-prog-pct').textContent = '100%';
|
||||
if(ev.ok){
|
||||
appendOutput('[✓] Scan complete — fetching results…', 'ln-done');
|
||||
fetchResult(currentJobId);
|
||||
} else {
|
||||
appendOutput('[!] Scan failed', 'ln-error');
|
||||
scanDone(false, 'Scan failed');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function addLivePort(port, service, banner){
|
||||
const tbody = document.getElementById('hh-live-ports-body');
|
||||
document.getElementById('hh-live-ports').style.display = '';
|
||||
const tr = document.createElement('tr');
|
||||
tr.innerHTML = `<td>${port}</td><td>${esc(service||'—')}</td>
|
||||
<td style="font-family:monospace;font-size:0.72rem;max-width:300px;overflow:hidden;text-overflow:ellipsis">${esc((banner||'').slice(0,80))}</td>`;
|
||||
tbody.appendChild(tr);
|
||||
}
|
||||
|
||||
function fetchResult(jobId){
|
||||
fetch('/hack-hijack/scan/' + jobId)
|
||||
.then(r=>r.json()).then(d=>{
|
||||
if(!d.done){ setTimeout(()=>fetchResult(jobId), 500); return; }
|
||||
if(!d.ok){ scanDone(false, d.error); return; }
|
||||
currentScanResult = d.result;
|
||||
appendOutput(`[✓] Done — ${d.result.open_ports.length} ports, ${d.result.backdoors.length} backdoor indicators`, 'ln-done');
|
||||
scanDone(true);
|
||||
renderResults(d.result);
|
||||
switchTab('results');
|
||||
}).catch(e=>scanDone(false, e.message));
|
||||
}
|
||||
|
||||
function scanDone(ok, errMsg){
|
||||
document.getElementById('hh-scan-btn').disabled = false;
|
||||
document.getElementById('hh-cancel-btn').style.display = 'none';
|
||||
document.getElementById('hh-progress-wrap').style.display = 'none';
|
||||
if(!ok && errMsg) appendOutput('[!] Error: ' + errMsg, 'ln-error');
|
||||
currentJobId = null;
|
||||
}
|
||||
|
||||
function cancelScan(){
|
||||
if(activeStream){ activeStream.close(); activeStream = null; }
|
||||
appendOutput('[x] Scan cancelled by user', 'ln-warn');
|
||||
scanDone(false);
|
||||
}
|
||||
|
||||
function renderResults(r){
|
||||
document.getElementById('hh-no-results').style.display='none';
|
||||
document.getElementById('hh-results').style.display='';
|
||||
document.getElementById('res-target').textContent=r.target;
|
||||
document.getElementById('res-time').textContent=r.scan_time.replace('T',' ').slice(0,19)+' UTC';
|
||||
document.getElementById('res-ports-count').textContent=r.open_ports.length;
|
||||
document.getElementById('res-backdoors-count').textContent=r.backdoors.length;
|
||||
document.getElementById('res-time').textContent=(r.scan_time||'').replace('T',' ').slice(0,19)+' UTC';
|
||||
document.getElementById('res-ports-count').textContent=(r.open_ports||[]).length;
|
||||
document.getElementById('res-backdoors-count').textContent=(r.backdoors||[]).length;
|
||||
document.getElementById('res-duration').textContent=r.duration;
|
||||
if(r.os_guess){
|
||||
document.getElementById('res-os').style.display='';
|
||||
@@ -231,7 +361,7 @@ function renderResults(r){
|
||||
// Ports table
|
||||
const pb=document.getElementById('hh-ports-body');
|
||||
pb.innerHTML='';
|
||||
r.open_ports.forEach(p=>{
|
||||
(r.open_ports||[]).forEach(p=>{
|
||||
const tr=document.createElement('tr');
|
||||
tr.innerHTML=`<td>${p.port}</td><td>${p.protocol}</td><td>${p.service||'—'}</td>
|
||||
<td style="font-family:monospace;font-size:0.75rem;max-width:400px;overflow:hidden;text-overflow:ellipsis">${esc(p.banner||'')}</td>`;
|
||||
@@ -241,7 +371,7 @@ function renderResults(r){
|
||||
// Backdoors
|
||||
const bs=document.getElementById('hh-backdoors-section');
|
||||
const bb=document.getElementById('hh-backdoors-body');
|
||||
if(r.backdoors.length){
|
||||
if((r.backdoors||[]).length){
|
||||
bs.style.display='';
|
||||
bb.innerHTML='';
|
||||
r.backdoors.forEach((b,i)=>{
|
||||
@@ -285,7 +415,6 @@ function tryTakeover(idx){
|
||||
} else {
|
||||
alert(d.message||d.error||'Takeover result received');
|
||||
if(d.msf_command){
|
||||
// Copy MSF command to clipboard
|
||||
navigator.clipboard.writeText(d.msf_command).then(()=>{
|
||||
alert('MSF command copied to clipboard');
|
||||
}).catch(()=>{});
|
||||
@@ -311,7 +440,7 @@ function loadSessions(){
|
||||
onclick="openShell('${esc(s.session_id)}','${esc(s.host)}:${s.port}','')">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center">
|
||||
<div><strong>${esc(s.type)}</strong> → ${esc(s.host)}:${s.port}</div>
|
||||
<div style="font-size:0.75rem;color:var(--text-muted)">${s.connected_at.slice(0,19)}</div>
|
||||
<div style="font-size:0.75rem;color:var(--text-muted)">${(s.connected_at||'').slice(0,19)}</div>
|
||||
</div></div>`).join('');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ let discPoll=null;
|
||||
function switchTab(name){
|
||||
document.querySelectorAll('.tab').forEach((t,i)=>t.classList.toggle('active',['discover','map','scans'][i]===name));
|
||||
document.querySelectorAll('.tab-content').forEach(c=>c.style.display='none');
|
||||
document.getElementById('tab-'+name).style.display='';
|
||||
document.getElementById('tab-'+name).style.display='block';
|
||||
if(name==='scans') loadScans();
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ function switchTab(name){
|
||||
document.querySelectorAll('.tab').forEach((t,i)=>t.classList.toggle('active',
|
||||
['identify','crack','generate','spray','wordlists'][i]===name));
|
||||
document.querySelectorAll('.tab-content').forEach(c=>c.style.display='none');
|
||||
document.getElementById('tab-'+name).style.display='';
|
||||
document.getElementById('tab-'+name).style.display='block';
|
||||
if(name==='crack') loadTools();
|
||||
if(name==='wordlists') loadWordlists();
|
||||
}
|
||||
|
||||
402
web/templates/port_scanner.html
Normal file
402
web/templates/port_scanner.html
Normal file
@@ -0,0 +1,402 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Port Scanner — AUTARCH{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
<div class="page-header">
|
||||
<h1>Port Scanner</h1>
|
||||
<p class="text-muted" style="font-size:0.85rem;color:var(--text-secondary)">
|
||||
Advanced TCP port scanner with nmap integration and real-time live output
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div style="display:grid;grid-template-columns:380px 1fr;gap:1.25rem;align-items:start">
|
||||
|
||||
<!-- ── Config Panel ── -->
|
||||
<div>
|
||||
<div class="card">
|
||||
<h3>Scan Configuration</h3>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Target Host / IP</label>
|
||||
<input type="text" id="ps-target" class="form-control"
|
||||
placeholder="192.168.1.1 or hostname.local"
|
||||
onkeypress="if(event.key==='Enter')startScan()">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Scan Mode</label>
|
||||
<select id="ps-mode" class="form-control" onchange="onModeChange()">
|
||||
<option value="quick">Quick — 22 common ports (~1s)</option>
|
||||
<option value="common" selected>Common — 110 well-known ports (~5s)</option>
|
||||
<option value="full">Full — All 65,535 ports (may take minutes)</option>
|
||||
<option value="custom">Custom — Specify ports / ranges</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="custom-ports-group" style="display:none">
|
||||
<label>Ports / Ranges (e.g. 22,80,443,8000-9000)</label>
|
||||
<input type="text" id="ps-custom-ports" class="form-control"
|
||||
placeholder="22,80,443,1024-2048">
|
||||
</div>
|
||||
|
||||
<!-- Options -->
|
||||
<div style="padding:12px;background:var(--bg-primary);border:1px solid var(--border);border-radius:var(--radius);margin-bottom:14px">
|
||||
<div style="font-size:0.75rem;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:10px">Options</div>
|
||||
|
||||
<div style="display:flex;flex-wrap:wrap;gap:10px;margin-bottom:10px">
|
||||
<label style="display:flex;align-items:center;gap:6px;font-size:0.83rem;cursor:pointer">
|
||||
<input type="checkbox" id="opt-nmap" style="width:auto"> Use nmap
|
||||
</label>
|
||||
<label style="display:flex;align-items:center;gap:6px;font-size:0.83rem;cursor:pointer">
|
||||
<input type="checkbox" id="opt-svc" style="width:auto"> Service detection (-sV)
|
||||
</label>
|
||||
<label style="display:flex;align-items:center;gap:6px;font-size:0.83rem;cursor:pointer">
|
||||
<input type="checkbox" id="opt-os" style="width:auto"> OS fingerprint (-O)
|
||||
</label>
|
||||
<label style="display:flex;align-items:center;gap:6px;font-size:0.83rem;cursor:pointer">
|
||||
<input type="checkbox" id="opt-agg" style="width:auto"> Aggressive (-A)
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px">
|
||||
<div>
|
||||
<div style="font-size:0.75rem;color:var(--text-muted);margin-bottom:3px">Timeout (s)</div>
|
||||
<input type="number" id="opt-timeout" class="form-control" value="1.0" min="0.1" max="10" step="0.1">
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-size:0.75rem;color:var(--text-muted);margin-bottom:3px">Concurrency</div>
|
||||
<input type="number" id="opt-concurrency" class="form-control" value="200" min="1" max="500">
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-size:0.75rem;color:var(--text-muted);margin-bottom:3px">nmap Timing</div>
|
||||
<select id="opt-timing" class="form-control">
|
||||
<option value="2">T2 — Polite</option>
|
||||
<option value="3">T3 — Normal</option>
|
||||
<option value="4" selected>T4 — Aggressive</option>
|
||||
<option value="5">T5 — Insane</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display:flex;gap:8px">
|
||||
<button id="ps-start-btn" class="btn btn-primary" style="flex:1" onclick="startScan()">
|
||||
▶ Start Scan
|
||||
</button>
|
||||
<button id="ps-cancel-btn" class="btn btn-danger btn-small" style="display:none"
|
||||
onclick="cancelScan()">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stats Card -->
|
||||
<div class="card" id="stats-card" style="display:none">
|
||||
<h3>Scan Stats</h3>
|
||||
<table style="width:100%;font-size:0.85rem">
|
||||
<tr><td style="color:var(--text-muted);padding:3px 0">Target</td>
|
||||
<td id="st-target" style="text-align:right;color:var(--accent)"></td></tr>
|
||||
<tr><td style="color:var(--text-muted);padding:3px 0">Ports Scanned</td>
|
||||
<td id="st-scanned" style="text-align:right"></td></tr>
|
||||
<tr><td style="color:var(--text-muted);padding:3px 0">Open Ports</td>
|
||||
<td id="st-open" style="text-align:right;color:var(--success);font-weight:700"></td></tr>
|
||||
<tr><td style="color:var(--text-muted);padding:3px 0">Duration</td>
|
||||
<td id="st-duration" style="text-align:right"></td></tr>
|
||||
<tr id="st-os-row" style="display:none">
|
||||
<td style="color:var(--text-muted);padding:3px 0">OS Guess</td>
|
||||
<td id="st-os" style="text-align:right;font-size:0.8rem"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── Right Panel — Output + Results ── -->
|
||||
<div>
|
||||
<!-- Progress bar -->
|
||||
<div id="ps-progress-wrap" style="display:none;margin-bottom:1rem">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px">
|
||||
<span id="ps-progress-label" style="font-size:0.82rem;color:var(--text-secondary)">Initializing...</span>
|
||||
<span id="ps-progress-pct" style="font-size:0.82rem;font-weight:600;color:var(--accent)">0%</span>
|
||||
</div>
|
||||
<div style="background:var(--bg-input);border-radius:4px;height:6px;overflow:hidden">
|
||||
<div id="ps-progress-bar" style="height:100%;background:var(--accent);
|
||||
transition:width 0.3s;border-radius:4px;width:0%"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Live output box -->
|
||||
<div class="card" style="padding:0;overflow:hidden">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;
|
||||
padding:10px 16px;border-bottom:1px solid var(--border)">
|
||||
<span style="font-size:0.8rem;font-weight:600;letter-spacing:0.05em">LIVE OUTPUT</span>
|
||||
<div style="display:flex;gap:6px;align-items:center">
|
||||
<span id="ps-status-dot" style="width:8px;height:8px;border-radius:50%;
|
||||
background:var(--text-muted);display:inline-block"></span>
|
||||
<span id="ps-status-txt" style="font-size:0.75rem;color:var(--text-muted)">Idle</span>
|
||||
<button class="btn btn-small" style="font-size:0.7rem;padding:3px 8px"
|
||||
onclick="clearOutput()">Clear</button>
|
||||
</div>
|
||||
</div>
|
||||
<pre id="ps-output" style="background:var(--bg-primary);color:#c8d3f5;
|
||||
font-family:'Cascadia Code','Fira Code','Consolas',monospace;
|
||||
font-size:0.78rem;line-height:1.5;padding:14px;margin:0;
|
||||
height:340px;overflow-y:auto;white-space:pre-wrap;word-break:break-all"></pre>
|
||||
</div>
|
||||
|
||||
<!-- Results table -->
|
||||
<div id="ps-results-wrap" style="display:none;margin-top:1rem">
|
||||
<div class="card" style="padding:0;overflow:hidden">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;
|
||||
padding:12px 16px;border-bottom:1px solid var(--border)">
|
||||
<span style="font-weight:600;font-size:0.9rem">
|
||||
Open Ports — <span id="res-count" style="color:var(--success)">0</span> found
|
||||
</span>
|
||||
<div style="display:flex;gap:6px">
|
||||
<button class="btn btn-small" onclick="exportResults('txt')">Export TXT</button>
|
||||
<button class="btn btn-small" onclick="exportResults('json')">Export JSON</button>
|
||||
</div>
|
||||
</div>
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:80px">Port</th>
|
||||
<th style="width:70px">Proto</th>
|
||||
<th style="width:150px">Service</th>
|
||||
<th>Banner / Version</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="ps-results-body"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
#ps-output .ln-info { color: #c8d3f5; }
|
||||
#ps-output .ln-open { color: #4ade80; font-weight: 700; }
|
||||
#ps-output .ln-warn { color: #fbbf24; }
|
||||
#ps-output .ln-error { color: #f87171; }
|
||||
#ps-output .ln-nmap { color: #94a3b8; font-size: 0.73rem; }
|
||||
#ps-output .ln-prog { color: #818cf8; }
|
||||
#ps-output .ln-done { color: #34d399; font-weight: 700; }
|
||||
#ps-output .ln-muted { color: #475569; }
|
||||
.advanced-toggle { font-size: 0.82rem; color: var(--text-secondary); cursor: pointer;
|
||||
user-select: none; display: inline-flex; align-items: center; gap: 4px; }
|
||||
.advanced-toggle:hover { color: var(--text-primary); }
|
||||
</style>
|
||||
|
||||
<script>
|
||||
let _jobId = null;
|
||||
let _es = null;
|
||||
let _openPorts = [];
|
||||
let _scanResult = null;
|
||||
|
||||
function onModeChange() {
|
||||
const mode = document.getElementById('ps-mode').value;
|
||||
document.getElementById('custom-ports-group').style.display =
|
||||
mode === 'custom' ? '' : 'none';
|
||||
}
|
||||
|
||||
|
||||
function startScan() {
|
||||
const target = document.getElementById('ps-target').value.trim();
|
||||
if (!target) { alert('Enter a target host or IP address'); return; }
|
||||
const mode = document.getElementById('ps-mode').value;
|
||||
if (mode === 'custom' && !document.getElementById('ps-custom-ports').value.trim()) {
|
||||
alert('Enter ports or ranges for custom mode'); return;
|
||||
}
|
||||
|
||||
_openPorts = [];
|
||||
_scanResult = null;
|
||||
clearOutput();
|
||||
document.getElementById('ps-results-wrap').style.display = 'none';
|
||||
document.getElementById('stats-card').style.display = 'none';
|
||||
document.getElementById('ps-progress-wrap').style.display = '';
|
||||
|
||||
const payload = {
|
||||
target,
|
||||
mode,
|
||||
ports: document.getElementById('ps-custom-ports').value.trim(),
|
||||
use_nmap: document.getElementById('opt-nmap').checked,
|
||||
service_detection: document.getElementById('opt-svc').checked,
|
||||
os_detection: document.getElementById('opt-os').checked,
|
||||
aggressive: document.getElementById('opt-agg').checked,
|
||||
timing: document.getElementById('opt-timing').value,
|
||||
timeout: parseFloat(document.getElementById('opt-timeout').value) || 1.0,
|
||||
concurrency: parseInt(document.getElementById('opt-concurrency').value) || 200,
|
||||
};
|
||||
|
||||
fetch('/port-scanner/start', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
}).then(r => r.json()).then(d => {
|
||||
if (!d.ok) { appendLine('error', '✗ ' + d.error); return; }
|
||||
_jobId = d.job_id;
|
||||
setStatus('scanning', 'Scanning...');
|
||||
document.getElementById('ps-start-btn').disabled = true;
|
||||
document.getElementById('ps-cancel-btn').style.display = '';
|
||||
appendLine('info', `► Scan started | job=${d.job_id} | ${d.port_count} ports queued`);
|
||||
openStream(d.job_id);
|
||||
}).catch(e => appendLine('error', '✗ ' + e.message));
|
||||
}
|
||||
|
||||
function openStream(jobId) {
|
||||
if (_es) { _es.close(); _es = null; }
|
||||
_es = new EventSource('/port-scanner/stream/' + jobId);
|
||||
_es.onmessage = e => handleEvent(JSON.parse(e.data));
|
||||
_es.onerror = () => { setStatus('idle', 'Connection lost'); };
|
||||
}
|
||||
|
||||
function handleEvent(ev) {
|
||||
switch (ev.type) {
|
||||
case 'start':
|
||||
appendLine('info', `▶ Target: ${ev.target} | Ports: ${ev.total_ports} | Mode: ${ev.mode}`);
|
||||
setProgress(0, ev.total_ports, '0%', 'Starting...');
|
||||
document.getElementById('st-target').textContent = ev.target;
|
||||
document.getElementById('st-scanned').textContent = ev.total_ports;
|
||||
document.getElementById('stats-card').style.display = '';
|
||||
break;
|
||||
case 'info':
|
||||
appendLine('info', ' ' + ev.msg);
|
||||
break;
|
||||
case 'warning':
|
||||
appendLine('warn', '⚠ ' + ev.msg);
|
||||
break;
|
||||
case 'error':
|
||||
appendLine('error', '✗ ' + ev.msg);
|
||||
scanFinished();
|
||||
break;
|
||||
case 'progress':
|
||||
setProgress(ev.current, ev.total, ev.pct + '%', `Port ${ev.port} | ${ev.open_count} open | ETA ${ev.eta}`);
|
||||
break;
|
||||
case 'port_open':
|
||||
_openPorts.push(ev);
|
||||
const svc = ev.service || 'unknown';
|
||||
const banner = ev.banner ? ` — ${ev.banner.substring(0, 60)}` : '';
|
||||
appendLine('open', ` ✔ ${String(ev.port).padEnd(6)} ${svc.padEnd(18)}${banner}`);
|
||||
addResultRow(ev);
|
||||
document.getElementById('res-count').textContent = _openPorts.length;
|
||||
document.getElementById('st-open').textContent = _openPorts.length;
|
||||
document.getElementById('ps-results-wrap').style.display = '';
|
||||
break;
|
||||
case 'nmap_start':
|
||||
appendLine('info', ` nmap: ${ev.cmd}`);
|
||||
break;
|
||||
case 'nmap_line':
|
||||
if (ev.line.trim()) appendLine('nmap', ' ' + ev.line);
|
||||
break;
|
||||
case 'done':
|
||||
appendLine('done',
|
||||
`\n✔ SCAN COMPLETE — ${ev.open_count} open ports found in ${ev.duration}s ` +
|
||||
`(${ev.ports_scanned} ports scanned)`
|
||||
);
|
||||
if (ev.os_guess) {
|
||||
appendLine('info', ` OS: ${ev.os_guess}`);
|
||||
document.getElementById('st-os-row').style.display = '';
|
||||
document.getElementById('st-os').textContent = ev.os_guess;
|
||||
}
|
||||
document.getElementById('st-duration').textContent = ev.duration + 's';
|
||||
setProgress(100, 100, '100%', 'Complete');
|
||||
scanFinished();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function addResultRow(port) {
|
||||
const tbody = document.getElementById('ps-results-body');
|
||||
const tr = document.createElement('tr');
|
||||
const banner = port.banner
|
||||
? `<span style="font-family:monospace;font-size:0.75rem;color:var(--text-secondary)">${esc(port.banner.substring(0, 120))}</span>`
|
||||
: '<span style="color:var(--text-muted)">—</span>';
|
||||
tr.innerHTML = `
|
||||
<td><strong style="color:var(--success)">${port.port}</strong></td>
|
||||
<td style="color:var(--text-muted)">${port.protocol}</td>
|
||||
<td>${esc(port.service || '—')}</td>
|
||||
<td>${banner}</td>`;
|
||||
tbody.appendChild(tr);
|
||||
}
|
||||
|
||||
function cancelScan() {
|
||||
if (!_jobId) return;
|
||||
fetch('/port-scanner/cancel/' + _jobId, { method: 'POST' });
|
||||
appendLine('warn', '⚠ Scan cancelled by user');
|
||||
scanFinished();
|
||||
}
|
||||
|
||||
function scanFinished() {
|
||||
if (_es) { _es.close(); _es = null; }
|
||||
document.getElementById('ps-start-btn').disabled = false;
|
||||
document.getElementById('ps-cancel-btn').style.display = 'none';
|
||||
setStatus('idle', _openPorts.length + ' open ports');
|
||||
_jobId = null;
|
||||
}
|
||||
|
||||
function setStatus(state, text) {
|
||||
const dot = document.getElementById('ps-status-dot');
|
||||
const txt = document.getElementById('ps-status-txt');
|
||||
txt.textContent = text;
|
||||
dot.style.background = state === 'scanning' ? 'var(--success)'
|
||||
: state === 'error' ? 'var(--danger)'
|
||||
: 'var(--text-muted)';
|
||||
if (state === 'scanning') {
|
||||
dot.style.animation = 'ps-pulse 1.2s ease infinite';
|
||||
} else {
|
||||
dot.style.animation = '';
|
||||
}
|
||||
}
|
||||
|
||||
function setProgress(current, total, pct, label) {
|
||||
document.getElementById('ps-progress-bar').style.width = (typeof pct === 'string' ? pct : pct + '%');
|
||||
document.getElementById('ps-progress-pct').textContent = (typeof pct === 'string' ? pct : pct + '%');
|
||||
document.getElementById('ps-progress-label').textContent = label;
|
||||
}
|
||||
|
||||
function appendLine(cls, text) {
|
||||
const out = document.getElementById('ps-output');
|
||||
const el = document.createElement('span');
|
||||
el.className = 'ln-' + cls;
|
||||
el.textContent = text + '\n';
|
||||
out.appendChild(el);
|
||||
out.scrollTop = out.scrollHeight;
|
||||
}
|
||||
|
||||
function clearOutput() {
|
||||
document.getElementById('ps-output').innerHTML = '';
|
||||
}
|
||||
|
||||
function exportResults(fmt) {
|
||||
if (!_openPorts.length) { alert('No results to export'); return; }
|
||||
let content, mime, ext;
|
||||
if (fmt === 'json') {
|
||||
content = JSON.stringify({ target: document.getElementById('ps-target').value,
|
||||
scan_time: new Date().toISOString(),
|
||||
open_ports: _openPorts }, null, 2);
|
||||
mime = 'application/json'; ext = 'json';
|
||||
} else {
|
||||
const target = document.getElementById('ps-target').value;
|
||||
const lines = [`# AUTARCH Port Scan Results`, `# Target: ${target}`,
|
||||
`# Date: ${new Date().toISOString()}`, `# Open Ports: ${_openPorts.length}`, ''];
|
||||
_openPorts.forEach(p => {
|
||||
lines.push(`${p.port}/tcp\topen\t${p.service || 'unknown'}\t${p.banner || ''}`);
|
||||
});
|
||||
content = lines.join('\n'); mime = 'text/plain'; ext = 'txt';
|
||||
}
|
||||
const a = document.createElement('a');
|
||||
a.href = URL.createObjectURL(new Blob([content], { type: mime }));
|
||||
a.download = `scan_${document.getElementById('ps-target').value}_${Date.now()}.${ext}`;
|
||||
a.click();
|
||||
}
|
||||
|
||||
function esc(s) {
|
||||
return s ? String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>') : '';
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@keyframes ps-pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.4; }
|
||||
}
|
||||
</style>
|
||||
|
||||
{% endblock %}
|
||||
@@ -104,7 +104,7 @@ let currentReportId=null;
|
||||
function switchTab(name){
|
||||
document.querySelectorAll('.tab').forEach((t,i)=>t.classList.toggle('active',['reports','editor','templates'][i]===name));
|
||||
document.querySelectorAll('.tab-content').forEach(c=>c.style.display='none');
|
||||
document.getElementById('tab-'+name).style.display='';
|
||||
document.getElementById('tab-'+name).style.display='block';
|
||||
if(name==='reports') loadReports();
|
||||
if(name==='templates') loadTemplates();
|
||||
}
|
||||
|
||||
@@ -323,7 +323,7 @@ function switchTab(name){
|
||||
document.querySelectorAll('.tab').forEach((t,i)=>t.classList.toggle('active',
|
||||
['harvest','pretexts','qr','campaigns'][i]===name));
|
||||
document.querySelectorAll('.tab-content').forEach(c=>c.style.display='none');
|
||||
document.getElementById('tab-'+name).style.display='';
|
||||
document.getElementById('tab-'+name).style.display='block';
|
||||
if(name==='harvest'){loadPages();loadCaptures();}
|
||||
if(name==='pretexts') loadPretexts();
|
||||
if(name==='campaigns') loadCampaigns();
|
||||
|
||||
@@ -110,7 +110,7 @@ function switchTab(name){
|
||||
document.querySelectorAll('.tab').forEach((t,i)=>t.classList.toggle('active',
|
||||
['quick','dirbust','subdomain','vuln','crawl'][i]===name));
|
||||
document.querySelectorAll('.tab-content').forEach(c=>c.style.display='none');
|
||||
document.getElementById('tab-'+name).style.display='';
|
||||
document.getElementById('tab-'+name).style.display='block';
|
||||
}
|
||||
|
||||
function quickScan(){
|
||||
|
||||
Reference in New Issue
Block a user