Autarch/web/templates/malware_sandbox.html
DigiJ 2322f69516 v2.2.0 — Full arsenal expansion: 16 new security modules
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>
2026-03-03 05:20:39 -08:00

409 lines
18 KiB
HTML

{% extends "base.html" %}
{% block title %}AUTARCH — Malware Sandbox{% endblock %}
{% block content %}
<div class="page-header">
<h1>Malware Sandbox</h1>
<p style="margin:0;font-size:0.85rem;color:var(--text-secondary)">
Submit, analyze, and report on suspicious files using static and dynamic analysis.
</p>
</div>
<!-- Tab Bar -->
<div class="tab-bar">
<button class="tab active" data-tab-group="sandbox" data-tab="submit" onclick="showTab('sandbox','submit')">Submit</button>
<button class="tab" data-tab-group="sandbox" data-tab="analyze" onclick="showTab('sandbox','analyze')">Analyze</button>
<button class="tab" data-tab-group="sandbox" data-tab="reports" onclick="showTab('sandbox','reports')">Reports</button>
</div>
<!-- ==================== SUBMIT TAB ==================== -->
<div class="tab-content active" data-tab-group="sandbox" data-tab="submit">
<div class="section">
<h2>Submit Sample</h2>
<p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
Upload a file or specify a path on the server to submit for analysis.
</p>
<div class="form-row" style="margin-bottom:12px">
<div class="form-group">
<label>Upload File</label>
<input type="file" id="sandbox-upload-file">
</div>
</div>
<div style="font-size:0.8rem;color:var(--text-muted);text-align:center;margin-bottom:12px">-- OR --</div>
<div class="form-row" style="margin-bottom:12px">
<div class="form-group">
<label>Server File Path</label>
<input type="text" id="sandbox-file-path" placeholder="/path/to/suspicious/file">
</div>
</div>
<div class="tool-actions" style="margin-bottom:12px">
<button id="btn-sandbox-submit" class="btn btn-primary" onclick="sandboxSubmit()">Submit Sample</button>
</div>
<pre class="output-panel" id="sandbox-submit-output" style="min-height:0"></pre>
</div>
<div class="section">
<h2>Submitted Samples</h2>
<div class="tool-actions" style="margin-bottom:12px">
<button class="btn btn-small" onclick="sandboxLoadSamples()">Refresh</button>
</div>
<table class="data-table">
<thead><tr><th>Name</th><th>Size</th><th>SHA256</th><th>Submitted</th><th>Status</th></tr></thead>
<tbody id="sandbox-samples-table">
<tr><td colspan="5" class="empty-state">No samples submitted yet.</td></tr>
</tbody>
</table>
</div>
</div>
<!-- ==================== ANALYZE TAB ==================== -->
<div class="tab-content" data-tab-group="sandbox" data-tab="analyze">
<div class="section">
<h2>Select Sample</h2>
<div class="input-row">
<select id="sandbox-sample-select" style="flex:2">
<option value="">-- Select a sample --</option>
</select>
<button class="btn btn-small" onclick="sandboxRefreshSelect()">Refresh List</button>
</div>
</div>
<div class="section">
<h2>Static Analysis</h2>
<p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:8px">
Inspect file headers, strings, imports, and calculate risk score without execution.
</p>
<div class="tool-actions" style="margin-bottom:12px">
<button id="btn-static" class="btn btn-primary" onclick="sandboxStatic()">Run Static Analysis</button>
</div>
<!-- Risk Score Gauge -->
<div id="sandbox-static-results" style="display:none">
<div style="display:flex;gap:24px;align-items:flex-start;flex-wrap:wrap;margin-bottom:16px">
<div class="score-display">
<div class="score-value" id="sandbox-risk-score">--</div>
<div class="score-label">Risk Score</div>
</div>
<div style="flex:1;min-width:250px">
<table class="data-table" style="font-size:0.85rem">
<tbody>
<tr><td>File Type</td><td id="sandbox-file-type">--</td></tr>
<tr><td>File Size</td><td id="sandbox-file-size">--</td></tr>
<tr><td>MD5</td><td id="sandbox-md5" style="font-family:monospace;font-size:0.8rem">--</td></tr>
<tr><td>SHA256</td><td id="sandbox-sha256" style="font-family:monospace;font-size:0.8rem;word-break:break-all">--</td></tr>
</tbody>
</table>
</div>
</div>
<h3>Indicators by Category</h3>
<div id="sandbox-indicators" style="margin-bottom:16px"></div>
<h3>Interesting Strings</h3>
<pre class="output-panel scrollable" id="sandbox-strings" style="max-height:200px"></pre>
</div>
</div>
<div class="section">
<h2>Dynamic Analysis</h2>
<p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:8px">
Execute sample in an isolated Docker container and monitor behavior.
</p>
<div class="tool-actions" style="margin-bottom:12px">
<button id="btn-dynamic" class="btn btn-danger" onclick="sandboxDynamic()">Run Dynamic Analysis</button>
<span id="sandbox-dynamic-status" style="font-size:0.8rem;color:var(--text-muted);margin-left:12px"></span>
</div>
<div id="sandbox-dynamic-results" style="display:none">
<h3>Syscalls</h3>
<pre class="output-panel scrollable" id="sandbox-syscalls" style="max-height:200px"></pre>
<h3 style="margin-top:12px">Files Accessed</h3>
<pre class="output-panel scrollable" id="sandbox-files" style="max-height:200px"></pre>
<h3 style="margin-top:12px">Network Calls</h3>
<pre class="output-panel scrollable" id="sandbox-network" style="max-height:200px"></pre>
</div>
</div>
</div>
<!-- ==================== REPORTS TAB ==================== -->
<div class="tab-content" data-tab-group="sandbox" data-tab="reports">
<div class="section">
<h2>Analysis Reports</h2>
<div class="tool-actions" style="margin-bottom:12px">
<button class="btn btn-small" onclick="sandboxLoadReports()">Refresh</button>
</div>
<table class="data-table">
<thead><tr><th>Sample</th><th>Risk Level</th><th>Date</th><th>Action</th></tr></thead>
<tbody id="sandbox-reports-table">
<tr><td colspan="4" class="empty-state">No reports generated yet.</td></tr>
</tbody>
</table>
</div>
<div class="section">
<h2>Generate Report</h2>
<div class="input-row">
<select id="sandbox-report-sample" style="flex:2">
<option value="">-- Select a sample --</option>
</select>
<button id="btn-gen-report" class="btn btn-primary" onclick="sandboxGenReport()">Generate Report</button>
</div>
</div>
<div class="section" id="sandbox-report-viewer" style="display:none">
<h2>Report</h2>
<div id="sandbox-report-content"></div>
</div>
</div>
<script>
function esc(s) { return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;'); }
var _dynamicPoll = null;
/* ── Submit ── */
function sandboxSubmit() {
var btn = document.getElementById('btn-sandbox-submit');
var fileInput = document.getElementById('sandbox-upload-file');
var pathInput = document.getElementById('sandbox-file-path').value.trim();
if (fileInput.files.length > 0) {
setLoading(btn, true);
var fd = new FormData();
fd.append('file', fileInput.files[0]);
fetch('/sandbox/submit', {method: 'POST', body: fd}).then(function(r) { return r.json(); }).then(function(data) {
setLoading(btn, false);
renderOutput('sandbox-submit-output', data.message || data.error || 'Submitted');
if (data.success) { sandboxLoadSamples(); sandboxRefreshSelect(); }
}).catch(function() { setLoading(btn, false); renderOutput('sandbox-submit-output', 'Upload failed'); });
} else if (pathInput) {
setLoading(btn, true);
postJSON('/sandbox/submit', {path: pathInput}).then(function(data) {
setLoading(btn, false);
renderOutput('sandbox-submit-output', data.message || data.error || 'Submitted');
if (data.success) { sandboxLoadSamples(); sandboxRefreshSelect(); }
}).catch(function() { setLoading(btn, false); });
} else {
renderOutput('sandbox-submit-output', 'Select a file or enter a path.');
}
}
function sandboxLoadSamples() {
fetchJSON('/sandbox/samples').then(function(data) {
var tb = document.getElementById('sandbox-samples-table');
var samples = data.samples || [];
if (!samples.length) {
tb.innerHTML = '<tr><td colspan="5" class="empty-state">No samples submitted yet.</td></tr>';
return;
}
var html = '';
samples.forEach(function(s) {
var statusBadge = s.status === 'analyzed' ? '<span class="badge badge-pass">Analyzed</span>'
: s.status === 'pending' ? '<span class="badge badge-medium">Pending</span>'
: '<span class="badge badge-info">' + esc(s.status) + '</span>';
html += '<tr><td>' + esc(s.name) + '</td><td>' + esc(s.size) + '</td>'
+ '<td style="font-family:monospace;font-size:0.75rem;word-break:break-all">' + esc(s.sha256 || '--') + '</td>'
+ '<td>' + esc(s.date) + '</td><td>' + statusBadge + '</td></tr>';
});
tb.innerHTML = html;
});
}
function sandboxRefreshSelect() {
fetchJSON('/sandbox/samples').then(function(data) {
var samples = data.samples || [];
var opts = '<option value="">-- Select a sample --</option>';
samples.forEach(function(s) {
opts += '<option value="' + esc(s.id || s.sha256) + '">' + esc(s.name) + ' (' + esc(s.size) + ')</option>';
});
document.getElementById('sandbox-sample-select').innerHTML = opts;
document.getElementById('sandbox-report-sample').innerHTML = opts;
});
}
/* ── Static Analysis ── */
function sandboxStatic() {
var sampleId = document.getElementById('sandbox-sample-select').value;
if (!sampleId) { alert('Select a sample first.'); return; }
var btn = document.getElementById('btn-static');
setLoading(btn, true);
document.getElementById('sandbox-static-results').style.display = 'none';
postJSON('/sandbox/analyze/static', {sample_id: sampleId}).then(function(data) {
setLoading(btn, false);
if (data.error) { alert('Error: ' + data.error); return; }
document.getElementById('sandbox-static-results').style.display = 'block';
var score = data.risk_score || 0;
var scoreEl = document.getElementById('sandbox-risk-score');
scoreEl.textContent = score + '/100';
scoreEl.style.color = score >= 70 ? 'var(--danger)' : score >= 40 ? 'var(--warning)' : 'var(--success)';
document.getElementById('sandbox-file-type').textContent = data.file_type || '--';
document.getElementById('sandbox-file-size').textContent = data.file_size || '--';
document.getElementById('sandbox-md5').textContent = data.md5 || '--';
document.getElementById('sandbox-sha256').textContent = data.sha256 || '--';
var indHtml = '';
var indicators = data.indicators || {};
Object.keys(indicators).forEach(function(cat) {
indHtml += '<div style="margin-bottom:8px"><strong style="color:var(--text-secondary);font-size:0.85rem">' + esc(cat) + '</strong><ul style="margin:4px 0 0 16px;font-size:0.85rem">';
(indicators[cat] || []).forEach(function(item) {
indHtml += '<li>' + esc(item) + '</li>';
});
indHtml += '</ul></div>';
});
document.getElementById('sandbox-indicators').innerHTML = indHtml || '<span class="empty-state">No indicators found.</span>';
var strings = (data.strings || []).join('\n');
renderOutput('sandbox-strings', strings || 'No interesting strings found.');
}).catch(function() { setLoading(btn, false); });
}
/* ── Dynamic Analysis ── */
function sandboxDynamic() {
var sampleId = document.getElementById('sandbox-sample-select').value;
if (!sampleId) { alert('Select a sample first.'); return; }
var btn = document.getElementById('btn-dynamic');
setLoading(btn, true);
document.getElementById('sandbox-dynamic-status').textContent = 'Submitting for dynamic analysis...';
document.getElementById('sandbox-dynamic-results').style.display = 'none';
postJSON('/sandbox/analyze/dynamic', {sample_id: sampleId}).then(function(data) {
if (data.error) {
setLoading(btn, false);
document.getElementById('sandbox-dynamic-status').textContent = 'Error: ' + data.error;
return;
}
if (data.job_id) {
document.getElementById('sandbox-dynamic-status').textContent = 'Running in Docker sandbox...';
sandboxPollDynamic(data.job_id);
} else {
setLoading(btn, false);
sandboxRenderDynamic(data);
}
}).catch(function() {
setLoading(btn, false);
document.getElementById('sandbox-dynamic-status').textContent = 'Request failed';
});
}
function sandboxPollDynamic(jobId) {
if (_dynamicPoll) clearInterval(_dynamicPoll);
_dynamicPoll = setInterval(function() {
fetchJSON('/sandbox/analyze/dynamic/status/' + jobId).then(function(data) {
if (data.status === 'running') {
document.getElementById('sandbox-dynamic-status').textContent = 'Running... (' + (data.elapsed || '0') + 's)';
} else {
clearInterval(_dynamicPoll);
_dynamicPoll = null;
setLoading(document.getElementById('btn-dynamic'), false);
if (data.status === 'complete') {
document.getElementById('sandbox-dynamic-status').textContent = 'Analysis complete';
sandboxRenderDynamic(data);
} else {
document.getElementById('sandbox-dynamic-status').textContent = 'Failed: ' + (data.error || 'unknown');
}
}
}).catch(function() {
clearInterval(_dynamicPoll);
_dynamicPoll = null;
setLoading(document.getElementById('btn-dynamic'), false);
document.getElementById('sandbox-dynamic-status').textContent = 'Poll error';
});
}, 3000);
}
function sandboxRenderDynamic(data) {
document.getElementById('sandbox-dynamic-results').style.display = 'block';
renderOutput('sandbox-syscalls', (data.syscalls || []).join('\n') || 'No syscalls captured.');
renderOutput('sandbox-files', (data.files_accessed || []).join('\n') || 'No file access recorded.');
renderOutput('sandbox-network', (data.network_calls || []).join('\n') || 'No network activity recorded.');
}
/* ── Reports ── */
function sandboxLoadReports() {
fetchJSON('/sandbox/reports').then(function(data) {
var tb = document.getElementById('sandbox-reports-table');
var reports = data.reports || [];
if (!reports.length) {
tb.innerHTML = '<tr><td colspan="4" class="empty-state">No reports generated yet.</td></tr>';
return;
}
var html = '';
reports.forEach(function(r) {
var lvl = (r.risk_level || 'unknown').toLowerCase();
var badgeClass = lvl === 'critical' || lvl === 'high' ? 'badge-fail'
: lvl === 'medium' ? 'badge-medium'
: lvl === 'low' ? 'badge-low' : 'badge-info';
html += '<tr><td>' + esc(r.sample_name) + '</td>'
+ '<td><span class="badge ' + badgeClass + '">' + esc(r.risk_level) + '</span></td>'
+ '<td>' + esc(r.date) + '</td>'
+ '<td><button class="btn btn-small" onclick="sandboxViewReport(\'' + esc(r.id) + '\')">View</button></td></tr>';
});
tb.innerHTML = html;
});
}
function sandboxGenReport() {
var sampleId = document.getElementById('sandbox-report-sample').value;
if (!sampleId) { alert('Select a sample first.'); return; }
var btn = document.getElementById('btn-gen-report');
setLoading(btn, true);
postJSON('/sandbox/reports/generate', {sample_id: sampleId}).then(function(data) {
setLoading(btn, false);
if (data.error) { alert('Error: ' + data.error); return; }
sandboxLoadReports();
if (data.report_id) sandboxViewReport(data.report_id);
}).catch(function() { setLoading(btn, false); });
}
function sandboxViewReport(reportId) {
fetchJSON('/sandbox/reports/' + reportId).then(function(data) {
if (data.error) { alert('Error: ' + data.error); return; }
document.getElementById('sandbox-report-viewer').style.display = 'block';
var html = '<div style="background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:16px">';
var lvl = (data.risk_level || 'unknown').toLowerCase();
var badgeClass = lvl === 'critical' || lvl === 'high' ? 'badge-fail'
: lvl === 'medium' ? 'badge-medium'
: lvl === 'low' ? 'badge-low' : 'badge-info';
html += '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px">'
+ '<strong>' + esc(data.sample_name || 'Unknown') + '</strong>'
+ '<span class="badge ' + badgeClass + '">' + esc(data.risk_level || 'N/A') + '</span></div>';
html += '<table class="data-table" style="font-size:0.85rem;margin-bottom:12px"><tbody>';
html += '<tr><td>Risk Score</td><td>' + (data.risk_score || '--') + '/100</td></tr>';
html += '<tr><td>File Type</td><td>' + esc(data.file_type || '--') + '</td></tr>';
html += '<tr><td>SHA256</td><td style="font-family:monospace;font-size:0.8rem;word-break:break-all">' + esc(data.sha256 || '--') + '</td></tr>';
html += '<tr><td>Date</td><td>' + esc(data.date || '--') + '</td></tr>';
html += '</tbody></table>';
if (data.summary) {
html += '<h4 style="margin-bottom:6px;font-size:0.85rem;color:var(--text-secondary)">Summary</h4>';
html += '<p style="font-size:0.85rem;margin-bottom:12px">' + esc(data.summary) + '</p>';
}
html += '</div>';
document.getElementById('sandbox-report-content').innerHTML = html;
});
}
/* ── Init ── */
document.addEventListener('DOMContentLoaded', function() {
sandboxLoadSamples();
sandboxRefreshSelect();
sandboxLoadReports();
});
</script>
{% endblock %}