diff --git a/README.md b/README.md index ddb273e..5a07a66 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Support ------- Wifite2 is designed entirely for the latest version of Kali Rolling release (tested on Kali 2016.2, updated May 2017). -This means only the latest versions of these programs are supported: Aircrack-ng suite, wash, reaver, tshark, cowpatty. +This means only the latest versions of these programs are supported: Aircrack-ng suite, reaver, tshark, cowpatty. Other pen-testing distributions (such as BackBox) have outdated versions of these suites; these distributions are not supported. diff --git a/TODO.md b/TODO.md index d4f828a..884d901 100644 --- a/TODO.md +++ b/TODO.md @@ -57,6 +57,22 @@ TSHARK * DIY: Extract Beacon frames from the .cap file with WPS flags... * `tshark -r f.cap -R "wps.primary_device_type.category == 6" -n -2` +We can extract WPS networks' BSSID and WPS lock status: + +```bash +% tshark -r withwps-01.cap -n -Y "wps.wifi_protected_setup_state && wlan.da == ff:ff:ff:ff:ff:ff" -T fields -e wlan.ta -e wps.ap_setup_locked -E separator=, +# Output: +88:ad:43:d2:77:c8, +18:d6:c7:6d:6b:18, +f4:f2:6d:9e:34:25, +fc:51:a4:1e:11:67, +98:e7:f4:90:f1:12,0x00000001 +10:13:31:30:35:2c, +60:a4:4c:6a:46:b0, +c0:7c:d1:6f:a2:c8, +f8:cf:c5:fb:a3:e2, +``` + ------------------------------------------------------ ### Backwards Compatibility diff --git a/py/Airodump.py b/py/Airodump.py index c8814e7..6de6f54 100644 --- a/py/Airodump.py +++ b/py/Airodump.py @@ -5,7 +5,7 @@ from Process import Process from Configuration import Configuration from Target import Target from Client import Client -from Wash import Wash +from Tshark import Tshark import os, time @@ -14,7 +14,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_wash=False): + ivs_only=False, skip_wps=False): ''' Sets up airodump arguments, doesn't start process yet ''' @@ -40,7 +40,7 @@ class Airodump(object): self.target_bssid = target_bssid self.output_file_prefix = output_file_prefix self.ivs_only = ivs_only - self.skip_wash = skip_wash + self.skip_wps = skip_wps # For tracking decloaked APs (previously were hidden) self.decloaking = False @@ -139,13 +139,13 @@ class Airodump(object): targets = Airodump.get_targets_from_csv(csv_filename) # Check targets for WPS - if not self.skip_wash: + if not self.skip_wps: capfile = csv_filename[:-3] + 'cap' - Wash.check_for_wps_and_update_targets(capfile, targets) + Tshark.check_for_wps_and_update_targets(capfile, targets) if apply_filter: # Filter targets based on encryption & WPS capability - targets = Airodump.filter_targets(targets, skip_wash=self.skip_wash) + targets = Airodump.filter_targets(targets, skip_wps=self.skip_wps) # Sort by power targets.sort(key=lambda x: x.power, reverse=True) @@ -218,7 +218,7 @@ class Airodump(object): return targets @staticmethod - def filter_targets(targets, skip_wash=False): + def filter_targets(targets, skip_wps=False): ''' Filters targets based on Configuration ''' result = [] # Filter based on Encryption @@ -229,7 +229,7 @@ class Airodump(object): result.append(target) elif 'WPS' in Configuration.encryption_filter and target.wps: result.append(target) - elif skip_wash: + elif skip_wps: result.append(target) # Filter based on BSSID/ESSID diff --git a/py/AttackWEP.py b/py/AttackWEP.py index c3bc48f..d6d77af 100644 --- a/py/AttackWEP.py +++ b/py/AttackWEP.py @@ -44,7 +44,7 @@ class AttackWEP(Attack): with Airodump(channel=self.target.channel, target_bssid=self.target.bssid, ivs_only=True, # Only capture IVs packets - skip_wash=True, # Don't check for WPS-compatibility + skip_wps=True, # Don't check for WPS-compatibility output_file_prefix='wep') as airodump: Color.clear_line() diff --git a/py/AttackWPA.py b/py/AttackWPA.py index 114b64d..9da7350 100644 --- a/py/AttackWPA.py +++ b/py/AttackWPA.py @@ -37,7 +37,7 @@ class AttackWPA(Attack): # First, start Airodump process with Airodump(channel=self.target.channel, target_bssid=self.target.bssid, - skip_wash=True, + skip_wps=True, output_file_prefix='wpa') as airodump: Color.clear_entire_line() diff --git a/py/Bully.py b/py/Bully.py index c860b7e..8940174 100644 --- a/py/Bully.py +++ b/py/Bully.py @@ -50,7 +50,7 @@ class Bully(Attack): def run(self): with Airodump(channel=self.target.channel, target_bssid=self.target.bssid, - skip_wash=True, + skip_wps=True, output_file_prefix='wps_pin') as airodump: # Wait for target Color.clear_entire_line() diff --git a/py/Client.py b/py/Client.py index 51a6918..2ae4b5c 100644 --- a/py/Client.py +++ b/py/Client.py @@ -21,10 +21,15 @@ class Client(object): 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() + try: + self.station = fields[0].strip() + self.power = int(fields[3].strip()) + self.packets = int(fields[4].strip()) + self.bssid = fields[5].strip() + except ValueError, e: + print "\nValueError ({})".format(e) + print "\twhile parsing {}".format(fields) + raise e def __str__(self): diff --git a/py/Reaver.py b/py/Reaver.py index f73f560..329647c 100644 --- a/py/Reaver.py +++ b/py/Reaver.py @@ -73,7 +73,7 @@ class Reaver(Attack): with Airodump(channel=self.target.channel, target_bssid=self.target.bssid, - skip_wash=True, + skip_wps=True, output_file_prefix='pixie') as airodump: Color.clear_line() @@ -210,7 +210,7 @@ class Reaver(Attack): with Airodump(channel=self.target.channel, target_bssid=self.target.bssid, - skip_wash=True, + skip_wps=True, output_file_prefix='wps') as airodump: Color.clear_line() diff --git a/py/Tshark.py b/py/Tshark.py new file mode 100644 index 0000000..9713f04 --- /dev/null +++ b/py/Tshark.py @@ -0,0 +1,83 @@ +#!/usr/bin/python2.7 +# -*- coding: utf-8 -*- + +from Process import Process +import re + +class Tshark(object): + ''' Wrapper for Tshark program. ''' + + def __init__(self): + pass + + @staticmethod + def check_for_wps_and_update_targets(capfile, targets): + ''' + Given a cap file and list of targets, use TShark to + find which BSSIDs in the cap file use WPS. + Then update the 'wps' flag for those BSSIDs in the targets. + + Args: + capfile - .cap file from airodump containing packets + targets - list of Targets from scan, to be updated + ''' + # Tshark is required to detect WPS networks + if not Process.exists('tshark'): + return + + command = [ + 'tshark', + '-r', capfile, # Path to cap file + '-n', # Don't resolve addresses + # Filter WPS broadcast packets + '-Y', 'wps.wifi_protected_setup_state && wlan.da == ff:ff:ff:ff:ff:ff', + '-T', 'fields', # Only output certain fields + '-e', 'wlan.ta', # BSSID + '-e', 'wps.ap_setup_locked', # Locked status + '-E', 'separator=,' # CSV + ] + p = Process(command) + + + try: + p.wait() + lines = p.stdout() + except: + # Failure is acceptable + return + + bssids = set() + for line in lines.split('\n'): + if ',' not in line: + continue + bssid, locked = line.split(',') + # TODO: Ignore if WPS is locked? + bssids.add(bssid.upper()) + + for t in targets: + t.wps = t.bssid.upper() in bssids + + +if __name__ == '__main__': + test_file = './tests/files/contains_wps_network.cap' + + target_bssid = 'A4:2B:8C:16:6B:3A' + from Target import Target + fields = [ + 'A4:2B:8C:16:6B:3A', # BSSID + '2015-05-27 19:28:44', '2015-05-27 19:28:46', # Dates + '11', # Channel + '54', # throughput + 'WPA2', 'CCMP TKIP', 'PSK', # AUTH + '-58', '2', '0', '0.0.0.0', '9', # ??? + 'Test Router Please Ignore', # SSID + ] + t = Target(fields) + targets = [t] + + # Should update 'wps' field of a target + Tshark.check_for_wps_and_update_targets(test_file, targets) + + print 'Target(BSSID={}).wps = {} (Expected: True)'.format(targets[0].bssid, targets[0].wps) + assert targets[0].wps == True + diff --git a/py/Wash.py b/py/Wash.py deleted file mode 100644 index 6256d71..0000000 --- a/py/Wash.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/python2.7 -# -*- coding: utf-8 -*- - -from Process import Process -import re - -class Wash(object): - ''' Wrapper for Wash program. ''' - BSSID_REGEX = re.compile("([A-F0-9\:]{17})", re.IGNORECASE) - - def __init__(self): - pass - - @staticmethod - def check_for_wps_and_update_targets(capfile, targets): - ''' - Given a cap file and list of targets, use Wash to - find which BSSIDs in the cap file use WPS. - Then update the 'wps' flag for those BSSIDs in the targets. - - Args: - capfile - .cap file from airodump containing packets - targets - list of Targets from scan, to be updated - ''' - # Wash/Walsh is required to detect WPS - wash_name = 'wash' - if not Process.exists(wash_name): - wash_name = 'walsh' - if not Process.exists(wash_name): - # Wash isn't found, drop out - return - - command = [ - 'wash', - '-f', capfile # Path to cap file - ] - p = Process(command) - - p.wait() - if p.poll() != 0: - return - - bssids = [bssid.upper() for bssid in Wash.BSSID_REGEX.findall(p.stdout())] - for t in targets: - t.wps = t.bssid.upper() in bssids - - -if __name__ == '__main__': - from Target import Target - # Test target within range - fields = 'A4:2B:8C:16:6B:3A,2015-05-27 19:28:44,2015-05-27 19:28:46,11,54,WPA2,CCMP TKIP,PSK,-58,2,0,0.0.0.0,9,Test Router Please Ignore,'.split(',') - t = Target(fields) - targets = [t] - Wash.check_for_wps_and_update_targets('./tests/files/handshake_exists.cap', targets) - print targets[0].bssid, 'WPS =', targets[0].wps - diff --git a/py/tests/files/contains_wps_network.cap b/py/tests/files/contains_wps_network.cap new file mode 100644 index 0000000..b6001fa Binary files /dev/null and b/py/tests/files/contains_wps_network.cap differ