Code cleanup

This commit is contained in:
derv82
2018-04-18 14:42:24 -04:00
parent 8f32972546
commit 2b40ce3706
9 changed files with 333 additions and 279 deletions

View File

@@ -67,7 +67,7 @@ class Arguments(object):
glob.add_argument('--channel', help=argparse.SUPPRESS, action='store', dest='channel', type=int) glob.add_argument('--channel', help=argparse.SUPPRESS, action='store', dest='channel', type=int)
glob.add_argument('-mac', glob.add_argument('-mac',
'---random-mac', '--random-mac',
action='store_true', action='store_true',
dest='random_mac', dest='random_mac',
help=Color.s('Randomize wireless card MAC address (default: {G}off{W})')) help=Color.s('Randomize wireless card MAC address (default: {G}off{W})'))

View File

@@ -1,18 +1,19 @@
#!/usr/bin/python2.7 #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os
from .util.color import Color from .util.color import Color
from .tools.macchanger import Macchanger from .tools.macchanger import Macchanger
import os
class Configuration(object): class Configuration(object):
''' Stores configuration variables and functions for Wifite. ''' ''' Stores configuration variables and functions for Wifite. '''
verbose = 0 version = '2.1.3'
initialized = False # Flag indicating config has been initialized initialized = False # Flag indicating config has been initialized
temp_dir = None # Temporary directory temp_dir = None # Temporary directory
version = '2.1.3' interface = None
verbose = 0
@staticmethod @staticmethod
def initialize(load_interface=True): def initialize(load_interface=True):
@@ -315,15 +316,18 @@ class Configuration(object):
Configuration.delete_temp() Configuration.delete_temp()
Macchanger.reset_if_changed() Macchanger.reset_if_changed()
from .tools.airmon import Airmon from .tools.airmon import Airmon
if hasattr(Configuration, "interface") and Configuration.interface is not None and Airmon.base_interface is not None: 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('{!} 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) #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) # Stop monitor mode
Airmon.stop(Configuration.interface)
# Bring original interface back up
Airmon.put_interface_up(Airmon.base_interface)
if Airmon.killed_network_manager: if Airmon.killed_network_manager:
Color.pl('{!} You can restart NetworkManager when finished ({C}service network-manager start{W})') #Color.pl('{!} You can restart NetworkManager when finished ({C}service network-manager start{W})')
#Airmon.start_network_manager() Airmon.start_network_manager()
exit(code) exit(code)

View File

@@ -4,9 +4,7 @@
import time import time
class Attack(object): class Attack(object):
''' '''Contains functionality common to all attacks.'''
Contains functionality common to all attacks
'''
target_wait = 20 target_wait = 20
@@ -17,17 +15,13 @@ class Attack(object):
raise Exception("Unimplemented method: run") raise Exception("Unimplemented method: run")
def wait_for_target(self, airodump): def wait_for_target(self, airodump):
''' '''Waits for target to appear in airodump.'''
Waits for target to appear in airodump
'''
start_time = time.time() start_time = time.time()
targets = airodump.get_targets(apply_filter=False) targets = airodump.get_targets(apply_filter=False)
while len(targets) == 0: while len(targets) == 0:
# Wait for target to appear in airodump. # Wait for target to appear in airodump.
if int(time.time() - start_time) > Attack.target_wait: if int(time.time() - start_time) > Attack.target_wait:
raise Exception( raise Exception('Target did not appear after %d seconds, stopping' % Attack.target_wait)
"Target did not appear after %d seconds, stopping"
% Attack.target_wait)
time.sleep(1) time.sleep(1)
targets = airodump.get_targets() targets = airodump.get_targets()
continue continue

View File

@@ -13,11 +13,49 @@ import re
import os import os
import signal 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): class Airmon(object):
''' Wrapper around the 'airmon-ng' program ''' ''' Wrapper around the 'airmon-ng' program '''
base_interface = None base_interface = None
killed_network_manager = False killed_network_manager = False
# Drivers that need to be manually put into monitor mode
BAD_DRIVERS = ['rtl8821au']
#see if_arp.h #see if_arp.h
ARPHRD_ETHER = 1 #managed ARPHRD_ETHER = 1 #managed
ARPHRD_IEEE80211_RADIOTAP = 803 #monitor ARPHRD_IEEE80211_RADIOTAP = 803 #monitor
@@ -31,7 +69,7 @@ class Airmon(object):
def print_menu(self): def print_menu(self):
''' Prints menu ''' ''' Prints menu '''
print(Interface.menu_header()) print(AirmonIface.menu_header())
for idx, iface in enumerate(self.interfaces, start=1): for idx, iface in enumerate(self.interfaces, start=1):
Color.pl(" {G}%d{W}. %s" % (idx, iface)) Color.pl(" {G}%d{W}. %s" % (idx, iface))
@@ -44,44 +82,57 @@ class Airmon(object):
@staticmethod @staticmethod
def get_interfaces(): def get_interfaces():
''' '''Returns List of AirmonIface objects known by airmon-ng'''
Returns:
List of Interface objects known by airmon-ng
'''
interfaces = [] interfaces = []
p = Process('airmon-ng') p = Process('airmon-ng')
for line in p.stdout().split('\n'): for line in p.stdout().split('\n'):
# Ignore blank/header lines # [PHY ]IFACE DRIVER CHIPSET
if len(line) == 0 or line.startswith('Interface') or line.startswith('PHY'): airmon_re = re.compile(r'^(?:([^\t]*)\t+)?([^\t]*)\t+([^\t]*)\t+([^\t]*)$')
matches = airmon_re.match(line)
if not matches:
continue continue
# Strip out interface information phy, interface, driver, chipset = matches.groups()
fields = line.split("\t") if phy == 'PHY' or phy == 'Interface':
while '' in fields: continue # Header
fields.remove('')
# Add Interface object to list interfaces.append(AirmonIface(phy, interface, driver, chipset))
interfaces.append(Interface(fields))
return interfaces return interfaces
@staticmethod @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) Ifconfig.down(iface)
Iwconfig.mode(iface, 'monitor') Iwconfig.mode(iface, 'monitor')
Ifconfig.up(iface) Ifconfig.up(iface)
with open("/sys/class/net/" + iface + "/type", "r") as f: # /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): if (int(f.read()) == Airmon.ARPHRD_IEEE80211_RADIOTAP):
return iface return iface
return None return None
@staticmethod @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) Ifconfig.down(iface)
Iwconfig.mode(iface, 'managed') Iwconfig.mode(iface, 'managed')
Ifconfig.up(iface) Ifconfig.up(iface)
with open("/sys/class/net/" + iface + "/type", "r") as f: # /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): if (int(f.read()) == Airmon.ARPHRD_ETHER):
return iface return iface
@@ -93,7 +144,7 @@ class Airmon(object):
Starts an interface (iface) in monitor mode Starts an interface (iface) in monitor mode
Args: Args:
iface - The interface to start in monitor mode 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). or the name of the interface (string).
Returns: Returns:
Name of the interface put into monitor mode. Name of the interface put into monitor mode.
@@ -101,95 +152,100 @@ class Airmon(object):
Exception - If an interface can't be put into monitor mode Exception - If an interface can't be put into monitor mode
''' '''
# Get interface name from input # Get interface name from input
if type(iface) == Interface: if type(iface) == AirmonIface:
iface = iface.interface iface_name = iface.interface
Airmon.base_interface = iface driver = iface.driver
else:
iface_name = iface
driver = None
# Call airmon-ng # Remember this as the "base" interface.
Color.p("{+} enabling {G}monitor mode{W} on {C}%s{W}... " % iface) Airmon.base_interface = iface_name
(out,err) = Process.call('airmon-ng start %s' % iface)
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_output = Process(['airmon-ng', 'start', iface_name]).stdout()
# Airmon did not enable monitor mode on an interface
mon_iface = Airmon.start_baddriver(iface)
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}") 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 # Assert that there is an interface in monitor mode
if len(mon_ifaces) == 0: if len(monitor_interfaces) == 0:
Color.pl("{R}failed{W}") 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 # 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}") 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. # No errors found; the device 'enabled_iface' was put into Mode:Monitor.
Color.pl("{G}enabled {C}%s{W}" % mon_iface) Color.pl("{G}enabled {C}%s{W}" % enabled_iface)
Configuration.interface = mon_iface return enabled_iface
return mon_iface
@staticmethod @staticmethod
def _parse_airmon_start(stdout): def _parse_airmon_start(airmon_output):
# Find the interface put into monitor mode (if any) '''Find the interface put into monitor mode (if any)'''
mon_iface = None
for line in stdout.split('\n'): # airmon-ng output: (mac80211 monitor mode vif enabled for [phy10]wlan0 on [phy10]wlan0mon)
if 'monitor mode' in line and 'enabled' in line and ' on ' in line: enabled_re = re.compile(r'\s*\(mac80211 monitor mode (?:vif )?enabled for [^ ]+ on (?:\[\w+\])?(\w+)\)\s*')
mon_iface = line.split(' on ')[1]
if ']' in mon_iface: for line in airmon_output.split('\n'):
mon_iface = mon_iface.split(']')[1] matches = enabled_re.match(line)
if ')' in mon_iface: if matches:
mon_iface = mon_iface.split(')')[0] return matches.group(1)
break
return mon_iface return None
@staticmethod @staticmethod
def stop(iface): def stop(iface):
Color.p("{!} {R}disabling {O}monitor mode{O} on {R}%s{O}... " % 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 airmon_output = Process(['airmon-ng', 'stop', iface]).stdout()
match = re.search('([a-zA-Z0-9]+).*\(removed\)', line)
if match:
mon_iface = match.groups()[0]
break
if not mon_iface: disabled_iface = Airmon._parse_airmon_stop(airmon_output)
mon_iface = Airmon.stop_baddriver(iface)
if mon_iface: if not disabled_iface and iface in Airmon.BAD_DRIVERS:
Color.pl('{R}disabled %s{W}' % mon_iface) 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: else:
Color.pl('{O}could not disable on {R}%s{W}' % iface) Color.pl('{O}could not disable on {R}%s{W}' % iface)
@staticmethod @staticmethod
def get_interfaces_in_monitor_mode(): def _parse_airmon_stop(airmon_output):
''' '''Find the interface taken out of into monitor mode (if any)'''
Uses 'iwconfig' to find all interfaces in monitor mode
Returns: # airmon-ng 1.2rc2 output: (mac80211 monitor mode vif enabled for [phy10]wlan0 on [phy10]wlan0mon)
List of interface names that are in monitor mode disabled_re = re.compile(r'\s*\(mac80211 monitor mode (?:vif )?disabled for (?:\[\w+\])?(\w+)\)\s*')
'''
return Iwconfig.get_interfaces(mode='Monitor') # 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 @staticmethod
@@ -198,20 +254,19 @@ class Airmon(object):
Asks user to define which wireless interface to use. Asks user to define which wireless interface to use.
Does not ask if: Does not ask if:
1. There is already an interface in monitor mode, or 1. There is already an interface in monitor mode, or
2. There is only one wireles interface (automatically selected). 2. There is only one wireless interface (automatically selected).
Puts selected device into Monitor Mode. Puts selected device into Monitor Mode.
''' '''
Airmon.terminate_conflicting_processes() Airmon.terminate_conflicting_processes()
Color.pl('\n{+} looking for {C}wireless interfaces{W}') Color.pl('\n{+} looking for {C}wireless interfaces{W}')
mon_ifaces = Airmon.get_interfaces_in_monitor_mode() monitor_interfaces = Iwconfig.get_interfaces(mode='Monitor')
mon_count = len(mon_ifaces) if len(monitor_interfaces) == 1:
if mon_count == 1:
# Assume we're using the device already in montior mode # Assume we're using the device already in montior mode
iface = mon_ifaces[0] iface = monitor_interfaces[0]
Color.pl('{+} using interface {G}%s{W} which is already in monitor mode' Color.pl(' using interface {G}%s{W} (already in monitor mode)' % iface);
% iface); Color.pl(' you can specify the wireless interface using {C}-i wlan0{W}')
Airmon.base_interface = None Airmon.base_interface = None
return iface return iface
@@ -240,7 +295,7 @@ class Airmon(object):
iface = a.get(choice) 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) Color.pl('{+} {G}%s{W} is already in monitor mode' % iface.interface)
else: else:
iface.interface = Airmon.start(iface) iface.interface = Airmon.start(iface)
@@ -251,52 +306,48 @@ class Airmon(object):
def terminate_conflicting_processes(): def terminate_conflicting_processes():
''' Deletes conflicting processes reported by airmon-ng ''' ''' Deletes conflicting processes reported by airmon-ng '''
''' airmon_output = Process(['airmon-ng', 'check']).stdout()
% airmon-ng check
Found 3 processes that could cause trouble. # Conflicting process IDs and names
If airodump-ng, aireplay-ng or airtun-ng stops working after pid_pnames = []
a short period of time, you may want to kill (some of) them!
-e
PID Name
2272 dhclient
2293 NetworkManager
3302 wpa_supplicant
'''
out = Process(['airmon-ng', 'check']).stdout() # 2272 dhclient
if 'processes that could cause trouble' not in out: # 2293 NetworkManager
# No proceses to kill 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 return
hit_pids = False if not Configuration.kill_conflicting_processes:
for line in out.split('\n'): # Don't kill processes, warn user
if re.search('^ *PID', line): for pid, pname in pid_pnames:
hit_pids = True Color.pl('{!} {O}conflicting process: {R}%s{O} (PID {R}%s{O})' % (pname, pid))
continue Color.pl('{!} {O}if you have problems: {R}kill -9 PID{O} or re-run wifite with {R}--kill{O}){W}')
if not hit_pids or line.strip() == '': return
continue
match = re.search('^[ \t]*(\d+)[ \t]*([a-zA-Z0-9_\-]+)[ \t]*$', line) Color.pl('{!} {O}killing {R}%d {O}conflicting processes' % len(pid_pnames))
if match: for pid, pname in pid_pnames:
# Found process if pname == 'NetworkManager' and Process.exists('service'):
pid = match.groups()[0] Color.pl('{!} {O}stopping network-manager ({R}service network-manager stop{O})')
pname = match.groups()[1] # Can't just pkill network manager; it's a service
if Configuration.kill_conflicting_processes: 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)) Color.pl('{!} {R}terminating {O}conflicting process {R}%s{O} (PID {R}%s{O})' % (pname, pid))
os.kill(int(pid), signal.SIGTERM) 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}')
@staticmethod @staticmethod
def put_interface_up(iface): def put_interface_up(iface):
Color.p("{!} {O}putting interface {R}%s up{O}..." % (iface)) Color.p("{!} {O}putting interface {R}%s up{O}..." % (iface))
Ifconfig.up(iface) Ifconfig.up(iface)
Color.pl(" {R}done{W}") Color.pl(" {G}done{W}")
@staticmethod @staticmethod
def start_network_manager(): def start_network_manager():

View File

@@ -16,9 +16,7 @@ class Airodump(object):
def __init__(self, interface=None, channel=None, encryption=None,\ def __init__(self, interface=None, channel=None, encryption=None,\
wps=False, target_bssid=None, output_file_prefix='airodump',\ wps=False, target_bssid=None, output_file_prefix='airodump',\
ivs_only=False, skip_wps=False): 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() Configuration.initialize()
@@ -67,22 +65,15 @@ class Airodump(object):
'-w', self.csv_file_prefix, # Output file prefix '-w', self.csv_file_prefix, # Output file prefix
'--write-interval', '1' # Write every second '--write-interval', '1' # Write every second
] ]
if self.channel: if self.channel: command.extend(['-c', str(self.channel)])
command.extend(['-c', str(self.channel)]) elif self.five_ghz: command.extend(['--band', 'a'])
elif self.five_ghz:
command.extend(['--band', 'a'])
if self.encryption: if self.encryption: command.extend(['--enc', self.encryption])
command.extend(['--enc', self.encryption]) if self.wps: command.extend(['--wps'])
if self.wps: if self.target_bssid: command.extend(['--bssid', self.target_bssid])
command.extend(['--wps'])
if self.target_bssid:
command.extend(['--bssid', self.target_bssid])
if self.ivs_only: if self.ivs_only: command.extend(['--output-format', 'ivs,csv'])
command.extend(['--output-format', 'ivs,csv']) else: command.extend(['--output-format', 'pcap,csv'])
else:
command.extend(['--output-format', 'pcap,csv'])
# Start the process # Start the process
self.pid = Process(command, devnull=True) self.pid = Process(command, devnull=True)
@@ -104,10 +95,14 @@ class Airodump(object):
def find_files(self, endswith=None): def find_files(self, endswith=None):
''' Finds all files in the temp directory that start with the output_file_prefix ''' ''' Finds all files in the temp directory that start with the output_file_prefix '''
result = [] result = []
for fil in os.listdir(Configuration.temp()): temp = Configuration.temp()
if fil.startswith(self.output_file_prefix): for fil in os.listdir(temp):
if not fil.startswith(self.output_file_prefix):
continue
if not endswith or fil.endswith(endswith): if not endswith or fil.endswith(endswith):
result.append(Configuration.temp() + fil) result.append(os.path.join(temp, fil))
return result return result
def delete_airodump_temp_files(self): def delete_airodump_temp_files(self):
@@ -130,14 +125,12 @@ class Airodump(object):
# Find the .CSV file # Find the .CSV file
csv_filename = None csv_filename = None
for fil in self.find_files(endswith='-01.csv'): for fil in self.find_files(endswith='-01.csv'):
# Found the file csv_filename = fil # Found the file
csv_filename = fil
break 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) targets = Airodump.get_targets_from_csv(csv_filename)
# Check targets for WPS # Check targets for WPS
@@ -156,9 +149,12 @@ class Airodump(object):
# Sort by power # Sort by power
targets.sort(key=lambda x: x.power, reverse=True) targets.sort(key=lambda x: x.power, reverse=True)
# Identify decloaked targets
for old_target in self.targets: for old_target in self.targets:
for new_target in 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: if new_target.essid_known and not old_target.essid_known:
# We decloaked a target! # We decloaked a target!
new_target.decloaked = True new_target.decloaked = True
@@ -175,9 +171,7 @@ class Airodump(object):
@staticmethod @staticmethod
def get_targets_from_csv(csv_filename): 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 = [] targets = []
import csv import csv
with open(csv_filename, 'rb') as csvopen: with open(csv_filename, 'rb') as csvopen:
@@ -275,11 +269,11 @@ class Airodump(object):
''' '''
self.decloaking = False self.decloaking = False
# Do not deauth if requested if Configuration.no_deauth:
if Configuration.no_deauth: return return # Do not deauth if requested
# Do not deauth if channel is not fixed. if self.channel is None:
if self.channel is None: return return # Do not deauth if channel is not fixed.
# Reusable deauth command # Reusable deauth command
deauth_cmd = [ deauth_cmd = [
@@ -288,22 +282,27 @@ class Airodump(object):
str(Configuration.num_deauths), # Number of deauth packets to send str(Configuration.num_deauths), # Number of deauth packets to send
'--ignore-negative-one' '--ignore-negative-one'
] ]
for target in self.targets: for target in self.targets:
if target.essid_known: continue if target.essid_known:
continue
now = int(time.time()) now = int(time.time())
secs_since_decloak = now - self.decloaked_times.get(target.bssid, 0) 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.decloaking = True
self.decloaked_times[target.bssid] = now self.decloaked_times[target.bssid] = now
if Configuration.verbose > 1: if Configuration.verbose > 1:
from ..util.color import Color from ..util.color import Color
verbout = " [?] Deauthing %s" % target.bssid Color.pe('{C} [?] Deauthing %s (broadcast & %d clients){W}' % (target.bssid, len(target.clients)))
verbout += " (broadcast & %d clients)" % len(target.clients)
Color.pe("\n{C}" + verbout + "{W}")
# Deauth broadcast # Deauth broadcast
iface = Configuration.interface iface = Configuration.interface
Process(deauth_cmd + ['-a', target.bssid, iface]) Process(deauth_cmd + ['-a', target.bssid, iface])
# Deauth clients # Deauth clients
for client in target.clients: for client in target.clients:
Process(deauth_cmd + ['-a', target.bssid, '-c', client.bssid, iface]) Process(deauth_cmd + ['-a', target.bssid, '-c', client.bssid, iface])

View File

@@ -18,7 +18,8 @@ class Ifconfig(object):
pid = Process(command) pid = Process(command)
pid.wait() 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 @classmethod
@@ -26,15 +27,10 @@ class Ifconfig(object):
'''Put interface down''' '''Put interface down'''
from ..util.process import Process from ..util.process import Process
command = ['ifconfig', interface, 'down'] pid = Process(['ifconfig', interface, 'down'])
if type(args) is list:
command.extend(args)
elif type(args) is 'str':
command.append(args)
pid = Process(command)
pid.wait() 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 @classmethod
@@ -43,11 +39,17 @@ class Ifconfig(object):
output = Process(['ifconfig', interface]).stdout() output = Process(['ifconfig', interface]).stdout()
mac_regex = ('[a-zA-Z0-9]{2}-' * 6)[:-1] # Mac address separated by dashes
match = re.search(' (%s)' % mac_regex, output) 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('-', ':')
# 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)
if not match:
raise Exception('Could not find the mac address for %s' % interface) raise Exception('Could not find the mac address for %s' % interface)
return match.groups()[0].replace('-', ':')

View File

@@ -4,7 +4,9 @@
class Iwconfig(object): class Iwconfig(object):
@classmethod @classmethod
def exists(cls): def exists(cls):
pass from ..util.process import Process
return Process.exists('iwconfig')
@classmethod @classmethod
def mode(cls, iface, mode_name): def mode(cls, iface, mode_name):
@@ -15,6 +17,7 @@ class Iwconfig(object):
return pid.poll() return pid.poll()
@classmethod @classmethod
def get_interfaces(cls, mode=None): def get_interfaces(cls, mode=None):
from ..util.process import Process from ..util.process import Process
@@ -34,5 +37,6 @@ class Iwconfig(object):
if mode is not None and 'Mode:{}'.format(mode) in line: if mode is not None and 'Mode:{}'.format(mode) in line:
interfaces.add(iface) interfaces.add(iface)
return list(interfaces) return list(interfaces)

View File

@@ -6,76 +6,80 @@ from ..tools.ifconfig import Ifconfig
from ..util.color import Color from ..util.color import Color
class Macchanger(object): class Macchanger(object):
is_init = False
is_changed = False is_changed = False
original_mac = None
@classmethod @classmethod
def init(cls): def down_macch_up(cls, iface, options):
if cls.is_init: return '''Put interface down, run macchanger with options, put interface up'''
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()
from ..util.process import Process from ..util.process import Process
from ..config import Configuration
iface = Configuration.interface
Color.clear_entire_line() 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: Ifconfig.down(iface)
Color.pl("{!} {C}macchanger{W}: Error running %s" % " ".join(cmd))
Color.pl("{!} Output: %s, %s" % (ifdown.stdout(), ifdown.stderr()))
return False
cmd = ["macchanger", macch_option, iface]
Color.clear_entire_line() Color.clear_entire_line()
Color.p("\r{+} {C}macchanger{W}: Changing MAC address of interface {C}%s{W}..." % iface) Color.p('\r{+} {C}macchanger{W}: changing mac address of interface {C}%s{W}...' % iface)
macch = Process(cmd)
command = ['macchanger']
command.extend(options)
command.append(iface)
macch = Process(command)
macch.wait() macch.wait()
if macch.poll() != 0: if macch.poll() != 0:
Color.pl("{!} {C}macchanger{W}: Error running %s" % " ".join(cmd)) Color.pl('\n{!} {R}macchanger{O}: error running {R}%s{O}' % ' '.join(command))
Color.pl("{!} Output: %s, %s" % (macch.stdout(), macch.stderr())) Color.pl('{!} {R}output: {O}%s, %s{W}' % (macch.stdout(), macch.stderr()))
return False return False
Color.clear_entire_line() 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 return True
@classmethod
def get_interface(cls):
# Helper method to get interface from configuration
from ..config import Configuration
return Configuration.interface
@classmethod @classmethod
def reset(cls): def reset(cls):
# --permanent to reset to permanent MAC address iface = cls.get_interface()
if not cls.down_macch_up("-p"): return Color.pl('\r{+} {C}macchanger{W}: resetting mac address on %s...' % iface)
Color.pl("\r{+} {C}macchanger{W}: Resetting MAC address...") # -p to reset to permanent MAC address
from ..config import Configuration if cls.down_macch_up(iface, ['-p']):
new_mac = Ifconfig.get_mac(Configuration.interface) new_mac = Ifconfig.get_mac(iface)
Color.clear_entire_line() Color.clear_entire_line()
Color.pl("\r{+} {C}macchanger{W}: Reset MAC address back to {C}%s{W}" % new_mac) Color.pl('\r{+} {C}macchanger{W}: reset mac address back to {C}%s{W} on {C}%s{W}' % (new_mac, iface))
@classmethod @classmethod
def random(cls): def random(cls):
# Use --permanent to use random MAC address from ..util.process import Process
if not cls.down_macch_up("-r"): return 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 cls.is_changed = True
from ..config import Configuration new_mac = Ifconfig.get_mac(iface)
new_mac = Ifconfig.get_mac(Configuration.interface)
Color.clear_entire_line() Color.clear_entire_line()
Color.pl("\r{+} {C}macchanger{W}: Changed MAC address to {C}%s{W}" % new_mac) Color.pl('\r{+} {C}macchanger{W}: changed mac address to {C}%s{W} on {C}%s{W}' % (new_mac, iface))
@classmethod @classmethod
def reset_if_changed(cls): def reset_if_changed(cls):
if not cls.is_changed: return if cls.is_changed:
cls.reset() cls.reset()

View File

@@ -45,17 +45,13 @@ class Color(object):
@staticmethod @staticmethod
def pl(text): 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.p('%s\n' % text)
Color.last_sameline_length = 0 Color.last_sameline_length = 0
@staticmethod @staticmethod
def pe(text): 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)) sys.stderr.write(Color.s('%s\n' % text))
Color.last_sameline_length = 0 Color.last_sameline_length = 0
@@ -85,14 +81,14 @@ class Color(object):
@staticmethod @staticmethod
def pattack(attack_type, target, attack_name, progress): def pattack(attack_type, target, attack_name, progress):
''' '''
Prints a one-liner for an attack Prints a one-liner for an attack.
Includes attack type (WEP/WPA), target BSSID/ESSID & power, attack type, and progress Includes attack type (WEP/WPA), target ESSID & power, attack type, and progress.
[name] ESSID (MAC @ Pwr) Attack_Type: Progress ESSID (Pwr) Attack_Type: Progress
e.g.: [WEP] Router2G (00:11:22 @ 23db) replay attack: 102 IVs e.g.: Router2G (23db) WEP replay attack: 102 IVs
''' '''
essid = "{C}%s{W}" % target.essid if target.essid_known else "{O}unknown{W}" 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 " % ( Color.p("\r{+} {G}%s{W} ({C}%sdb{W}) {G}%s {C}%s{W}: %s " % (
essid, target.bssid, target.power, attack_type, attack_name, progress)) essid, target.power, attack_type, attack_name, progress))
if __name__ == '__main__': if __name__ == '__main__':
Color.pl("{R}Testing{G}One{C}Two{P}Three{W}Done") Color.pl("{R}Testing{G}One{C}Two{P}Three{W}Done")