Autarch/web/templates/starlink_hack.html

901 lines
42 KiB
HTML
Raw Permalink Normal View History

{% extends "base.html" %}
{% block title %}AUTARCH — Starlink Hacking{% endblock %}
{% block content %}
<div class="page-header">
<h1 style="color:#ef4444">Starlink Terminal Security Analysis</h1>
<p style="margin:0;font-size:0.85rem;color:var(--text-secondary)">
gRPC exploitation, firmware analysis, network attacks, and RF analysis for Starlink user terminals.
</p>
</div>
<!-- Tab Bar -->
<div class="tab-bar">
<button class="tab active" data-tab-group="sl" data-tab="discovery" onclick="showTab('sl','discovery')">Discovery &amp; Status</button>
<button class="tab" data-tab-group="sl" data-tab="grpc" onclick="showTab('sl','grpc')">gRPC Control</button>
<button class="tab" data-tab-group="sl" data-tab="network" onclick="showTab('sl','network')">Network Attack</button>
<button class="tab" data-tab-group="sl" data-tab="rffirmware" onclick="showTab('sl','rffirmware')">RF &amp; Firmware</button>
</div>
<!-- ==================== DISCOVERY & STATUS TAB ==================== -->
<div class="tab-content active" data-tab-group="sl" data-tab="discovery">
<!-- Discover Dish -->
<div class="section">
<h2>Discover Dish</h2>
<div style="display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap">
<div class="form-group" style="margin:0">
<label>Dish IP</label>
<input type="text" id="sl-dish-ip" class="form-control" value="192.168.100.1" style="width:200px">
</div>
<button id="btn-sl-discover" class="btn btn-primary" onclick="slDiscover()">Discover</button>
<button class="btn" onclick="slModuleStatus()" title="Module status">Status</button>
</div>
<div id="sl-discover-result" style="margin-top:12px"></div>
</div>
<!-- Dish Status -->
<div class="section">
<h2>Dish Status</h2>
<div style="margin-bottom:8px">
<button id="btn-sl-status" class="btn btn-primary" onclick="slGetStatus()">Get Status</button>
<button class="btn" onclick="slGetInfo()">Device Info</button>
</div>
<div id="sl-status-result" style="margin-top:12px"></div>
</div>
<!-- Network Info -->
<div class="section">
<h2>Network &amp; WiFi Clients</h2>
<button id="btn-sl-network" class="btn btn-primary" onclick="slGetNetwork()">Get Network Info</button>
<div id="sl-network-result" style="margin-top:12px"></div>
</div>
<!-- Port Scan -->
<div class="section">
<h2>Port Scan</h2>
<button id="btn-sl-portscan" class="btn btn-primary" onclick="slPortScan()">Scan Dish Ports</button>
<span id="sl-portscan-status" style="margin-left:12px;font-size:0.85rem;color:var(--text-secondary)"></span>
<div id="sl-portscan-result" style="margin-top:12px"></div>
</div>
</div>
<!-- ==================== gRPC CONTROL TAB ==================== -->
<div class="tab-content" data-tab-group="sl" data-tab="grpc">
<!-- Enumerate Methods -->
<div class="section">
<h2>Enumerate gRPC Methods</h2>
<button id="btn-sl-grpc-enum" class="btn btn-primary" onclick="slGrpcEnum()">Enumerate Methods</button>
<div id="sl-grpc-enum-result" style="margin-top:12px"></div>
</div>
<!-- Quick Actions -->
<div class="section">
<h2>Quick Actions</h2>
<p style="font-size:0.85rem;color:var(--text-secondary);margin-bottom:10px">
Send commands to the Starlink dish via gRPC. Use with caution on production hardware.
</p>
<div style="display:flex;gap:10px;flex-wrap:wrap">
<button class="btn" style="border-color:#f97316;color:#f97316" onclick="slGrpcStow()">Stow Dish</button>
<button class="btn" style="border-color:#22c55e;color:#22c55e" onclick="slGrpcUnstow()">Unstow Dish</button>
<button class="btn" style="border-color:#ef4444;color:#ef4444" onclick="slGrpcReboot()">Reboot Dish</button>
<button class="btn" style="border-color:#ef4444;color:#ef4444;opacity:0.7" onclick="slGrpcFactoryReset()">Factory Reset</button>
</div>
<div id="sl-grpc-action-result" style="margin-top:12px"></div>
</div>
<!-- Custom gRPC Call -->
<div class="section">
<h2>Custom gRPC Call</h2>
<div style="display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap;max-width:800px">
<div class="form-group" style="flex:1;min-width:200px;margin:0">
<label>Method</label>
<input type="text" id="sl-grpc-method" class="form-control" placeholder="e.g. get_status">
</div>
<button class="btn btn-primary" onclick="slGrpcCall()">Execute</button>
</div>
<div class="form-group" style="margin-top:8px;max-width:800px">
<label>Parameters (JSON)</label>
<textarea id="sl-grpc-params" class="form-control" rows="3" placeholder='{"getStatus": {}}'
style="font-family:monospace;font-size:0.85rem"></textarea>
</div>
<div id="sl-grpc-call-result" style="margin-top:12px"></div>
</div>
</div>
<!-- ==================== NETWORK ATTACK TAB ==================== -->
<div class="tab-content" data-tab-group="sl" data-tab="network">
<!-- Traffic Interception -->
<div class="section">
<h2>Traffic Interception (ARP Spoof)</h2>
<p style="font-size:0.85rem;color:var(--text-secondary);margin-bottom:10px">
ARP spoofing between dish and gateway to intercept traffic. Requires arpspoof or ettercap.
</p>
<div style="display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap">
<div class="form-group" style="margin:0">
<label>Gateway IP</label>
<input type="text" id="sl-intercept-gateway" class="form-control" value="192.168.1.1" style="width:180px">
</div>
<div class="form-group" style="margin:0">
<label>Interface (optional)</label>
<input type="text" id="sl-intercept-iface" class="form-control" placeholder="auto" style="width:130px">
</div>
<button class="btn btn-primary" onclick="slInterceptStart()">Start Intercept</button>
<button class="btn" style="border-color:#ef4444;color:#ef4444" onclick="slInterceptStop()">Stop</button>
</div>
<div id="sl-intercept-result" style="margin-top:12px"></div>
</div>
<!-- DNS Spoofing -->
<div class="section">
<h2>DNS Spoofing</h2>
<p style="font-size:0.85rem;color:var(--text-secondary);margin-bottom:10px">
Redirect DNS queries for a domain to a controlled IP. Requires dnsspoof or ettercap.
</p>
<div style="display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap">
<div class="form-group" style="margin:0">
<label>Domain</label>
<input type="text" id="sl-dns-domain" class="form-control" placeholder="example.com" style="width:200px">
</div>
<div class="form-group" style="margin:0">
<label>Spoof IP</label>
<input type="text" id="sl-dns-ip" class="form-control" placeholder="10.0.0.1" style="width:160px">
</div>
<button class="btn btn-primary" onclick="slDnsStart()">Start DNS Spoof</button>
<button class="btn" style="border-color:#ef4444;color:#ef4444" onclick="slDnsStop()">Stop</button>
</div>
<div id="sl-dns-result" style="margin-top:12px"></div>
</div>
<!-- Client Deauth -->
<div class="section">
<h2>WiFi Client Deauthentication</h2>
<p style="font-size:0.85rem;color:var(--text-secondary);margin-bottom:10px">
Send deauth packets to disconnect WiFi clients from the Starlink router. Requires aircrack-ng or mdk4.
</p>
<div style="display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap">
<div class="form-group" style="margin:0">
<label>Target MAC (empty=broadcast)</label>
<input type="text" id="sl-deauth-mac" class="form-control" placeholder="AA:BB:CC:DD:EE:FF" style="width:200px">
</div>
<div class="form-group" style="margin:0">
<label>Wireless Interface</label>
<input type="text" id="sl-deauth-iface" class="form-control" placeholder="wlan0mon" style="width:140px">
</div>
<button class="btn btn-primary" onclick="slDeauth()">Send Deauth</button>
</div>
<div id="sl-deauth-result" style="margin-top:12px"></div>
</div>
<!-- MITM -->
<div class="section">
<h2>MITM WiFi Clients</h2>
<div style="display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap">
<div class="form-group" style="margin:0">
<label>Interface (optional)</label>
<input type="text" id="sl-mitm-iface" class="form-control" placeholder="auto" style="width:140px">
</div>
<button class="btn btn-primary" onclick="slMitm()">Start MITM</button>
</div>
<div id="sl-mitm-result" style="margin-top:12px"></div>
</div>
</div>
<!-- ==================== RF & FIRMWARE TAB ==================== -->
<div class="tab-content" data-tab-group="sl" data-tab="rffirmware">
<!-- Firmware Version Check -->
<div class="section">
<h2>Firmware Version Check</h2>
<p style="font-size:0.85rem;color:var(--text-secondary);margin-bottom:10px">
Check the running firmware version against known vulnerable versions.
</p>
<button id="btn-sl-fw-check" class="btn btn-primary" onclick="slFirmwareCheck()">Check Firmware</button>
<div id="sl-fw-check-result" style="margin-top:12px"></div>
</div>
<!-- Firmware Upload & Analyze -->
<div class="section">
<h2>Firmware Analysis</h2>
<p style="font-size:0.85rem;color:var(--text-secondary);margin-bottom:10px">
Upload a firmware image for signature scanning, entropy analysis, and string extraction.
</p>
<div style="display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap">
<div class="form-group" style="margin:0">
<label>Firmware File</label>
<input type="file" id="sl-fw-file" class="form-control" style="max-width:350px">
</div>
<button class="btn btn-primary" onclick="slFirmwareAnalyze()">Analyze</button>
</div>
<div id="sl-fw-analyze-result" style="margin-top:12px"></div>
</div>
<!-- Debug Interfaces -->
<div class="section">
<h2>Debug Interface Scan</h2>
<button class="btn btn-primary" onclick="slDebugInterfaces()">Scan Debug Interfaces</button>
<div id="sl-debug-result" style="margin-top:12px"></div>
</div>
<!-- RF Downlink Analysis -->
<div class="section">
<h2>RF Downlink Analysis</h2>
<p style="font-size:0.85rem;color:var(--text-secondary);margin-bottom:10px">
Ku-band downlink analysis (10.7-12.7 GHz). Requires SDR hardware (HackRF or RTL-SDR with LNB).
</p>
<div style="display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap">
<div class="form-group" style="margin:0">
<label>Device</label>
<select id="sl-rf-device" class="form-control" style="width:130px">
<option value="hackrf">HackRF</option>
<option value="rtl">RTL-SDR</option>
</select>
</div>
<div class="form-group" style="margin:0">
<label>Duration (s)</label>
<input type="number" id="sl-rf-duration" class="form-control" value="30" min="5" max="300" style="width:100px">
</div>
<button class="btn btn-primary" onclick="slRfDownlink()">Analyze Downlink</button>
</div>
<div id="sl-rf-downlink-result" style="margin-top:12px"></div>
</div>
<!-- Jamming Detection -->
<div class="section">
<h2>Jamming Detection</h2>
<p style="font-size:0.85rem;color:var(--text-secondary);margin-bottom:10px">
Check for signal jamming indicators by analyzing dish diagnostics (drop rate, latency, throughput, SNR).
</p>
<button class="btn btn-primary" onclick="slDetectJamming()">Detect Jamming</button>
<div id="sl-jamming-result" style="margin-top:12px"></div>
</div>
<!-- Known CVEs -->
<div class="section">
<h2>Known Vulnerabilities</h2>
<button class="btn btn-primary" onclick="slLoadCves()">Load CVE Database</button>
<button class="btn" onclick="slExportResults()" style="margin-left:8px">Export All Results</button>
<div id="sl-cve-result" style="margin-top:12px"></div>
</div>
</div>
<!-- ==================== JAVASCRIPT ==================== -->
<script>
/* ── helpers (from app.js) ── */
/* postJSON, fetchJSON, esc, setLoading, showTab are globally available */
function slShowResult(elId, html) {
document.getElementById(elId).innerHTML = html;
}
function slCardHtml(title, rows) {
let h = '<div style="background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:14px;margin-bottom:12px">';
if (title) h += '<h3 style="margin:0 0 8px 0;font-size:0.95rem;color:#f97316">' + esc(title) + '</h3>';
for (const [k, v] of rows) {
h += '<div style="display:flex;gap:8px;margin-bottom:3px;font-size:0.85rem">';
h += '<span style="color:var(--text-secondary);min-width:160px">' + esc(k) + '</span>';
h += '<span style="color:var(--text-primary);word-break:break-all">' + esc(String(v)) + '</span>';
h += '</div>';
}
h += '</div>';
return h;
}
function slTableHtml(headers, rows) {
let h = '<table style="width:100%;border-collapse:collapse;font-size:0.85rem;margin-top:8px">';
h += '<thead><tr>';
for (const hdr of headers) h += '<th style="text-align:left;padding:6px 8px;border-bottom:1px solid var(--border);color:var(--text-secondary)">' + esc(hdr) + '</th>';
h += '</tr></thead><tbody>';
for (const row of rows) {
h += '<tr>';
for (const cell of row) h += '<td style="padding:5px 8px;border-bottom:1px solid rgba(51,54,80,0.4)">' + esc(String(cell)) + '</td>';
h += '</tr>';
}
h += '</tbody></table>';
return h;
}
function slAlert(msg, type) {
const color = type === 'error' ? '#ef4444' : type === 'warning' ? '#f97316' : '#22c55e';
return '<div style="padding:8px 12px;border-left:3px solid ' + color + ';background:var(--bg-card);border-radius:var(--radius);font-size:0.85rem;margin-bottom:8px;color:' + color + '">' + esc(msg) + '</div>';
}
function slJsonBlock(data) {
return '<pre style="background:var(--bg-input);border:1px solid var(--border);border-radius:var(--radius);padding:12px;font-size:0.8rem;overflow-x:auto;max-height:400px;color:var(--text-primary)">' + esc(JSON.stringify(data, null, 2)) + '</pre>';
}
/* ── Discovery & Status ── */
async function slDiscover() {
const ip = document.getElementById('sl-dish-ip').value.trim();
setLoading('btn-sl-discover', true);
slShowResult('sl-discover-result', '<span style="color:var(--text-muted)">Discovering...</span>');
try {
const r = await postJSON('/starlink-hack/discover', {ip: ip || undefined});
let h = '';
if (r.found) {
h += slAlert('Dish found at ' + (r.target || ip), 'success');
h += slCardHtml('Discovery Results', [
['Target IP', r.target],
['gRPC Port (9200)', r.grpc_available ? 'OPEN' : 'closed'],
['HTTP Port (80)', r.http_available ? 'OPEN' : 'closed'],
['Firmware', r.firmware || 'unknown'],
['Hardware', r.hardware || 'unknown'],
['Extra Open Ports', (r.details?.extra_open_ports || []).join(', ') || 'none'],
]);
} else {
h += slAlert(r.error || 'Dish not found', 'error');
}
slShowResult('sl-discover-result', h);
} catch (e) {
slShowResult('sl-discover-result', slAlert('Request failed: ' + e.message, 'error'));
}
setLoading('btn-sl-discover', false);
}
async function slGetStatus() {
setLoading('btn-sl-status', true);
slShowResult('sl-status-result', '<span style="color:var(--text-muted)">Loading...</span>');
try {
const r = await fetchJSON('/starlink-hack/dish-status');
let h = '';
if (r.ok) {
h += slCardHtml('Dish Status', [
['State', r.device_state],
['Uptime', r.uptime_human],
['Firmware', r.software_version],
['Hardware', r.hardware_version],
['Alerts', r.alert_count + ' active' + (r.alerts?.length ? ': ' + r.alerts.join(', ') : '')],
['Obstruction', (r.obstruction?.fraction_obstructed || 0) + '%'],
['Downlink', (r.downlink_throughput_bps || 0).toLocaleString() + ' bps'],
['Uplink', (r.uplink_throughput_bps || 0).toLocaleString() + ' bps'],
['Latency', (r.pop_ping_latency_ms || 0) + ' ms'],
['Drop Rate', ((r.pop_ping_drop_rate || 0) * 100).toFixed(1) + '%'],
['ETH Speed', (r.eth_speed_mbps || 0) + ' Mbps'],
['SNR OK', r.snr_above_noise_floor ? 'Yes' : 'No'],
['Stowed', r.stowed ? 'Yes' : 'No'],
]);
} else {
h += slAlert(r.error || 'Failed to get status', 'error');
}
slShowResult('sl-status-result', h);
} catch (e) {
slShowResult('sl-status-result', slAlert('Request failed: ' + e.message, 'error'));
}
setLoading('btn-sl-status', false);
}
async function slGetInfo() {
slShowResult('sl-status-result', '<span style="color:var(--text-muted)">Loading device info...</span>');
try {
const r = await fetchJSON('/starlink-hack/dish-info');
let h = '';
if (r.ok) {
h += slCardHtml('Device Info', [
['Device ID', r.device_id],
['Hardware Version', r.hardware_version],
['Software Version', r.software_version],
['Country Code', r.country_code],
['Boot Count', r.bootcount || 'N/A'],
['Is Dev', r.is_dev ? 'Yes' : 'No'],
['Board Rev', r.board_rev || 'N/A'],
['Anti-Rollback', r.anti_rollback_version || 'N/A'],
]);
} else {
h += slAlert(r.error || 'Failed to get info', 'error');
}
slShowResult('sl-status-result', h);
} catch (e) {
slShowResult('sl-status-result', slAlert('Request failed: ' + e.message, 'error'));
}
}
async function slGetNetwork() {
setLoading('btn-sl-network', true);
slShowResult('sl-network-result', '<span style="color:var(--text-muted)">Loading...</span>');
try {
const r = await fetchJSON('/starlink-hack/network');
let h = '';
const cfg = r.wifi_config || {};
h += slCardHtml('WiFi Configuration', [
['SSID', cfg.ssid || 'unknown'],
['Security', cfg.security || 'unknown'],
['Band', cfg.band || 'unknown'],
['Channel', cfg.channel || 'auto'],
]);
const clients = r.wifi_clients || [];
if (clients.length) {
const rows = clients.map(c => [c.name || 'unknown', c.mac || '?', c.ip || '?', (c.signal_strength != null ? c.signal_strength + ' dBm' : 'N/A'), c.band || '?']);
h += '<h3 style="font-size:0.95rem;color:#f97316;margin:12px 0 4px 0">WiFi Clients (' + clients.length + ')</h3>';
h += slTableHtml(['Name', 'MAC', 'IP', 'Signal', 'Band'], rows);
} else {
h += '<p style="font-size:0.85rem;color:var(--text-muted)">No WiFi clients found.</p>';
}
slShowResult('sl-network-result', h);
} catch (e) {
slShowResult('sl-network-result', slAlert('Request failed: ' + e.message, 'error'));
}
setLoading('btn-sl-network', false);
}
async function slPortScan() {
setLoading('btn-sl-portscan', true);
document.getElementById('sl-portscan-status').textContent = 'Scanning (this may take a while)...';
slShowResult('sl-portscan-result', '');
try {
const r = await postJSON('/starlink-hack/scan-ports', {target: document.getElementById('sl-dish-ip').value.trim() || undefined});
let h = '';
if (r.ok) {
const ports = r.ports || [];
document.getElementById('sl-portscan-status').textContent = ports.length + ' open ports found (' + (r.scanner || 'unknown') + ')';
if (ports.length) {
h += slTableHtml(['Port', 'Protocol', 'State', 'Service'], ports.map(p => [p.port, p.protocol, p.state, p.service]));
} else {
h += '<p style="font-size:0.85rem;color:var(--text-muted)">No open ports found.</p>';
}
} else {
document.getElementById('sl-portscan-status').textContent = '';
h += slAlert(r.error || 'Scan failed', 'error');
}
slShowResult('sl-portscan-result', h);
} catch (e) {
document.getElementById('sl-portscan-status').textContent = '';
slShowResult('sl-portscan-result', slAlert('Request failed: ' + e.message, 'error'));
}
setLoading('btn-sl-portscan', false);
}
async function slModuleStatus() {
try {
const r = await fetchJSON('/starlink-hack/status');
let h = slCardHtml('Module Status', [
['Module', r.module + ' v' + r.version],
['Category', r.category],
['Dish IP', r.dish_ip],
['Results Count', r.results_count],
['Intercept Running', r.intercept_running ? 'Yes' : 'No'],
['Data Dir', r.data_dir],
]);
const tools = r.tools || {};
const toolRows = Object.entries(tools).map(([k, v]) => [k, v ? 'Available' : 'Missing']);
h += '<h3 style="font-size:0.95rem;color:#f97316;margin:12px 0 4px 0">Tool Availability</h3>';
h += slTableHtml(['Tool', 'Status'], toolRows);
slShowResult('sl-discover-result', h);
} catch (e) {
slShowResult('sl-discover-result', slAlert('Request failed: ' + e.message, 'error'));
}
}
/* ── gRPC Control ── */
async function slGrpcEnum() {
setLoading('btn-sl-grpc-enum', true);
slShowResult('sl-grpc-enum-result', '<span style="color:var(--text-muted)">Enumerating...</span>');
try {
const r = await postJSON('/starlink-hack/grpc/enumerate', {});
let h = '';
if (r.ok) {
const src = r.source ? ' (source: ' + r.source + ')' : '';
h += '<p style="font-size:0.85rem;color:var(--text-secondary)">' + (r.method_count || 0) + ' methods found' + esc(src) + '</p>';
if (r.note) h += '<p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:8px">' + esc(r.note) + '</p>';
const methods = r.methods || [];
if (methods.length) {
const rows = methods.map(m => {
if (typeof m === 'object') return [m.method || m.name || '?', m.service || '', m.description || m.desc || ''];
return [m, '', ''];
});
h += slTableHtml(['Method', 'Service', 'Description'], rows);
}
} else {
h += slAlert(r.error || 'Enumeration failed', 'error');
}
slShowResult('sl-grpc-enum-result', h);
} catch (e) {
slShowResult('sl-grpc-enum-result', slAlert('Request failed: ' + e.message, 'error'));
}
setLoading('btn-sl-grpc-enum', false);
}
async function slGrpcStow() {
if (!confirm('Stow the dish? This will park the antenna.')) return;
slShowResult('sl-grpc-action-result', '<span style="color:var(--text-muted)">Sending stow...</span>');
try {
const r = await postJSON('/starlink-hack/grpc/stow', {});
slShowResult('sl-grpc-action-result', r.ok ? slAlert(r.message || 'Stow sent', 'success') : slAlert(r.error || 'Failed', 'error'));
} catch (e) {
slShowResult('sl-grpc-action-result', slAlert(e.message, 'error'));
}
}
async function slGrpcUnstow() {
slShowResult('sl-grpc-action-result', '<span style="color:var(--text-muted)">Sending unstow...</span>');
try {
const r = await postJSON('/starlink-hack/grpc/unstow', {});
slShowResult('sl-grpc-action-result', r.ok ? slAlert(r.message || 'Unstow sent', 'success') : slAlert(r.error || 'Failed', 'error'));
} catch (e) {
slShowResult('sl-grpc-action-result', slAlert(e.message, 'error'));
}
}
async function slGrpcReboot() {
if (!confirm('Reboot the Starlink dish? It will be offline for ~2 minutes.')) return;
slShowResult('sl-grpc-action-result', '<span style="color:var(--text-muted)">Sending reboot...</span>');
try {
const r = await postJSON('/starlink-hack/grpc/reboot', {});
slShowResult('sl-grpc-action-result', r.ok ? slAlert(r.message || 'Reboot sent', 'success') : slAlert(r.error || 'Failed', 'error'));
} catch (e) {
slShowResult('sl-grpc-action-result', slAlert(e.message, 'error'));
}
}
async function slGrpcFactoryReset() {
if (!confirm('FACTORY RESET the Starlink dish? This will ERASE ALL settings!')) return;
if (!confirm('Are you ABSOLUTELY sure? This is irreversible.')) return;
slShowResult('sl-grpc-action-result', '<span style="color:var(--text-muted)">Sending factory reset...</span>');
try {
const r = await postJSON('/starlink-hack/grpc/factory-reset', {confirm: true});
slShowResult('sl-grpc-action-result', r.ok ? slAlert(r.message || 'Factory reset sent', 'warning') : slAlert(r.error || 'Failed', 'error'));
} catch (e) {
slShowResult('sl-grpc-action-result', slAlert(e.message, 'error'));
}
}
async function slGrpcCall() {
const method = document.getElementById('sl-grpc-method').value.trim();
const paramsStr = document.getElementById('sl-grpc-params').value.trim();
if (!method) { slShowResult('sl-grpc-call-result', slAlert('Method name is required', 'error')); return; }
let params = null;
if (paramsStr) {
try { params = JSON.parse(paramsStr); } catch (e) { slShowResult('sl-grpc-call-result', slAlert('Invalid JSON: ' + e.message, 'error')); return; }
}
slShowResult('sl-grpc-call-result', '<span style="color:var(--text-muted)">Calling ' + esc(method) + '...</span>');
try {
const r = await postJSON('/starlink-hack/grpc/call', {method, params});
let h = '';
if (r.ok) {
h += slAlert('Call successful', 'success');
h += slJsonBlock(r.response || {});
} else {
h += slAlert(r.error || 'Call failed', 'error');
}
slShowResult('sl-grpc-call-result', h);
} catch (e) {
slShowResult('sl-grpc-call-result', slAlert(e.message, 'error'));
}
}
/* ── Network Attack ── */
async function slInterceptStart() {
const gateway = document.getElementById('sl-intercept-gateway').value.trim();
const iface = document.getElementById('sl-intercept-iface').value.trim();
slShowResult('sl-intercept-result', '<span style="color:var(--text-muted)">Starting interception...</span>');
try {
const r = await postJSON('/starlink-hack/network/intercept', {target_ip: gateway || undefined, interface: iface || undefined});
let h = '';
if (r.ok) {
h += slAlert('Interception running (PID: ' + (r.pid || '?') + ', Tool: ' + (r.tool || '?') + ')', 'success');
if (r.capture_file) h += '<p style="font-size:0.85rem;color:var(--text-secondary)">Capture: ' + esc(r.capture_file) + '</p>';
} else {
h += slAlert(r.error || 'Failed', 'error');
}
slShowResult('sl-intercept-result', h);
} catch (e) {
slShowResult('sl-intercept-result', slAlert(e.message, 'error'));
}
}
async function slInterceptStop() {
try {
const r = await postJSON('/starlink-hack/network/intercept/stop', {});
slShowResult('sl-intercept-result', slAlert(r.message || 'Stopped', 'success'));
} catch (e) {
slShowResult('sl-intercept-result', slAlert(e.message, 'error'));
}
}
async function slDnsStart() {
const domain = document.getElementById('sl-dns-domain').value.trim();
const ip = document.getElementById('sl-dns-ip').value.trim();
if (!domain || !ip) { slShowResult('sl-dns-result', slAlert('Domain and IP are required', 'error')); return; }
slShowResult('sl-dns-result', '<span style="color:var(--text-muted)">Starting DNS spoof...</span>');
try {
const r = await postJSON('/starlink-hack/network/dns-spoof', {domain, ip});
slShowResult('sl-dns-result', r.ok ? slAlert('DNS spoofing active: ' + domain + ' -> ' + ip, 'success') : slAlert(r.error || 'Failed', 'error'));
} catch (e) {
slShowResult('sl-dns-result', slAlert(e.message, 'error'));
}
}
async function slDnsStop() {
try {
const r = await postJSON('/starlink-hack/network/dns-spoof/stop', {});
slShowResult('sl-dns-result', slAlert(r.message || 'Stopped', 'success'));
} catch (e) {
slShowResult('sl-dns-result', slAlert(e.message, 'error'));
}
}
async function slDeauth() {
const mac = document.getElementById('sl-deauth-mac').value.trim();
const iface = document.getElementById('sl-deauth-iface').value.trim();
if (!iface) { slShowResult('sl-deauth-result', slAlert('Wireless interface is required', 'error')); return; }
slShowResult('sl-deauth-result', '<span style="color:var(--text-muted)">Sending deauth...</span>');
try {
const r = await postJSON('/starlink-hack/network/deauth', {target_mac: mac || undefined, interface: iface});
slShowResult('sl-deauth-result', r.ok ? slAlert('Deauth sent to ' + (r.target || 'broadcast'), 'success') : slAlert(r.error || 'Failed', 'error'));
} catch (e) {
slShowResult('sl-deauth-result', slAlert(e.message, 'error'));
}
}
async function slMitm() {
const iface = document.getElementById('sl-mitm-iface').value.trim();
slShowResult('sl-mitm-result', '<span style="color:var(--text-muted)">Starting MITM...</span>');
try {
const r = await postJSON('/starlink-hack/network/mitm', {interface: iface || undefined});
let h = '';
if (r.ok) {
h += slAlert('MITM running (Tool: ' + (r.tool || '?') + ', PID: ' + (r.pid || '?') + ')', 'success');
if (r.note) h += '<p style="font-size:0.85rem;color:var(--text-secondary)">' + esc(r.note) + '</p>';
} else {
h += slAlert(r.error || 'Failed', 'error');
}
slShowResult('sl-mitm-result', h);
} catch (e) {
slShowResult('sl-mitm-result', slAlert(e.message, 'error'));
}
}
/* ── RF & Firmware ── */
async function slFirmwareCheck() {
setLoading('btn-sl-fw-check', true);
slShowResult('sl-fw-check-result', '<span style="color:var(--text-muted)">Checking firmware...</span>');
try {
const r = await postJSON('/starlink-hack/firmware/check', {});
let h = '';
if (r.ok) {
h += slCardHtml('Firmware Check', [
['Software Version', r.software_version || 'unknown'],
['Hardware Version', r.hardware_version || 'unknown'],
['Version Age', r.version_age || 'unknown'],
['Vulnerable', r.vulnerable ? 'YES' : 'No'],
]);
if (r.vulnerable) {
h += '<h3 style="color:#ef4444;font-size:0.95rem;margin:8px 0 4px 0">Matched Vulnerabilities</h3>';
const vulnRows = (r.vulnerabilities || []).map(v => [v.cve, v.title, v.severity, v.cvss]);
h += slTableHtml(['CVE', 'Title', 'Severity', 'CVSS'], vulnRows);
}
if (r.hardware_note) h += '<p style="font-size:0.8rem;color:var(--text-muted);margin-top:8px">' + esc(r.hardware_note) + '</p>';
} else {
h += slAlert(r.error || 'Check failed', 'error');
}
slShowResult('sl-fw-check-result', h);
} catch (e) {
slShowResult('sl-fw-check-result', slAlert(e.message, 'error'));
}
setLoading('btn-sl-fw-check', false);
}
async function slFirmwareAnalyze() {
const fileInput = document.getElementById('sl-fw-file');
if (!fileInput.files.length) { slShowResult('sl-fw-analyze-result', slAlert('Select a firmware file', 'error')); return; }
slShowResult('sl-fw-analyze-result', '<span style="color:var(--text-muted)">Analyzing firmware (may take a while)...</span>');
const form = new FormData();
form.append('file', fileInput.files[0]);
try {
const resp = await fetch('/starlink-hack/firmware/analyze', {method: 'POST', body: form});
const r = await resp.json();
let h = '';
if (r.ok) {
const fi = r.file_info || {};
h += slCardHtml('File Info', [
['Name', fi.name || '?'],
['Size', fi.size_human || '?'],
['Signatures Found', r.signature_count || 0],
['Interesting Strings', r.interesting_strings_count || 0],
]);
const ent = r.entropy_analysis || {};
if (ent.average !== undefined) {
h += slCardHtml('Entropy Analysis', [
['Average Entropy', ent.average],
['Max Entropy', ent.max],
['Min Entropy', ent.min],
['High Entropy Blocks', ent.high_entropy_blocks],
['Likely Encrypted', ent.likely_encrypted ? 'Yes' : 'No'],
['Likely Compressed', ent.likely_compressed ? 'Yes' : 'No'],
]);
}
const sigs = r.signatures || [];
if (sigs.length) {
h += '<h3 style="font-size:0.95rem;color:#f97316;margin:12px 0 4px 0">Signatures (' + sigs.length + ')</h3>';
h += slTableHtml(['Offset', 'Description'], sigs.slice(0, 50).map(s => [s.hex_offset || ('0x' + (s.offset || 0).toString(16)), s.description || '?']));
}
const strs = r.strings_of_interest || [];
if (strs.length) {
h += '<h3 style="font-size:0.95rem;color:#f97316;margin:12px 0 4px 0">Interesting Strings (' + strs.length + ')</h3>';
h += '<div style="background:var(--bg-input);border:1px solid var(--border);border-radius:var(--radius);padding:10px;max-height:300px;overflow-y:auto;font-family:monospace;font-size:0.8rem">';
for (const s of strs.slice(0, 100)) h += '<div>' + esc(s) + '</div>';
h += '</div>';
}
} else {
h += slAlert(r.error || 'Analysis failed', 'error');
}
slShowResult('sl-fw-analyze-result', h);
} catch (e) {
slShowResult('sl-fw-analyze-result', slAlert(e.message, 'error'));
}
}
async function slDebugInterfaces() {
slShowResult('sl-debug-result', '<span style="color:var(--text-muted)">Scanning...</span>');
try {
const r = await postJSON('/starlink-hack/firmware/debug', {});
let h = '';
if (r.ok) {
const ports = r.serial_ports || [];
h += slCardHtml('Debug Interface Scan', [
['Serial Ports Found', ports.length],
['JTAG Adapter Detected', r.jtag_detected ? 'Yes' : 'No'],
['OpenOCD Available', r.openocd_available ? 'Yes' : 'No'],
]);
if (ports.length) {
h += slTableHtml(['Device', 'Description', 'VID:PID', 'JTAG?'],
ports.map(p => [p.device, p.description, p.vid_pid || 'N/A', p.possible_jtag ? 'POSSIBLE' : '-']));
}
const inst = r.instructions || {};
if (inst.uart) {
h += slCardHtml('UART Instructions', [
['Settings', inst.uart.settings],
['Location', inst.uart.location],
['Tools', inst.uart.tools_needed],
]);
}
} else {
h += slAlert(r.error || 'Scan failed', 'error');
}
slShowResult('sl-debug-result', h);
} catch (e) {
slShowResult('sl-debug-result', slAlert(e.message, 'error'));
}
}
async function slRfDownlink() {
const device = document.getElementById('sl-rf-device').value;
const duration = parseInt(document.getElementById('sl-rf-duration').value) || 30;
slShowResult('sl-rf-downlink-result', '<span style="color:var(--text-muted)">Analyzing downlink (this may take ' + duration + 's)...</span>');
try {
const r = await postJSON('/starlink-hack/rf/downlink', {device, duration});
let h = '';
if (r.ok) {
h += slCardHtml('Downlink Analysis', [
['Band', r.band || 'Ku-band'],
['Freq Range', r.freq_range || '10.7-12.7 GHz'],
['Source', r.source || r.tool || 'unknown'],
['Capture File', r.capture_file || 'N/A'],
['Sweep Points', r.sweep_points || 'N/A'],
]);
if (r.dish_diagnostics) {
h += slCardHtml('Dish Diagnostics (Fallback)', [
['Downlink Throughput', (r.dish_diagnostics.downlink_throughput_bps || 0).toLocaleString() + ' bps'],
['Latency', (r.dish_diagnostics.pop_ping_latency_ms || 0) + ' ms'],
['Obstruction', (r.dish_diagnostics.obstruction_pct || 0) + '%'],
['SNR OK', r.dish_diagnostics.snr_above_noise_floor ? 'Yes' : 'No'],
]);
}
if (r.note) h += '<p style="font-size:0.8rem;color:var(--text-muted);margin-top:4px">' + esc(r.note) + '</p>';
if (r.alternatives) {
h += '<p style="font-size:0.8rem;color:var(--text-muted);margin-top:4px"><strong>LNB method:</strong> ' + esc(r.alternatives.lnb_method) + '</p>';
}
} else {
h += slAlert(r.error || 'Analysis failed', 'error');
}
slShowResult('sl-rf-downlink-result', h);
} catch (e) {
slShowResult('sl-rf-downlink-result', slAlert(e.message, 'error'));
}
}
async function slDetectJamming() {
slShowResult('sl-jamming-result', '<span style="color:var(--text-muted)">Analyzing jamming indicators...</span>');
try {
const r = await postJSON('/starlink-hack/rf/jamming', {});
let h = '';
if (r.ok) {
if (r.jamming_detected) {
h += slAlert('JAMMING INDICATORS DETECTED (Confidence: ' + (r.confidence || 'unknown') + ')', 'error');
} else {
h += slAlert('No jamming indicators detected (Confidence: ' + (r.confidence || 'none') + ')', 'success');
}
const indicators = r.indicators || [];
if (indicators.length) {
const rows = indicators.map(i => {
const sevColor = i.severity === 'high' ? '#ef4444' : i.severity === 'medium' ? '#f97316' : '#eab308';
return ['<span style="color:' + sevColor + '">' + esc(i.severity.toUpperCase()) + '</span>', esc(i.type), esc(i.detail)];
});
h += '<table style="width:100%;border-collapse:collapse;font-size:0.85rem;margin-top:8px"><thead><tr>';
h += '<th style="text-align:left;padding:6px 8px;border-bottom:1px solid var(--border);color:var(--text-secondary)">Severity</th>';
h += '<th style="text-align:left;padding:6px 8px;border-bottom:1px solid var(--border);color:var(--text-secondary)">Type</th>';
h += '<th style="text-align:left;padding:6px 8px;border-bottom:1px solid var(--border);color:var(--text-secondary)">Detail</th>';
h += '</tr></thead><tbody>';
for (const row of rows) {
h += '<tr><td style="padding:5px 8px;border-bottom:1px solid rgba(51,54,80,0.4)">' + row[0] + '</td>';
h += '<td style="padding:5px 8px;border-bottom:1px solid rgba(51,54,80,0.4)">' + row[1] + '</td>';
h += '<td style="padding:5px 8px;border-bottom:1px solid rgba(51,54,80,0.4)">' + row[2] + '</td></tr>';
}
h += '</tbody></table>';
}
if (r.recommendation) h += '<p style="font-size:0.8rem;color:var(--text-muted);margin-top:8px">' + esc(r.recommendation) + '</p>';
} else {
h += slAlert(r.error || 'Detection failed', 'error');
}
slShowResult('sl-jamming-result', h);
} catch (e) {
slShowResult('sl-jamming-result', slAlert(e.message, 'error'));
}
}
async function slLoadCves() {
slShowResult('sl-cve-result', '<span style="color:var(--text-muted)">Loading CVE database...</span>');
try {
const r = await fetchJSON('/starlink-hack/cves');
let h = '';
if (r.ok) {
if (r.current_firmware) {
h += '<p style="font-size:0.85rem;color:var(--text-secondary);margin-bottom:8px">Current firmware: <strong>' + esc(r.current_firmware) + '</strong>';
if (r.applicable_count > 0) {
h += ' — <span style="color:#ef4444">' + r.applicable_count + ' applicable CVE(s)</span>';
}
h += '</p>';
}
const cves = r.cves || [];
h += '<p style="font-size:0.85rem;color:var(--text-secondary);margin-bottom:8px">Total known CVEs: ' + cves.length + '</p>';
for (const cve of cves) {
const sevColor = cve.severity === 'Critical' ? '#ef4444' : cve.severity === 'High' ? '#f97316' : cve.severity === 'Medium' ? '#eab308' : '#22c55e';
h += '<div style="background:var(--bg-card);border:1px solid var(--border);border-left:3px solid ' + sevColor + ';border-radius:var(--radius);padding:12px;margin-bottom:10px">';
h += '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px">';
h += '<strong style="color:' + sevColor + '">' + esc(cve.cve) + '</strong>';
h += '<span style="font-size:0.8rem;color:' + sevColor + '">' + esc(cve.severity) + ' (CVSS ' + cve.cvss + ')</span>';
h += '</div>';
h += '<div style="font-size:0.9rem;font-weight:600;margin-bottom:4px">' + esc(cve.title) + '</div>';
h += '<div style="font-size:0.82rem;color:var(--text-secondary);margin-bottom:4px">' + esc(cve.description) + '</div>';
h += '<div style="font-size:0.8rem;color:var(--text-muted)"><strong>Affected:</strong> ' + esc(cve.affected) + '</div>';
h += '<div style="font-size:0.8rem;color:var(--text-muted)"><strong>Technique:</strong> ' + esc(cve.technique) + '</div>';
if (cve.references && cve.references.length) {
h += '<div style="font-size:0.8rem;margin-top:4px">';
for (const ref of cve.references) h += '<a href="' + esc(ref) + '" target="_blank" rel="noopener" style="display:block;color:var(--accent);font-size:0.78rem">' + esc(ref) + '</a>';
h += '</div>';
}
h += '</div>';
}
} else {
h += slAlert('Failed to load CVEs', 'error');
}
slShowResult('sl-cve-result', h);
} catch (e) {
slShowResult('sl-cve-result', slAlert(e.message, 'error'));
}
}
async function slExportResults() {
try {
const r = await postJSON('/starlink-hack/export', {});
if (r.ok) {
slShowResult('sl-cve-result', slAlert('Results exported to: ' + (r.path || '?') + ' (' + (r.size_human || '?') + ', ' + (r.entries || 0) + ' entries)', 'success'));
} else {
slShowResult('sl-cve-result', slAlert(r.error || 'Export failed', 'error'));
}
} catch (e) {
slShowResult('sl-cve-result', slAlert(e.message, 'error'));
}
}
</script>
{% endblock %}