From 1f2ebc991440b08e1dc5871b76922309a0f7f3db Mon Sep 17 00:00:00 2001 From: derv82 Date: Wed, 27 May 2015 20:26:30 -0700 Subject: [PATCH] Setting up Client, Target, and Airodump wrappers Fixed bugs in Process and other related classes. --- py/Airodump.py | 152 ++++++++++++++++++++++++++++++++++++++++++++ py/CapFile.py | 19 ------ py/Client.py | 46 +++++++++++--- py/Configuration.py | 28 ++++---- py/Process.py | 11 +++- py/Target.py | 76 ++++++++++++++++++++++ 6 files changed, 290 insertions(+), 42 deletions(-) create mode 100644 py/Airodump.py delete mode 100644 py/CapFile.py create mode 100644 py/Target.py diff --git a/py/Airodump.py b/py/Airodump.py new file mode 100644 index 0000000..825824e --- /dev/null +++ b/py/Airodump.py @@ -0,0 +1,152 @@ +#!/usr/bin/python + +from Process import Process +from Configuration import Configuration +from Target import Target +from Client import Client + +import os + +class Airodump(object): + ''' Wrapper around airodump-ng program ''' + + def __init__(self, interface, channel=None, encryption=None, wps=False): + ''' Constructor, sets things up ''' + self.targets = [] + self.interface = interface + self.channel = channel + self.encryption = encryption + self.wps = wps + + def __enter__(self): + ''' + Setting things up for this context. + Called at start of 'with Airodump(...) as x:' + ''' + self.delete_airodump_temp_files() + + self.csv_file_prefix = Configuration.temp() + "airodump"; + + # Build the command + command = [ + 'airodump-ng', + self.interface, + '-a', # Only show associated clients + '-w', self.csv_file_prefix # Output file prefix + ] + if self.channel: + command.extend(['-c', str(self.channel)]) + if self.encryption: + command.extend(['--enc', self.encryption]) + if self.wps: + command.extend(['--wps']) + + # Start the process + self.pid = Process(command, devnull=True) + return self + + + def __exit__(self, type, value, traceback): + ''' + Tearing things down since the context is being exited. + Called after 'with Airodump(...)' goes out of scope. + ''' + # Kill the process + self.pid.interrupt() + self.pid.kill() + # Delete temp files + self.delete_airodump_temp_files() + + def delete_airodump_temp_files(self): + ''' Deletes airodump* files in the temp directory ''' + for fil in os.listdir(Configuration.temp()): + if fil.startswith('airodump'): + os.remove(Configuration.temp() + fil) + + def get_targets(self, wpa_wep_only=True): + ''' Parses airodump's CSV file, returns list of Targets ''' + # Find the .CSV file + csv_filename = None + for fil in os.listdir(Configuration.temp()): + if fil.startswith('airodump') and fil.endswith('csv'): + # Found the file + csv_filename = Configuration.temp() + fil + break + if csv_filename == None or not os.path.exists(csv_filename): + # No file found + return self.targets + + targets = [] + + # Parse the .CSV file + import csv + with open(csv_filename, 'rb') as csvopen: + csv_reader = csv.reader(csvopen, delimiter=',') + for row in csv_reader: + # Each "row" is a list of fields for a target/client + + if len(row) == 0: continue + + if row[0].strip() == 'BSSID': + # This is the "header" for the list of Targets + hit_clients = False + continue + + elif row[0].strip() == 'Station MAC': + # This is the "header" for the list of Clients + hit_clients = True + continue + + if hit_clients: + # The current row corresponds to a "Client" (computer) + client = Client(row) + + if 'not associated' in client.bssid: + # Ignore unassociated clients + continue + + # Add this client to the appropriate Target + for t in targets: + if t.bssid == client.bssid: + t.clients.append(client) + break + + else: + # The current row corresponds to a "Target" (router) + target = Target(row) + + if target.essid_len == 0: + # Ignore empty/blank ESSIDs + continue + + if wpa_wep_only and 'WPA' not in target.encryption and 'WEP' not in target.encryption: + # Ignore non-WPA and non-WEP encrypted networks + continue + + if self.encryption and self.encryption not in target.encryption: + # We're looking for a specific type of encryption + continue + + targets.append(target) + + # Sort by power + targets.sort(key=lambda x: x.power, reverse=True) + + self.targets = targets + + return self.targets + + +if __name__ == '__main__': + ''' Example usage. wlan0mon should be in Monitor Mode ''' + with Airodump('wlan0mon', channel=6) as airodump: + from time import sleep + + sleep(7) + + targets = airodump.get_targets() + for t in targets: + print 'Target>', t + + Configuration.delete_temp() + diff --git a/py/CapFile.py b/py/CapFile.py deleted file mode 100644 index 1169cdc..0000000 --- a/py/CapFile.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/python - -class CapFile(object): - """ - Holds data about an access point's .cap file, - including filename, AP's ESSID & BSSID. - """ - def __init__(self, filename, ssid, bssid): - self.filename = filename - self.ssid = ssid - self.bssid = bssid - - def __str__(self): - return self.filename - -if __name__ == '__main__': - c = CapFile("cap-01.cap", "My Router", "AA:BB:CC:DD:EE:FF") - print c - diff --git a/py/Client.py b/py/Client.py index ed748b9..f1e02b8 100644 --- a/py/Client.py +++ b/py/Client.py @@ -1,11 +1,41 @@ +#!/usr/bin/python -class Client: - """ - Holds data for a Client (device connected to Access Point/Router) - """ +class Client(object): + ''' + Holds details for a "Client" - a wireless device (e.g. computer) + that is associated with an Access Point (e.g. router) + ''' - def __init__(self, bssid, station, power): - self.bssid = bssid - self.station = station - self.power = power + def __init__(self, fields): + ''' + Initializes & stores client info based on fields. + Args: + Fields - List of strings + INDEX KEY + 0 Station MAC (client's MAC address) + 1 First time seen, + 2 Last time seen, + 3 Power, + 4 # packets, + 5 BSSID, (Access Point's MAC address) + 6 Probed ESSIDs + ''' + self.station = fields[0].strip() + self.power = int(fields[3].strip()) + self.packets = int(fields[4].strip()) + self.bssid = fields[5].strip() + + def __str__(self): + ''' String representation of a Client ''' + result = '' + for (key,value) in self.__dict__.iteritems(): + result += key + ': ' + str(value) + result += ',' + return result + + +if __name__ == '__main__': + fields = '54:35:30:23:62:8E, 2015-05-27 19:43:47, 2015-05-27 19:43:47, -67, 2, (not associated) ,HOME-1102'.split(',') + c = Client(fields) + print c diff --git a/py/Configuration.py b/py/Configuration.py index 7c4a70e..038e187 100644 --- a/py/Configuration.py +++ b/py/Configuration.py @@ -5,9 +5,10 @@ import os class Configuration(object): ''' Stores configuration variables for Wifite. ''' + temp_dir = None + def __init__(self): ''' Sets up default initial configuration values ''' - self.temp_dir = None # Temporary directory self.version = 2.00 # Program version self.tx_power = 0 # Wifi transmit power (0 is default) @@ -64,13 +65,15 @@ class Configuration(object): if args.wordlist: self.wordlist = args.wordlist - def temp(self): + @staticmethod + def temp(): ''' Creates and/or returns the temporary directory ''' - if self.temp_dir == None: - self.temp_dir = self.create_temp() - return self.temp_dir + if Configuration.temp_dir == None: + Configuration.temp_dir = Configuration.create_temp() + return Configuration.temp_dir - def create_temp(self): + @staticmethod + def create_temp(): ''' Creates and returns a temporary directory ''' from tempfile import mkdtemp tmp = mkdtemp(prefix='wifite') @@ -78,13 +81,14 @@ class Configuration(object): tmp += os.sep return tmp - def delete_temp(self): + @staticmethod + def delete_temp(): ''' Remove temp files and folder ''' - if self.temp_dir == None: return - if os.path.exists(self.temp_dir): - for f in os.listdir(self.temp_dir): - os.remove(self.temp_dir + f) - os.rmdir(self.temp_dir) + if Configuration.temp_dir == None: return + if os.path.exists(Configuration.temp_dir): + for f in os.listdir(Configuration.temp_dir): + os.remove(Configuration.temp_dir + f) + os.rmdir(Configuration.temp_dir) def exit_gracefully(self, code=0): diff --git a/py/Process.py b/py/Process.py index 8b9e1b4..876565d 100644 --- a/py/Process.py +++ b/py/Process.py @@ -34,15 +34,20 @@ class Process(object): return True - def __init__(self, command): + def __init__(self, command, devnull=False): ''' Starts executing command ''' if type(command) == str: # Commands have to be a list command = command.split(' ') - self.command = command self.out = None self.err = None - self.pid = Popen(command, stdout=PIPE, stderr=PIPE) + if devnull: + sout = Process.devnull() + serr = Process.devnull() + else: + sout = PIPE + serr = PIPE + self.pid = Popen(command, stdout=sout, stderr=serr) def stdout(self): ''' Waits for process to finish, returns stdout output ''' diff --git a/py/Target.py b/py/Target.py new file mode 100644 index 0000000..c726467 --- /dev/null +++ b/py/Target.py @@ -0,0 +1,76 @@ +#!/usr/bin/python + +class Target(object): + ''' + Holds details for a "Target" aka Access Point (e.g. router). + ''' + + def __init__(self, fields): + ''' + Initializes & stores target info based on fields. + Args: + Fields - List of strings + INDEX KEY EXAMPLE + 0 BSSID (00:1D:D5:9B:11:00) + 1 First time seen (2015-05-27 19:28:43) + 2 Last time seen (2015-05-27 19:28:46) + 3 channel (6) + 4 Speed (54) + 5 Privacy (WPA2) + 6 Cipher (CCMP TKIP) + 7 Authentication (PSK) + 8 Power (-62) + 9 beacons (2) + 10 # IV (0) + 11 LAN IP (0. 0. 0. 0) + 12 ID-length (9) + 13 ESSID (HOME-ABCD) + 14 Key () + ''' + self.bssid = fields[0].strip() + self.channel = fields[3].strip() + + self.encryption = fields[5].strip() + if 'WPA' in self.encryption: + self.encryption = 'WPA' + elif 'WEP' in self.encryption: + self.encryption = 'WEP' + if len(self.encryption) > 4: + self.encryption = self.encryption[0:4].strip() + + self.power = int(fields[8].strip()) + if self.power < 0: + self.power += 100 + + self.beacons = int(fields[9].strip()) + self.ivs = int(fields[10].strip()) + + self.essid_len = int(fields[12].strip()) + self.essid = fields[13].strip() + if self.essid == '\\x00' * self.essid_len: + # Don't display "\x00..." for hidden ESSIDs + self.essid = '(hidden, length: %s)' % self.essid_len + + self.clients = [] + + + def __str__(self): + ''' String representation of this Target ''' + result = '' + for (key,value) in self.__dict__.iteritems(): + if key == 'clients': continue + result += key + ': ' + str(value) + result += ', ' + for client in self.clients: + result += 'client: %s' % client.station + result += ',' + if result.endswith(', '): + result = result[:-2] + return result + + +if __name__ == '__main__': + fields = '00:AC:E0:71:74:E0, 2015-05-27 19:28:44, 2015-05-27 19:28:46, 1, 54, WPA2, CCMP TKIP,PSK, -58, 2, 0, 0. 0. 0. 0, 9, HOME-74E2, '.split(',') + t = Target(fields) + print t +