Last active
September 19, 2026 15:01
-
-
Save rvrsh3ll/b5a9e367fad44f59beb37dcf23ba612c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| import sys | |
| import os | |
| import subprocess | |
| import signal | |
| import time | |
| import re | |
| import argparse | |
| import logging | |
| global uniqueSSID | |
| global detectedSSID | |
| global pid | |
| uniqueSSID = 0 | |
| detectedSSID = {} | |
| logging.basicConfig(filename='app.log',level=logging.INFO) | |
| def dumpNetworks(signum, frame): | |
| global detectedSSID | |
| global uniqueSSID | |
| print("!! Dumping detected networks:") | |
| print("!! MAC Address SSID Count Last Seen") | |
| print("!! -------------------- ------------------------------ ---------- -------------------") | |
| for key in detectedSSID: | |
| lastSeen = time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(detectedSSID[key][2])) | |
| print("!! {:20s} {:30s} {:10s} {:20s}".format(detectedSSID[key][2], detectedSSID[key][0], detectedSSID[key][1], lastSeen)) | |
| print("!! Total unique SSID: {}".format(uniqueSSID)) | |
| def cleanKill(signum, frame): | |
| global pid | |
| global detectedSSID | |
| global uniqueSSID | |
| if pid: | |
| print("!! Received kill signal!") | |
| os.kill(pid, signal.SIGUSR1) | |
| dumpNetworks(signum, frame) | |
| sys.exit(0) | |
| def main(ssid,interface,verbose,dumpfile): | |
| ifconfigPath = "/sbin/ifconfig" | |
| iwconfigPath = "/sbin/iwconfig" | |
| tsharkPath = "/usr/bin/tshark" | |
| uniqueSSID = 0 | |
| detectedSSID = {} | |
| # Configure wireless interface | |
| os.system("{} {} up".format(ifconfigPath, interface)) | |
| # Set interface in monitor mode | |
| os.system("{} {} mode monitor".format(iwconfigPath, interface)) | |
| # Create the child process to change wireless channels | |
| pid = os.fork() | |
| if pid: | |
| # --------------------------------- | |
| # Parent process: run the main loop | |
| # --------------------------------- | |
| if verbose: | |
| print("!! Running with PID: {} (child: {})".format(os.getpid(), pid)) | |
| tshark = subprocess.Popen([tsharkPath, "-i", interface, "-n", "-l", "subtype", "probereq"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
| for line in iter(tshark.stdout.readline, b''): | |
| line = line.decode().strip() | |
| if re.match("[a-zA-ZÀ-ÿ0-9\"\s\!\@\$\%\^\&\*\(\)\_\-\+\=\[\]\{\}\,\.\?\>\<]+", line): | |
| (macAddress, newKey) = re.search("\\d+\\.\\d+ ([a-zA-Z0-9:_]+).+SSID=([a-zA-ZÀ-ÿ0-9\"\\s\\!\\@\\$\\%\\^\\&\\*\\(\\)\\_\\-\\+\\=\\[\\]\\{\\}\\,\\.\\?\\>\\<]+)", line).group(1, 2) | |
| if newKey != "Broadcast": # Ignore broadcasts | |
| if newKey not in detectedSSID: | |
| # New network found! | |
| if newKey.replace("\"","") == ssid: | |
| print("Alert! Probe for {} is in-range!!".format(ssid)) | |
| newSSID = [newKey, 1, macAddress, time.time()] | |
| detectedSSID[newKey] = newSSID | |
| uniqueSSID += 1 | |
| print("++ New probe request from {} with SSID: {} [{}]".format(macAddress, newKey, uniqueSSID)) | |
| logging.info("macAddress,{},ssid,{}".format(macAddress,newKey)) | |
| else: | |
| # Existing SSID found! | |
| detectedSSID[newKey][1] += 1 # Increase packets counter | |
| detectedSSID[newKey][2] = macAddress # MAC Address | |
| detectedSSID[newKey][3] = time.time() # Now | |
| if verbose: | |
| print("-- Probe seen before: {} [{}]".format(newKey, uniqueSSID)) | |
| tshark.stdout.close() | |
| tshark.stderr.close() | |
| tshark.wait() | |
| else: | |
| # -------------------------------------------------- | |
| # Child process: Switch channels at regular interval | |
| # -------------------------------------------------- | |
| if verbose: | |
| print("!! Switching wireless channel every 5.") | |
| while True: | |
| for channel in range(1, 13): | |
| os.system("{} {} channel {}".format(iwconfigPath, interface, channel)) | |
| time.sleep(5) | |
| if __name__ == "__main__": | |
| signal.signal(signal.SIGUSR1, dumpNetworks) | |
| signal.signal(signal.SIGINT, cleanKill) | |
| signal.signal(signal.SIGTERM, cleanKill) | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument('-s', '--SSID', type=str, required=False) | |
| parser.add_argument('-i','--interface', type=str, default="wlan0", required=False) | |
| parser.add_argument('-v','--verbose', action="store_true", required=False) | |
| parser.add_argument('-d','--dumpfile', type=str, required=False) | |
| args = parser.parse_args() | |
| if os.geteuid() != 0: | |
| sys.exit("{} must be run by root!".format(sys.argv[0])) | |
| main(args.SSID,args.interface,args.verbose,args.dumpfile) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment