diff --git a/intercept.py b/intercept.py index 82118f0..8402853 100755 --- a/intercept.py +++ b/intercept.py @@ -701,6 +701,11 @@ HTML_TEMPLATE = ''' } } + @keyframes pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.3; } + } + .clear-btn { padding: 8px 16px; background: transparent; @@ -1674,6 +1679,20 @@ HTML_TEMPLATE = ''' +
+

Proximity Alerts

+
+ Alert when specific MAC addresses appear +
+
+ +
+ +
+
+

Attack Options

@@ -1812,7 +1831,8 @@ HTML_TEMPLATE = '''
+
+
Channel Utilization (5 GHz)
+
+
36
+
40
+
44
+
48
+
52
+
56
+
60
+
64
+
100
+
149
+
153
+
157
+
161
+
165
+
+
Security Overview
@@ -2000,6 +2039,7 @@ HTML_TEMPLATE = ''' if (mode === 'wifi') { refreshWifiInterfaces(); initRadar(); + initWatchList(); } else if (mode === 'bluetooth') { refreshBtInterfaces(); initBtRadar(); @@ -3092,6 +3132,137 @@ HTML_TEMPLATE = ''' let apCount = 0; let clientCount = 0; let handshakeCount = 0; + let rogueApCount = 0; + let ssidToBssids = {}; // Track SSIDs to their BSSIDs for rogue AP detection + let watchMacs = JSON.parse(localStorage.getItem('watchMacs') || '[]'); + let alertedMacs = new Set(); // Prevent duplicate alerts per session + + // 5GHz channel mapping for the graph + const channels5g = ['36', '40', '44', '48', '52', '56', '60', '64', '100', '149', '153', '157', '161', '165']; + + // Initialize watch list display + function initWatchList() { + updateWatchListDisplay(); + } + + // Add MAC to watch list + function addWatchMac() { + const input = document.getElementById('watchMacInput'); + const mac = input.value.trim().toUpperCase(); + if (!mac || !/^([0-9A-F]{2}:){5}[0-9A-F]{2}$/.test(mac)) { + alert('Please enter a valid MAC address (AA:BB:CC:DD:EE:FF)'); + return; + } + if (!watchMacs.includes(mac)) { + watchMacs.push(mac); + localStorage.setItem('watchMacs', JSON.stringify(watchMacs)); + updateWatchListDisplay(); + } + input.value = ''; + } + + // Remove MAC from watch list + function removeWatchMac(mac) { + watchMacs = watchMacs.filter(m => m !== mac); + localStorage.setItem('watchMacs', JSON.stringify(watchMacs)); + alertedMacs.delete(mac); + updateWatchListDisplay(); + } + + // Update watch list display + function updateWatchListDisplay() { + const container = document.getElementById('watchList'); + if (!container) return; + if (watchMacs.length === 0) { + container.innerHTML = '
No MACs in watch list
'; + } else { + container.innerHTML = watchMacs.map(mac => + `
+ ${mac} + +
` + ).join(''); + } + } + + // Check if MAC is in watch list and alert + function checkWatchList(mac, type) { + const upperMac = mac.toUpperCase(); + if (watchMacs.includes(upperMac) && !alertedMacs.has(upperMac)) { + alertedMacs.add(upperMac); + // Play alert sound multiple times for urgency + playAlert(); + setTimeout(playAlert, 300); + setTimeout(playAlert, 600); + // Show prominent alert + showProximityAlert(mac, type); + } + } + + // Show proximity alert popup + function showProximityAlert(mac, type) { + const alertDiv = document.createElement('div'); + alertDiv.className = 'proximity-alert'; + alertDiv.innerHTML = ` +
⚠ PROXIMITY ALERT
+
Watched ${type} detected:
+
${mac}
+ + `; + alertDiv.style.cssText = 'position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: #1a1a2e; border: 2px solid var(--accent-red); padding: 20px; border-radius: 8px; z-index: 10000; text-align: center; box-shadow: 0 0 30px rgba(255,0,0,0.5);'; + document.body.appendChild(alertDiv); + // Auto-dismiss after 10 seconds + setTimeout(() => alertDiv.remove(), 10000); + } + + // Check for rogue APs (same SSID, different BSSID) + function checkRogueAP(ssid, bssid) { + if (!ssid || ssid === 'Hidden' || ssid === '[Hidden]') return false; + + if (!ssidToBssids[ssid]) { + ssidToBssids[ssid] = new Set(); + } + + const isNewBssid = !ssidToBssids[ssid].has(bssid); + ssidToBssids[ssid].add(bssid); + + // If we have more than one BSSID for this SSID, it could be rogue (or just multiple APs) + if (ssidToBssids[ssid].size > 1 && isNewBssid) { + rogueApCount++; + document.getElementById('rogueApCount').textContent = rogueApCount; + playAlert(); + showInfo(`⚠ Potential Rogue AP: "${ssid}" seen on multiple BSSIDs (${ssidToBssids[ssid].size} total)`); + return true; + } + return false; + } + + // Update 5GHz channel graph + function updateChannel5gGraph() { + const bars = document.querySelectorAll('#channelGraph5g .channel-bar'); + const labels = document.querySelectorAll('#channelGraph5g .channel-label'); + + // Count networks per 5GHz channel + const channelCounts = {}; + channels5g.forEach(ch => channelCounts[ch] = 0); + + Object.values(wifiNetworks).forEach(net => { + const ch = net.channel?.toString().trim(); + if (channels5g.includes(ch)) { + channelCounts[ch]++; + } + }); + + const maxCount = Math.max(1, ...Object.values(channelCounts)); + + bars.forEach((bar, i) => { + const ch = channels5g[i]; + const count = channelCounts[ch] || 0; + const height = Math.max(2, (count / maxCount) * 50); + bar.style.height = height + 'px'; + bar.className = 'channel-bar' + (count > 0 ? ' active' : '') + (count > 3 ? ' congested' : '') + (count > 5 ? ' very-congested' : ''); + }); + } // Refresh WiFi interfaces function refreshWifiInterfaces() { @@ -3291,6 +3462,12 @@ HTML_TEMPLATE = ''' document.getElementById('apCount').textContent = apCount; playAlert(); pulseSignal(); + + // Check for rogue AP (same SSID, different BSSID) + checkRogueAP(net.essid, net.bssid); + + // Check proximity watch list + checkWatchList(net.bssid, 'AP'); } // Update recon display @@ -3305,6 +3482,10 @@ HTML_TEMPLATE = ''' // Add to output addWifiNetworkCard(net, isNew); + + // Update both channel graphs + updateChannelGraph(); + updateChannel5gGraph(); } // Handle discovered WiFi client @@ -3315,14 +3496,19 @@ HTML_TEMPLATE = ''' if (isNew) { clientCount++; document.getElementById('clientCount').textContent = clientCount; + + // Check proximity watch list + checkWatchList(client.mac, 'Client'); } - // Track in device intelligence + // Track in device intelligence with vendor info + const vendorInfo = client.vendor && client.vendor !== 'Unknown' ? ` [${client.vendor}]` : ''; trackDevice({ protocol: 'WiFi-Client', address: client.mac, - message: client.probes || '[No probes]', - bssid: client.bssid + message: (client.probes || '[No probes]') + vendorInfo, + bssid: client.bssid, + vendor: client.vendor }); } @@ -3400,8 +3586,12 @@ HTML_TEMPLATE = ''' }).then(r => r.json()) .then(data => { if (data.status === 'started') { - showInfo('Capturing handshakes for ' + bssid + '. File: ' + data.capture_file); + showInfo('🎯 Capturing handshakes for ' + bssid + '. File: ' + data.capture_file); setWifiRunning(true); + // Update handshake indicator to show active capture + const hsSpan = document.getElementById('handshakeCount'); + hsSpan.style.animation = 'pulse 1s infinite'; + hsSpan.title = 'Capturing: ' + bssid; } else { alert('Error: ' + data.message); } @@ -5113,6 +5303,8 @@ def parse_airodump_csv(csv_path): if len(parts) >= 6: station = parts[0] if station and ':' in station: + # Lookup vendor from OUI database + vendor = get_manufacturer(station) clients[station] = { 'mac': station, 'first_seen': parts[1], @@ -5120,7 +5312,8 @@ def parse_airodump_csv(csv_path): 'power': parts[3], 'packets': parts[4], 'bssid': parts[5], - 'probes': parts[6] if len(parts) > 6 else '' + 'probes': parts[6] if len(parts) > 6 else '', + 'vendor': vendor } except Exception as e: print(f"[WiFi] Error parsing CSV: {e}")