Add channel hopping feature and track channels for detected APs

This commit is contained in:
Yaro Kasear 2025-05-02 08:47:32 -05:00
parent 2e3484ed83
commit 6ae40ca9c5

View file

@ -6,6 +6,7 @@ import signal
import subprocess import subprocess
import sys import sys
import time import time
import threading
from argparse import ArgumentParser from argparse import ArgumentParser
from collections import defaultdict from collections import defaultdict
@ -27,6 +28,10 @@ current_channel = None
include_probes = False include_probes = False
deadpoint_candidates = set() deadpoint_candidates = set()
unlinked_candidates = set() unlinked_candidates = set()
bssid_channels = {}
CHANNEL_LIST = [1, 6, 11, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165] # Channels to hop
CHANNEL_HOP_INTERVAL = 5 # Seconds per channel
# === Signal handling === # === Signal handling ===
def stop_sniff(signum, frame): def stop_sniff(signum, frame):
@ -92,6 +97,10 @@ def handle_packet(pkt):
ssid = parse_ssid(pkt) ssid = parse_ssid(pkt)
if ssid: if ssid:
ssid_map[a2] = ssid ssid_map[a2] = ssid
# Track channel seen on
if pkt.haslayer(RadioTap) and hasattr(pkt[RadioTap], 'ChannelFrequency'):
# Nah, be lazy
bssid_channels[a2] = current_channel
# === Track all seen clients === # === Track all seen clients ===
if dot11.type == 2: if dot11.type == 2:
@ -193,18 +202,30 @@ def print_suspect_aps():
if suspects: if suspects:
for bssid, ssid, flags in suspects: for bssid, ssid, flags in suspects:
print(f" - {bssid} (SSID: {ssid}) <-- {' + '.join(flags)}") ch = bssid_channels.get(bssid, "?")
print(f" - {bssid} (SSID: {ssid}, Channel: {ch}) <-- {' + '.join(flags)}")
else: else:
print(" None found (yet).") print(" None found (yet).")
def channel_hopper(interface):
global running
i = 0
while running:
channel = CHANNEL_LIST[i % len(CHANNEL_LIST)]
set_monitor_channel(interface, channel)
i += 1
time.sleep(CHANNEL_HOP_INTERVAL)
# === Main === # === Main ===
def main(): def main():
parser = ArgumentParser() parser = ArgumentParser()
parser.add_argument("--main-iface", required=True, help="Active interface (used to determine channel)") parser.add_argument("--main-iface", required=True, help="Active interface (used to determine channel)")
parser.add_argument("--monitor-iface", required=True, help="Monitor interface to sniff on") parser.add_argument("--monitor-iface", required=True, help="Monitor interface to sniff on")
parser.add_argument("--outfile", required=True, help="CSV file to append metrics row") parser.add_argument("--outfile", required=True, help="CSV file to append metrics row")
parser.add_argument("--channel", type=int, help="Channel to lock monitor interface to (overrides main iface)")
parser.add_argument("--include-probes", action="store_true", help="Include probe responses as valid APs") parser.add_argument("--include-probes", action="store_true", help="Include probe responses as valid APs")
group = parser.add_mutually_exclusive_group()
group.add_argument("--channel", type=int, help="Channel to lock monitor interface to")
group.add_argument("--channel-hop", action="store_true", help="Enable channel hopping")
args = parser.parse_args() args = parser.parse_args()
@ -237,8 +258,11 @@ def main():
target_ap_bssid = None # Can't determine AP if we're not associated target_ap_bssid = None # Can't determine AP if we're not associated
print("[+] Sniffing... (waiting for SIGINT to stop)") print("[+] Sniffing... (waiting for SIGINT to stop)")
if args.channel_hop:
hopper_thread = threading.Thread(target=channel_hopper, args=(args.monitor_iface,))
hopper_thread.daemon = True
hopper_thread.start()
while running: while running:
sniff(iface=args.monitor_iface, prn=handle_packet, store=False, timeout=5) sniff(iface=args.monitor_iface, prn=handle_packet, store=False, timeout=5)
@ -247,7 +271,8 @@ def main():
for bssid in sorted(aps): for bssid in sorted(aps):
ssid = ssid_map.get(bssid, "<unknown>") ssid = ssid_map.get(bssid, "<unknown>")
print(f" - {bssid} (SSID: {ssid})") ch = bssid_channels.get(bssid, "?")
print(f" - {bssid} (SSID: {ssid}, Channel: {ch})")
print(f"[+] Total APsOnChannel: {len(aps)}") print(f"[+] Total APsOnChannel: {len(aps)}")
print_suspect_aps() print_suspect_aps()