From 2b40ce3706538a9e41d3d18d7ed6a81105940dfa Mon Sep 17 00:00:00 2001 From: derv82 Date: Wed, 18 Apr 2018 14:42:24 -0400 Subject: [PATCH] Code cleanup --- wifite/args.py | 2 +- wifite/config.py | 26 ++-- wifite/model/attack.py | 12 +- wifite/tools/airmon.py | 311 +++++++++++++++++++++---------------- wifite/tools/airodump.py | 99 ++++++------ wifite/tools/ifconfig.py | 30 ++-- wifite/tools/iwconfig.py | 6 +- wifite/tools/macchanger.py | 100 ++++++------ wifite/util/color.py | 26 ++-- 9 files changed, 333 insertions(+), 279 deletions(-) diff --git a/wifite/args.py b/wifite/args.py index 2e721bb..7534fde 100755 --- a/wifite/args.py +++ b/wifite/args.py @@ -67,7 +67,7 @@ class Arguments(object): glob.add_argument('--channel', help=argparse.SUPPRESS, action='store', dest='channel', type=int) glob.add_argument('-mac', - '---random-mac', + '--random-mac', action='store_true', dest='random_mac', help=Color.s('Randomize wireless card MAC address (default: {G}off{W})')) diff --git a/wifite/config.py b/wifite/config.py index 6b73ce2..f0b4ac7 100755 --- a/wifite/config.py +++ b/wifite/config.py @@ -1,18 +1,19 @@ #!/usr/bin/python2.7 # -*- coding: utf-8 -*- +import os + from .util.color import Color from .tools.macchanger import Macchanger -import os - class Configuration(object): ''' Stores configuration variables and functions for Wifite. ''' - verbose = 0 + version = '2.1.3' initialized = False # Flag indicating config has been initialized temp_dir = None # Temporary directory - version = '2.1.3' + interface = None + verbose = 0 @staticmethod def initialize(load_interface=True): @@ -315,15 +316,18 @@ class Configuration(object): Configuration.delete_temp() Macchanger.reset_if_changed() from .tools.airmon import Airmon - if hasattr(Configuration, "interface") and Configuration.interface is not None and Airmon.base_interface is not None: - Color.pl('{!} Leaving interface {C}%s{W} in Monitor Mode.' % Configuration.interface) - Color.pl('{!} You can disable Monitor Mode when finished ({C}airmon-ng stop %s{W})' % Configuration.interface) - #Airmon.stop(Configuration.interface) - #Airmon.put_interface_up(Airmon.base_interface) + if Configuration.interface is not None and Airmon.base_interface is not None: + #Color.pl('{!} Leaving interface {C}%s{W} in Monitor Mode.' % Configuration.interface) + #Color.pl('{!} You can disable Monitor Mode when finished ({C}airmon-ng stop %s{W})' % Configuration.interface) + + # Stop monitor mode + Airmon.stop(Configuration.interface) + # Bring original interface back up + Airmon.put_interface_up(Airmon.base_interface) if Airmon.killed_network_manager: - Color.pl('{!} You can restart NetworkManager when finished ({C}service network-manager start{W})') - #Airmon.start_network_manager() + #Color.pl('{!} You can restart NetworkManager when finished ({C}service network-manager start{W})') + Airmon.start_network_manager() exit(code) diff --git a/wifite/model/attack.py b/wifite/model/attack.py index 9e0cc2e..a915c21 100755 --- a/wifite/model/attack.py +++ b/wifite/model/attack.py @@ -4,9 +4,7 @@ import time class Attack(object): - ''' - Contains functionality common to all attacks - ''' + '''Contains functionality common to all attacks.''' target_wait = 20 @@ -17,17 +15,13 @@ class Attack(object): raise Exception("Unimplemented method: run") def wait_for_target(self, airodump): - ''' - Waits for target to appear in airodump - ''' + '''Waits for target to appear in airodump.''' start_time = time.time() targets = airodump.get_targets(apply_filter=False) while len(targets) == 0: # Wait for target to appear in airodump. if int(time.time() - start_time) > Attack.target_wait: - raise Exception( - "Target did not appear after %d seconds, stopping" - % Attack.target_wait) + raise Exception('Target did not appear after %d seconds, stopping' % Attack.target_wait) time.sleep(1) targets = airodump.get_targets() continue diff --git a/wifite/tools/airmon.py b/wifite/tools/airmon.py index b8bf2a6..5f42dc3 100755 --- a/wifite/tools/airmon.py +++ b/wifite/tools/airmon.py @@ -13,11 +13,49 @@ import re import os import signal +class AirmonIface(object): + def __init__(self, phy, interface, driver, chipset): + self.phy = phy + self.interface = interface + self.driver = driver + self.chipset = chipset + self.mac_address = Ifconfig.get_mac(interface) + + # Max length of fields. + # Used for printing a table of interfaces. + PHY_LEN = 6 + INTERFACE_LEN = 12 + DRIVER_LEN = 20 + CHIPSET_LEN = 30 + + def __str__(self): + ''' Colored string representation of interface ''' + s = Color.s('{W}%s' % self.phy.ljust(self.PHY_LEN)) + s += Color.s('{G}%s' % self.interface.ljust(self.INTERFACE_LEN)) + s += Color.s('{C}%s' % self.driver.ljust(self.DRIVER_LEN)) + s += Color.s('{W}%s' % self.chipset.ljust(self.CHIPSET_LEN)) + return s + + @staticmethod + def menu_header(): + ''' Colored header row for interfaces ''' + s = ' ' + s += 'PHY'.ljust(AirmonIface.PHY_LEN) + s += 'Interface'.ljust(AirmonIface.INTERFACE_LEN) + s += 'Driver'.ljust(AirmonIface.DRIVER_LEN) + s += 'Chipset'.ljust(AirmonIface.CHIPSET_LEN) + s += '\n' + s += '-' * (Interface.PHY_LEN + Interface.INTERFACE_LEN + Interface.DRIVER_LEN + Interface.CHIPSET_LEN + 3) + return s + + class Airmon(object): ''' Wrapper around the 'airmon-ng' program ''' base_interface = None killed_network_manager = False + # Drivers that need to be manually put into monitor mode + BAD_DRIVERS = ['rtl8821au'] #see if_arp.h ARPHRD_ETHER = 1 #managed ARPHRD_IEEE80211_RADIOTAP = 803 #monitor @@ -31,7 +69,7 @@ class Airmon(object): def print_menu(self): ''' Prints menu ''' - print(Interface.menu_header()) + print(AirmonIface.menu_header()) for idx, iface in enumerate(self.interfaces, start=1): Color.pl(" {G}%d{W}. %s" % (idx, iface)) @@ -44,46 +82,59 @@ class Airmon(object): @staticmethod def get_interfaces(): - ''' - Returns: - List of Interface objects known by airmon-ng - ''' + '''Returns List of AirmonIface objects known by airmon-ng''' interfaces = [] p = Process('airmon-ng') for line in p.stdout().split('\n'): - # Ignore blank/header lines - if len(line) == 0 or line.startswith('Interface') or line.startswith('PHY'): + # [PHY ]IFACE DRIVER CHIPSET + airmon_re = re.compile(r'^(?:([^\t]*)\t+)?([^\t]*)\t+([^\t]*)\t+([^\t]*)$') + matches = airmon_re.match(line) + if not matches: continue - # Strip out interface information - fields = line.split("\t") - while '' in fields: - fields.remove('') - # Add Interface object to list - interfaces.append(Interface(fields)) + phy, interface, driver, chipset = matches.groups() + if phy == 'PHY' or phy == 'Interface': + continue # Header + + interfaces.append(AirmonIface(phy, interface, driver, chipset)) + return interfaces @staticmethod - def start_baddriver(iface): #fix for bad drivers like the rtl8812AU + def start_bad_driver(iface): + ''' + Manually put interface into monitor mode (no airmon-ng or vif). + Fix for bad drivers like the rtl8812AU. + ''' Ifconfig.down(iface) Iwconfig.mode(iface, 'monitor') Ifconfig.up(iface) - with open("/sys/class/net/" + iface + "/type", "r") as f: - if (int(f.read()) == Airmon.ARPHRD_IEEE80211_RADIOTAP): - return iface + # /sys/class/net/wlan0/type + iface_type_path = os.path.join('/sys/class/net', iface, 'type') + if os.path.exists(iface_type_path): + with open(iface_type_path, 'r') as f: + if (int(f.read()) == Airmon.ARPHRD_IEEE80211_RADIOTAP): + return iface return None @staticmethod - def stop_baddriver(iface): + def stop_bad_driver(iface): + ''' + Manually put interface into managed mode (no airmon-ng or vif). + Fix for bad drivers like the rtl8812AU. + ''' Ifconfig.down(iface) Iwconfig.mode(iface, 'managed') Ifconfig.up(iface) - with open("/sys/class/net/" + iface + "/type", "r") as f: - if (int(f.read()) == Airmon.ARPHRD_ETHER): - return iface + # /sys/class/net/wlan0/type + iface_type_path = os.path.join('/sys/class/net', iface, 'type') + if os.path.exists(iface_type_path): + with open(iface_type_path, 'r') as f: + if (int(f.read()) == Airmon.ARPHRD_ETHER): + return iface return None @@ -93,7 +144,7 @@ class Airmon(object): Starts an interface (iface) in monitor mode Args: iface - The interface to start in monitor mode - Either an instance of Interface object, + Either an instance of AirmonIface object, or the name of the interface (string). Returns: Name of the interface put into monitor mode. @@ -101,117 +152,121 @@ class Airmon(object): Exception - If an interface can't be put into monitor mode ''' # Get interface name from input - if type(iface) == Interface: - iface = iface.interface - Airmon.base_interface = iface + if type(iface) == AirmonIface: + iface_name = iface.interface + driver = iface.driver + else: + iface_name = iface + driver = None - # Call airmon-ng - Color.p("{+} enabling {G}monitor mode{W} on {C}%s{W}... " % iface) - (out,err) = Process.call('airmon-ng start %s' % iface) + # Remember this as the "base" interface. + Airmon.base_interface = iface_name - mon_iface = Airmon._parse_airmon_start(out) + Color.p("{+} enabling {G}monitor mode{W} on {C}%s{W}... " % iface_name) - if mon_iface is None: - # Airmon did not enable monitor mode on an interface - mon_iface = Airmon.start_baddriver(iface) + airmon_output = Process(['airmon-ng', 'start', iface_name]).stdout() - if mon_iface is None: + enabled_iface = Airmon._parse_airmon_start(airmon_output) + + if enabled_iface is None and driver in Airmon.BAD_DRIVERS: + Color.p('{O}"bad driver" detected{W} ') + enabled_iface = Airmon.start_bad_driver(iface_name) + + if enabled_iface is None: Color.pl("{R}failed{W}") - mon_ifaces = Airmon.get_interfaces_in_monitor_mode() + monitor_interfaces = Iwconfig.get_interfaces(mode='Monitor') # Assert that there is an interface in monitor mode - if len(mon_ifaces) == 0: + if len(monitor_interfaces) == 0: Color.pl("{R}failed{W}") - raise Exception("iwconfig does not see any interfaces in Mode:Monitor") + raise Exception("Cannot find any interfaces in Mode:Monitor") # Assert that the interface enabled by airmon-ng is in monitor mode - if mon_iface not in mon_ifaces: + if enabled_iface not in monitor_interfaces: Color.pl("{R}failed{W}") - raise Exception("iwconfig does not see %s in Mode:Monitor" % mon_iface) + raise Exception("Cannot find %s with Mode:Monitor" % enabled_iface) - # No errors found; the device 'mon_iface' was put into MM. - Color.pl("{G}enabled {C}%s{W}" % mon_iface) + # No errors found; the device 'enabled_iface' was put into Mode:Monitor. + Color.pl("{G}enabled {C}%s{W}" % enabled_iface) - Configuration.interface = mon_iface - - return mon_iface + return enabled_iface @staticmethod - def _parse_airmon_start(stdout): - # Find the interface put into monitor mode (if any) - mon_iface = None - for line in stdout.split('\n'): - if 'monitor mode' in line and 'enabled' in line and ' on ' in line: - mon_iface = line.split(' on ')[1] - if ']' in mon_iface: - mon_iface = mon_iface.split(']')[1] - if ')' in mon_iface: - mon_iface = mon_iface.split(')')[0] - break - return mon_iface + def _parse_airmon_start(airmon_output): + '''Find the interface put into monitor mode (if any)''' + + # airmon-ng output: (mac80211 monitor mode vif enabled for [phy10]wlan0 on [phy10]wlan0mon) + enabled_re = re.compile(r'\s*\(mac80211 monitor mode (?:vif )?enabled for [^ ]+ on (?:\[\w+\])?(\w+)\)\s*') + + for line in airmon_output.split('\n'): + matches = enabled_re.match(line) + if matches: + return matches.group(1) + + return None @staticmethod def stop(iface): Color.p("{!} {R}disabling {O}monitor mode{O} on {R}%s{O}... " % iface) - (out,err) = Process.call('airmon-ng stop %s' % iface) - mon_iface = None - for line in out.split('\n'): - # aircrack-ng 1.2 rc2 - if 'monitor mode' in line and 'disabled' in line and ' for ' in line: - mon_iface = line.split(' for ')[1] - if ']' in mon_iface: - mon_iface = mon_iface.split(']')[1] - if ')' in mon_iface: - mon_iface = mon_iface.split(')')[0] - break - # aircrack-ng 1.2 rc1 - match = re.search('([a-zA-Z0-9]+).*\(removed\)', line) - if match: - mon_iface = match.groups()[0] - break + airmon_output = Process(['airmon-ng', 'stop', iface]).stdout() - if not mon_iface: - mon_iface = Airmon.stop_baddriver(iface) + disabled_iface = Airmon._parse_airmon_stop(airmon_output) - if mon_iface: - Color.pl('{R}disabled %s{W}' % mon_iface) + if not disabled_iface and iface in Airmon.BAD_DRIVERS: + Color.p('{O}"bad driver" detected{W} ') + disabled_iface = Airmon.stop_bad_driver(iface) + + if disabled_iface: + Color.pl('{G}disabled %s{W}' % disabled_iface) else: Color.pl('{O}could not disable on {R}%s{W}' % iface) @staticmethod - def get_interfaces_in_monitor_mode(): - ''' - Uses 'iwconfig' to find all interfaces in monitor mode - Returns: - List of interface names that are in monitor mode - ''' - return Iwconfig.get_interfaces(mode='Monitor') + def _parse_airmon_stop(airmon_output): + '''Find the interface taken out of into monitor mode (if any)''' + + # airmon-ng 1.2rc2 output: (mac80211 monitor mode vif enabled for [phy10]wlan0 on [phy10]wlan0mon) + disabled_re = re.compile(r'\s*\(mac80211 monitor mode (?:vif )?disabled for (?:\[\w+\])?(\w+)\)\s*') + + # airmon-ng 1.2rc1 output: wlan0mon (removed) + removed_re = re.compile(r'([a-zA-Z0-9]+).*\(removed\)') + + disabled_iface = None + for line in airmon_output.split('\n'): + matches = disabled_re.match(line) + if matches: + return matches.group(1) + + matches = removed_re.match(line) + if matches: + return matches.group(1) + + return None @staticmethod def ask(): ''' - Asks user to define which wireless interface to use. - Does not ask if: - 1. There is already an interface in monitor mode, or - 2. There is only one wireles interface (automatically selected). - Puts selected device into Monitor Mode. + Asks user to define which wireless interface to use. + Does not ask if: + 1. There is already an interface in monitor mode, or + 2. There is only one wireless interface (automatically selected). + Puts selected device into Monitor Mode. ''' Airmon.terminate_conflicting_processes() Color.pl('\n{+} looking for {C}wireless interfaces{W}') - mon_ifaces = Airmon.get_interfaces_in_monitor_mode() - mon_count = len(mon_ifaces) - if mon_count == 1: + monitor_interfaces = Iwconfig.get_interfaces(mode='Monitor') + if len(monitor_interfaces) == 1: # Assume we're using the device already in montior mode - iface = mon_ifaces[0] - Color.pl('{+} using interface {G}%s{W} which is already in monitor mode' - % iface); + iface = monitor_interfaces[0] + Color.pl(' using interface {G}%s{W} (already in monitor mode)' % iface); + Color.pl(' you can specify the wireless interface using {C}-i wlan0{W}') Airmon.base_interface = None return iface @@ -240,7 +295,7 @@ class Airmon(object): iface = a.get(choice) - if a.get(choice).interface in mon_ifaces: + if a.get(choice).interface in monitor_interfaces: Color.pl('{+} {G}%s{W} is already in monitor mode' % iface.interface) else: iface.interface = Airmon.start(iface) @@ -251,52 +306,48 @@ class Airmon(object): def terminate_conflicting_processes(): ''' Deletes conflicting processes reported by airmon-ng ''' - ''' - % airmon-ng check + airmon_output = Process(['airmon-ng', 'check']).stdout() - Found 3 processes that could cause trouble. - If airodump-ng, aireplay-ng or airtun-ng stops working after - a short period of time, you may want to kill (some of) them! - -e - PID Name - 2272 dhclient - 2293 NetworkManager - 3302 wpa_supplicant - ''' + # Conflicting process IDs and names + pid_pnames = [] - out = Process(['airmon-ng', 'check']).stdout() - if 'processes that could cause trouble' not in out: - # No proceses to kill + # 2272 dhclient + # 2293 NetworkManager + pid_pname_re = re.compile(r'^\s*(\d+)\s*([a-zA-Z0-9_\-]+)\s*$') + for line in airmon_output.split('\n'): + match = pid_pname_re.match(line) + if match: + pid = match.group(1) + pname = match.group(2) + pid_pnames.append( (pid, pname) ) + + if len(pid_pnames) == 0: return - hit_pids = False - for line in out.split('\n'): - if re.search('^ *PID', line): - hit_pids = True - continue - if not hit_pids or line.strip() == '': - continue - match = re.search('^[ \t]*(\d+)[ \t]*([a-zA-Z0-9_\-]+)[ \t]*$', line) - if match: - # Found process - pid = match.groups()[0] - pname = match.groups()[1] - if Configuration.kill_conflicting_processes: - Color.pl('{!} {R}terminating {O}conflicting process {R}%s{O} (PID {R}%s{O})' % (pname, pid)) - os.kill(int(pid), signal.SIGTERM) - if pname == 'NetworkManager': - Airmon.killed_network_manager= True - else: - Color.pl('{!} {O}conflicting process: {R}%s{O} (PID {R}%s{O})' % (pname, pid)) - if not Configuration.kill_conflicting_processes: - Color.pl('{!} {O}if you have problems, try killing these processes ({R}kill -9 PID{O}){W}') + # Don't kill processes, warn user + for pid, pname in pid_pnames: + Color.pl('{!} {O}conflicting process: {R}%s{O} (PID {R}%s{O})' % (pname, pid)) + Color.pl('{!} {O}if you have problems: {R}kill -9 PID{O} or re-run wifite with {R}--kill{O}){W}') + return + + Color.pl('{!} {O}killing {R}%d {O}conflicting processes' % len(pid_pnames)) + for pid, pname in pid_pnames: + if pname == 'NetworkManager' and Process.exists('service'): + Color.pl('{!} {O}stopping network-manager ({R}service network-manager stop{O})') + # Can't just pkill network manager; it's a service + Process(['service', 'network-manager', 'stop']).wait() + Airmon.killed_network_manager = True + else: + Color.pl('{!} {R}terminating {O}conflicting process {R}%s{O} (PID {R}%s{O})' % (pname, pid)) + os.kill(int(pid), signal.SIGTERM) + @staticmethod def put_interface_up(iface): Color.p("{!} {O}putting interface {R}%s up{O}..." % (iface)) Ifconfig.up(iface) - Color.pl(" {R}done{W}") + Color.pl(" {G}done{W}") @staticmethod def start_network_manager(): diff --git a/wifite/tools/airodump.py b/wifite/tools/airodump.py index ccfa72d..c5467a7 100755 --- a/wifite/tools/airodump.py +++ b/wifite/tools/airodump.py @@ -16,9 +16,7 @@ class Airodump(object): def __init__(self, interface=None, channel=None, encryption=None,\ wps=False, target_bssid=None, output_file_prefix='airodump',\ ivs_only=False, skip_wps=False): - ''' - Sets up airodump arguments, doesn't start process yet - ''' + '''Sets up airodump arguments, doesn't start process yet.''' Configuration.initialize() @@ -51,9 +49,9 @@ class Airodump(object): def __enter__(self): ''' - Setting things up for this context. - Called at start of 'with Airodump(...) as x:' - Actually starts the airodump process. + Setting things up for this context. + Called at start of 'with Airodump(...) as x:' + Actually starts the airodump process. ''' self.delete_airodump_temp_files() @@ -67,22 +65,15 @@ class Airodump(object): '-w', self.csv_file_prefix, # Output file prefix '--write-interval', '1' # Write every second ] - if self.channel: - command.extend(['-c', str(self.channel)]) - elif self.five_ghz: - command.extend(['--band', 'a']) + if self.channel: command.extend(['-c', str(self.channel)]) + elif self.five_ghz: command.extend(['--band', 'a']) - if self.encryption: - command.extend(['--enc', self.encryption]) - if self.wps: - command.extend(['--wps']) - if self.target_bssid: - command.extend(['--bssid', self.target_bssid]) + if self.encryption: command.extend(['--enc', self.encryption]) + if self.wps: command.extend(['--wps']) + if self.target_bssid: command.extend(['--bssid', self.target_bssid]) - if self.ivs_only: - command.extend(['--output-format', 'ivs,csv']) - else: - command.extend(['--output-format', 'pcap,csv']) + if self.ivs_only: command.extend(['--output-format', 'ivs,csv']) + else: command.extend(['--output-format', 'pcap,csv']) # Start the process self.pid = Process(command, devnull=True) @@ -91,8 +82,8 @@ class Airodump(object): def __exit__(self, type, value, traceback): ''' - Tearing things down since the context is being exited. - Called after 'with Airodump(...)' goes out of scope. + Tearing things down since the context is being exited. + Called after 'with Airodump(...)' goes out of scope. ''' # Kill the process self.pid.interrupt() @@ -104,16 +95,20 @@ class Airodump(object): def find_files(self, endswith=None): ''' Finds all files in the temp directory that start with the output_file_prefix ''' result = [] - for fil in os.listdir(Configuration.temp()): - if fil.startswith(self.output_file_prefix): - if not endswith or fil.endswith(endswith): - result.append(Configuration.temp() + fil) + temp = Configuration.temp() + for fil in os.listdir(temp): + if not fil.startswith(self.output_file_prefix): + continue + + if not endswith or fil.endswith(endswith): + result.append(os.path.join(temp, fil)) + return result def delete_airodump_temp_files(self): ''' - Deletes airodump* files in the temp directory. - Also deletes replay_*.cap and *.xor files in pwd. + Deletes airodump* files in the temp directory. + Also deletes replay_*.cap and *.xor files in pwd. ''' # Remove all temp files for fil in self.find_files(): @@ -130,14 +125,12 @@ class Airodump(object): # Find the .CSV file csv_filename = None for fil in self.find_files(endswith='-01.csv'): - # Found the file - csv_filename = fil + csv_filename = fil # Found the file break - if csv_filename is None or not os.path.exists(csv_filename): - # No file found - return self.targets - # Parse the .CSV file + if csv_filename is None or not os.path.exists(csv_filename): + return self.targets # No file found + targets = Airodump.get_targets_from_csv(csv_filename) # Check targets for WPS @@ -156,9 +149,12 @@ class Airodump(object): # Sort by power targets.sort(key=lambda x: x.power, reverse=True) + # Identify decloaked targets for old_target in self.targets: for new_target in targets: - if old_target.bssid != new_target.bssid: continue + if old_target.bssid != new_target.bssid: + continue + if new_target.essid_known and not old_target.essid_known: # We decloaked a target! new_target.decloaked = True @@ -175,9 +171,7 @@ class Airodump(object): @staticmethod def get_targets_from_csv(csv_filename): - ''' - Returns list of Target objects parsed from CSV file - ''' + '''Returns list of Target objects parsed from CSV file.''' targets = [] import csv with open(csv_filename, 'rb') as csvopen: @@ -270,16 +264,16 @@ class Airodump(object): def deauth_hidden_targets(self): ''' - Sends deauths (to broadcast and to each client) for all - targets (APs) that have unknown ESSIDs (hidden router names). + Sends deauths (to broadcast and to each client) for all + targets (APs) that have unknown ESSIDs (hidden router names). ''' self.decloaking = False - # Do not deauth if requested - if Configuration.no_deauth: return + if Configuration.no_deauth: + return # Do not deauth if requested - # Do not deauth if channel is not fixed. - if self.channel is None: return + if self.channel is None: + return # Do not deauth if channel is not fixed. # Reusable deauth command deauth_cmd = [ @@ -288,22 +282,27 @@ class Airodump(object): str(Configuration.num_deauths), # Number of deauth packets to send '--ignore-negative-one' ] + for target in self.targets: - if target.essid_known: continue + if target.essid_known: + continue + now = int(time.time()) secs_since_decloak = now - self.decloaked_times.get(target.bssid, 0) - # Decloak every AP once every 30 seconds - if secs_since_decloak < 30: continue + + if secs_since_decloak < 30: + continue # Decloak every AP once every 30 seconds + self.decloaking = True self.decloaked_times[target.bssid] = now if Configuration.verbose > 1: from ..util.color import Color - verbout = " [?] Deauthing %s" % target.bssid - verbout += " (broadcast & %d clients)" % len(target.clients) - Color.pe("\n{C}" + verbout + "{W}") + Color.pe('{C} [?] Deauthing %s (broadcast & %d clients){W}' % (target.bssid, len(target.clients))) + # Deauth broadcast iface = Configuration.interface Process(deauth_cmd + ['-a', target.bssid, iface]) + # Deauth clients for client in target.clients: Process(deauth_cmd + ['-a', target.bssid, '-c', client.bssid, iface]) diff --git a/wifite/tools/ifconfig.py b/wifite/tools/ifconfig.py index b0de5a8..5a9cb0c 100644 --- a/wifite/tools/ifconfig.py +++ b/wifite/tools/ifconfig.py @@ -18,7 +18,8 @@ class Ifconfig(object): pid = Process(command) pid.wait() - return pid.poll() == 0 + if pid.poll() != 0: + raise Exception('Error putting interface %s up:\n%s\n%s' % (interface, pid.stdout(), pid.stderr())) @classmethod @@ -26,15 +27,10 @@ class Ifconfig(object): '''Put interface down''' from ..util.process import Process - command = ['ifconfig', interface, 'down'] - if type(args) is list: - command.extend(args) - elif type(args) is 'str': - command.append(args) - - pid = Process(command) + pid = Process(['ifconfig', interface, 'down']) pid.wait() - return pid.poll() == 0 + if pid.poll() != 0: + raise Exception('Error putting interface %s down:\n%s\n%s' % (interface, pid.stdout(), pid.stderr())) @classmethod @@ -43,11 +39,17 @@ class Ifconfig(object): output = Process(['ifconfig', interface]).stdout() - mac_regex = ('[a-zA-Z0-9]{2}-' * 6)[:-1] - match = re.search(' (%s)' % mac_regex, output) + # Mac address separated by dashes + mac_dash_regex = ('[a-zA-Z0-9]{2}-' * 6)[:-1] + match = re.search(' ({})'.format(mac_dash_regex), output) + if match: + return match.group(1).replace('-', ':') - if not match: - raise Exception('Could not find the mac address for %s' % interface) + # Mac address separated by colons + mac_colon_regex = ('[a-zA-Z0-9]{2}:' * 6)[:-1] + match = re.search(' ({})'.format(mac_colon_regex), output) + if match: + return match.group(1) - return match.groups()[0].replace('-', ':') + raise Exception('Could not find the mac address for %s' % interface) diff --git a/wifite/tools/iwconfig.py b/wifite/tools/iwconfig.py index f09a3ae..939f15f 100644 --- a/wifite/tools/iwconfig.py +++ b/wifite/tools/iwconfig.py @@ -4,7 +4,9 @@ class Iwconfig(object): @classmethod def exists(cls): - pass + from ..util.process import Process + return Process.exists('iwconfig') + @classmethod def mode(cls, iface, mode_name): @@ -15,6 +17,7 @@ class Iwconfig(object): return pid.poll() + @classmethod def get_interfaces(cls, mode=None): from ..util.process import Process @@ -34,5 +37,6 @@ class Iwconfig(object): if mode is not None and 'Mode:{}'.format(mode) in line: interfaces.add(iface) + return list(interfaces) diff --git a/wifite/tools/macchanger.py b/wifite/tools/macchanger.py index 81e74b9..43313c8 100755 --- a/wifite/tools/macchanger.py +++ b/wifite/tools/macchanger.py @@ -6,76 +6,80 @@ from ..tools.ifconfig import Ifconfig from ..util.color import Color class Macchanger(object): - is_init = False is_changed = False - original_mac = None @classmethod - def init(cls): - if cls.is_init: return - from ..config import Configuration - iface = Configuration.interface - if type(iface) == Interface: - iface = iface.interface - cls.original_mac = Ifconfig.get_mac(iface) - cls.is_init = True - - @classmethod - def down_macch_up(cls, macch_option): - cls.init() - + def down_macch_up(cls, iface, options): + '''Put interface down, run macchanger with options, put interface up''' from ..util.process import Process - from ..config import Configuration - iface = Configuration.interface Color.clear_entire_line() - Color.p("\r{+} {C}macchanger{W}: Taking interface {C}%s{W} down..." % iface) + Color.p('\r{+} {C}macchanger{W}: taking interface {C}%s{W} down...' % iface) - if Ifconfig.down(iface) != 0: - Color.pl("{!} {C}macchanger{W}: Error running %s" % " ".join(cmd)) - Color.pl("{!} Output: %s, %s" % (ifdown.stdout(), ifdown.stderr())) - return False + Ifconfig.down(iface) - cmd = ["macchanger", macch_option, iface] Color.clear_entire_line() - Color.p("\r{+} {C}macchanger{W}: Changing MAC address of interface {C}%s{W}..." % iface) - macch = Process(cmd) + Color.p('\r{+} {C}macchanger{W}: changing mac address of interface {C}%s{W}...' % iface) + + command = ['macchanger'] + command.extend(options) + command.append(iface) + macch = Process(command) macch.wait() if macch.poll() != 0: - Color.pl("{!} {C}macchanger{W}: Error running %s" % " ".join(cmd)) - Color.pl("{!} Output: %s, %s" % (macch.stdout(), macch.stderr())) + Color.pl('\n{!} {R}macchanger{O}: error running {R}%s{O}' % ' '.join(command)) + Color.pl('{!} {R}output: {O}%s, %s{W}' % (macch.stdout(), macch.stderr())) return False Color.clear_entire_line() - Color.p("\r{+} {C}macchanger{W}: Bringing interface {C}%s{W} up..." % iface) + Color.p('\r{+} {C}macchanger{W}: bringing interface {C}%s{W} up...' % iface) + + Ifconfig.up(iface) - if Ifconfig.up(iface) != 0: - Color.pl("{!} {C}macchanger{W}: Error running %s" % " ".join(cmd)) - Color.pl("{!} Output: %s, %s" % (ifup.stdout(), ifup.stderr())) - return False return True + + @classmethod + def get_interface(cls): + # Helper method to get interface from configuration + from ..config import Configuration + return Configuration.interface + + @classmethod def reset(cls): - # --permanent to reset to permanent MAC address - if not cls.down_macch_up("-p"): return - Color.pl("\r{+} {C}macchanger{W}: Resetting MAC address...") - from ..config import Configuration - new_mac = Ifconfig.get_mac(Configuration.interface) - Color.clear_entire_line() - Color.pl("\r{+} {C}macchanger{W}: Reset MAC address back to {C}%s{W}" % new_mac) + iface = cls.get_interface() + Color.pl('\r{+} {C}macchanger{W}: resetting mac address on %s...' % iface) + # -p to reset to permanent MAC address + if cls.down_macch_up(iface, ['-p']): + new_mac = Ifconfig.get_mac(iface) + + Color.clear_entire_line() + Color.pl('\r{+} {C}macchanger{W}: reset mac address back to {C}%s{W} on {C}%s{W}' % (new_mac, iface)) + @classmethod def random(cls): - # Use --permanent to use random MAC address - if not cls.down_macch_up("-r"): return - cls.is_changed = True - from ..config import Configuration - new_mac = Ifconfig.get_mac(Configuration.interface) - Color.clear_entire_line() - Color.pl("\r{+} {C}macchanger{W}: Changed MAC address to {C}%s{W}" % new_mac) + from ..util.process import Process + if not Process.exists('macchanger'): + Color.pl('{!} {R}macchanger: {O}not installed') + return + + iface = cls.get_interface() + Color.pl('\n{+} {C}macchanger{W}: changing mac address on {C}%s{W}' % iface) + + # -r to use random MAC address + # -e to keep vendor bytes the same + if cls.down_macch_up(iface, ['-e']): + cls.is_changed = True + new_mac = Ifconfig.get_mac(iface) + + Color.clear_entire_line() + Color.pl('\r{+} {C}macchanger{W}: changed mac address to {C}%s{W} on {C}%s{W}' % (new_mac, iface)) + @classmethod def reset_if_changed(cls): - if not cls.is_changed: return - cls.reset() + if cls.is_changed: + cls.reset() + diff --git a/wifite/util/color.py b/wifite/util/color.py index 747813d..3fa8090 100755 --- a/wifite/util/color.py +++ b/wifite/util/color.py @@ -31,9 +31,9 @@ class Color(object): @staticmethod def p(text): ''' - Prints text using colored format on same line. - Example: - Color.p("{R}This text is red. {W} This text is white") + Prints text using colored format on same line. + Example: + Color.p("{R}This text is red. {W} This text is white") ''' sys.stdout.write(Color.s(text)) sys.stdout.flush() @@ -45,17 +45,13 @@ class Color(object): @staticmethod def pl(text): - ''' - Prints text using colored format with trailing new line. - ''' + '''Prints text using colored format with trailing new line.''' Color.p('%s\n' % text) Color.last_sameline_length = 0 @staticmethod def pe(text): - ''' - Prints text using colored format with leading and trailing new line to STDERR. - ''' + '''Prints text using colored format with leading and trailing new line to STDERR.''' sys.stderr.write(Color.s('%s\n' % text)) Color.last_sameline_length = 0 @@ -85,14 +81,14 @@ class Color(object): @staticmethod def pattack(attack_type, target, attack_name, progress): ''' - Prints a one-liner for an attack - Includes attack type (WEP/WPA), target BSSID/ESSID & power, attack type, and progress - [name] ESSID (MAC @ Pwr) Attack_Type: Progress - e.g.: [WEP] Router2G (00:11:22 @ 23db) replay attack: 102 IVs + Prints a one-liner for an attack. + Includes attack type (WEP/WPA), target ESSID & power, attack type, and progress. + ESSID (Pwr) Attack_Type: Progress + e.g.: Router2G (23db) WEP replay attack: 102 IVs ''' essid = "{C}%s{W}" % target.essid if target.essid_known else "{O}unknown{W}" - Color.p("\r{+} {G}%s{W} ({C}%s @ %sdb{W}) {G}%s {C}%s{W}: %s " % ( - essid, target.bssid, target.power, attack_type, attack_name, progress)) + Color.p("\r{+} {G}%s{W} ({C}%sdb{W}) {G}%s {C}%s{W}: %s " % ( + essid, target.power, attack_type, attack_name, progress)) if __name__ == '__main__': Color.pl("{R}Testing{G}One{C}Two{P}Three{W}Done")