10 Commits

Author SHA1 Message Date
Alexandre CHAZAL
cfeaa3f066 Update README.md 2019-04-22 17:18:59 +08:00
104e45637b Migrated from ifconfig to ip 2019-01-27 17:11:56 +01:00
4baf8f5c46 Forgot to push this file. 2019-01-27 12:49:24 +01:00
Alexandre CHAZAL
5badcf2488 Update README.md 2019-01-27 12:43:10 +01:00
ceebb14ea8 Migrated from iwconfig to iw 2019-01-27 12:39:59 +01:00
derv82
e190794149 Use enums to describe target WPS state.
To avoid confusion about wps = True/False/None.
Came about because of #130
2018-09-09 10:39:57 -07:00
WhiteOnBlackCode
355f891d0f Created PMKID argument group (#136)
* Added PMKID argument group
2018-09-09 09:47:54 -07:00
derv82
710dd98b66 Detect when --dict is a directory, show warning and ignore wordlist.
In case people pass in a directory, until we figure out #135
2018-09-03 17:02:27 -07:00
derv82
79b2753929 Small fixes for #133
* Avoid cracking the same PMKID twice when selecting multiple files &
specifying a tool that is not hashcat.

* Mention PMKID hashes can only be cracked using hashcat:
  1. If all files are PMKID, or
  2. If the file is PMKID but a tool other than hashcat was chosen.

* Fix header colors if a warning is printed before the handshake files.
2018-09-03 11:02:34 -07:00
WhiteOnBlackCode
6d492aca44 Do not show handshake files that are in cracked.txt with a key (match on filename) (#133)
Make cracked.txt a configurable variable
* Do not show handshake files that are in cracked.txt with a key (match on filename).
* Don't ask user for a crack-tool when attacking PMKIDs only
* Few minor cleanups

Fixed any_pmkid -> all_pmkid (to decide that we are strictly using hashcat)
* Added a safe-check to make sure we are indeed using hashcat for the PMKID hashes
* Changed the ugly split() to basename()

Making an FR from the TODO
2018-09-03 10:53:59 -07:00
20 changed files with 245 additions and 183 deletions

View File

@@ -1,3 +1,9 @@
Fork note
=========
This fork has made the migration from the deprecated iwconfig and ifconfig to iw and ip.
I also added an option to disable monitor mode on the wifi antenna after wifite quits.
Wifite
======
@@ -29,7 +35,7 @@ Second, only the latest versions of these programs are supported and must be ins
**Required:**
* `python`: Wifite is compatible with both `python2` and `python3`.
* [`iwconfig`](https://wiki.debian.org/iwconfig): For identifying wireless devices already in Monitor Mode.
* [`iw`](https://wireless.wiki.kernel.org/en/users/documentation/iw): For identifying wireless devices already in Monitor Mode.
* [`ifconfig`](https://en.wikipedia.org/wiki/Ifconfig): For starting/stopping wireless devices.
* [`Aircrack-ng`](http://aircrack-ng.org/) suite, includes:
* [`airmon-ng`](https://tools.kali.org/wireless-attacks/airmon-ng): For enumerating and enabling Monitor Mode on wireless devices.

View File

@@ -31,6 +31,7 @@ class Arguments(object):
self._add_wep_args(parser.add_argument_group(Color.s('{C}WEP{W}')))
self._add_wpa_args(parser.add_argument_group(Color.s('{C}WPA{W}')))
self._add_wps_args(parser.add_argument_group(Color.s('{C}WPS{W}')))
self._add_pmkid_args(parser.add_argument_group(Color.s('{C}PMKID{W}')))
self._add_eviltwin_args(parser.add_argument_group(Color.s('{C}EVIL TWIN{W}')))
self._add_command_args(parser.add_argument_group(Color.s('{C}COMMANDS{W}')))
@@ -153,6 +154,11 @@ class Arguments(object):
help=self._verbose('Number of deauth packets to send (default: ' +
'{G}%d{W})' % self.config.num_deauths))
glob.add_argument('--demon',
action='store_true',
dest='demon',
help=Color.s('Puts device back in managed mode after quitting (default: '+
'{G}off{W})'))
def _add_eviltwin_args(self, group):
pass
@@ -292,23 +298,6 @@ class Arguments(object):
wpa.add_argument('-wpa', help=argparse.SUPPRESS, action='store_true',
dest='wpa_filter')
wpa.add_argument('--pmkid',
action='store_true',
dest='use_pmkid_only',
help=Color.s('{O}Only{W} use {C}PMKID capture{W}, avoids other WPS & ' +
'WPA attacks (default: {G}off{W})'))
# Alias
wpa.add_argument('-pmkid', action='store_true', dest='use_pmkid_only',
help=argparse.SUPPRESS)
wpa.add_argument('--pmkid-timeout',
action='store',
dest='pmkid_timeout',
metavar='[sec]',
type=int,
help=self._verbose('Time to wait for PMKID capture ' +
'(default: {G}%d{W} seconds)' % self.config.pmkid_timeout))
wpa.add_argument('--hs-dir',
action='store',
dest='wpa_handshake_dir',
@@ -443,6 +432,22 @@ class Arguments(object):
wps.add_argument('-wpsto', help=argparse.SUPPRESS, action='store',
dest='wps_timeout_threshold', type=int)
def _add_pmkid_args(self, pmkid):
pmkid.add_argument('--pmkid',
action='store_true',
dest='use_pmkid_only',
help=Color.s('{O}Only{W} use {C}PMKID capture{W}, avoids other WPS & ' +
'WPA attacks (default: {G}off{W})'))
# Alias
pmkid.add_argument('-pmkid', help=argparse.SUPPRESS, action='store_true', dest='use_pmkid_only')
pmkid.add_argument('--pmkid-timeout',
action='store',
dest='pmkid_timeout',
metavar='[sec]',
type=int,
help=Color.s('Time to wait for PMKID capture ' +
'(default: {G}%d{W} seconds)' % self.config.pmkid_timeout))
def _add_command_args(self, commands):
commands.add_argument('--cracked',
@@ -470,7 +475,7 @@ class Arguments(object):
if __name__ == '__main__':
from .util.color import Color
from config import Configuration
from .config import Configuration
Configuration.initialize(False)
a = Arguments(Configuration)
args = a.args

View File

@@ -5,7 +5,7 @@ from ..model.attack import Attack
from ..tools.airodump import Airodump
from ..tools.aireplay import Aireplay, WEPAttackType
from ..tools.aircrack import Aircrack
from ..tools.ifconfig import Ifconfig
from ..tools.ip import Ip
from ..config import Configuration
from ..util.color import Color
from ..util.input import raw_input
@@ -67,7 +67,7 @@ class AttackWEP(Attack):
if self.fake_auth():
# We successfully authenticated!
# Use our interface's MAC address for the attacks.
client_mac = Ifconfig.get_mac(Configuration.interface)
client_mac = Ip.get_mac(Configuration.interface)
# Keep us authenticated
fakeauth_proc = Aireplay(self.target, 'fakeauth')
elif len(airodump_target.clients) == 0:
@@ -303,7 +303,7 @@ class AttackWEP(Attack):
Color.p('\r{+} {O}Deauthenticating *broadcast*{W} (all clients)...')
Aireplay.deauth(target.bssid, essid=target.essid)
attacking_mac = Ifconfig.get_mac(Configuration.interface)
attacking_mac = Ip.get_mac(Configuration.interface)
for client in target.clients:
if attacking_mac.lower() == client.station.lower():
continue # Don't deauth ourselves.

View File

@@ -48,6 +48,7 @@ class Configuration(object):
cls.random_mac = False # Should generate a random Mac address at startup.
cls.no_deauth = False # Deauth hidden networks & WPA handshake targets
cls.num_deauths = 1 # Number of deauth packets to send to each target.
cls.demon = False # Don't put back interface back in managed mode
cls.encryption_filter = ['WEP', 'WPA', 'WPS']
@@ -78,10 +79,13 @@ class Configuration(object):
cls.wpa_handshake_dir = 'hs' # Dir to store handshakes
cls.wpa_strip_handshake = False # Strip non-handshake packets
cls.ignore_old_handshakes = False # Always fetch a new handshake
# PMKID variables
cls.use_pmkid_only = False # Only use PMKID Capture+Crack attack
cls.pmkid_timeout = 30 # Time to wait for PMKID capture
# Default dictionary for cracking
cls.cracked_file = 'cracked.txt'
cls.wordlist = None
wordlists = [
'./wordlist-top4800-probable.txt', # Local file (ran from cloned repo)
@@ -140,6 +144,7 @@ class Configuration(object):
cls.parse_wep_args(args)
cls.parse_wpa_args(args)
cls.parse_wps_args(args)
cls.parse_pmkid_args(args)
cls.parse_encryption()
# EvilTwin
@@ -169,6 +174,7 @@ class Configuration(object):
@classmethod
def parse_settings_args(cls, args):
'''Parses basic settings/configurations from arguments.'''
if args.random_mac:
cls.random_mac = True
Color.pl('{+} {C}option:{W} using {G}random mac address{W} ' +
@@ -202,6 +208,10 @@ class Configuration(object):
Color.pl('{+} {C}option:{W} will {R}not{W} {O}deauth{W} clients ' +
'during scans or captures')
if args.demon == True:
cls.demon = True
Color.pl('{+} {C}option:{W} will put interface back to managed mode')
if args.num_deauths and args.num_deauths > 0:
cls.num_deauths = args.num_deauths
Color.pl('{+} {C}option:{W} send {G}%d{W} deauth packets when deauthing' % (
@@ -282,12 +292,15 @@ class Configuration(object):
cls.wpa_filter = args.wpa_filter
if args.wordlist:
if os.path.exists(args.wordlist):
cls.wordlist = args.wordlist
Color.pl('{+} {C}option:{W} using wordlist {G}%s{W} to crack WPA handshakes' % args.wordlist)
else:
if not os.path.exists(args.wordlist):
cls.wordlist = None
Color.pl('{+} {C}option:{O} wordlist {R}%s{O} was not found, wifite will NOT attempt to crack handshakes' % args.wordlist)
elif os.path.isfile(args.wordlist):
cls.wordlist = args.wordlist
Color.pl('{+} {C}option:{W} using wordlist {G}%s{W} to crack WPA handshakes' % args.wordlist)
elif os.path.isdir(args.wordlist):
cls.wordlist = None
Color.pl('{+} {C}option:{O} wordlist {R}%s{O} is a directory, not a file. Wifite will NOT attempt to crack handshakes' % args.wordlist)
if args.wpa_deauth_timeout:
cls.wpa_deauth_timeout = args.wpa_deauth_timeout
@@ -304,14 +317,6 @@ class Configuration(object):
Color.pl('{+} {C}option:{W} will {O}ignore{W} existing handshakes ' +
'(force capture)')
if args.use_pmkid_only:
cls.use_pmkid_only = True
Color.pl('{+} {C}option:{W} will ONLY use {C}PMKID{W} attack on WPA networks')
if args.pmkid_timeout:
cls.pmkid_timeout = args.pmkid_timeout
Color.pl('{+} {C}option:{W} will wait {G}%d{W} seconds during {C}PMKID{W} capture')
if args.wpa_handshake_dir:
cls.wpa_handshake_dir = args.wpa_handshake_dir
Color.pl('{+} {C}option:{W} will store handshakes to ' +
@@ -356,7 +361,7 @@ class Configuration(object):
'(no {O}Pixie-Dust{W}) on targets')
if args.use_bully:
from tools.bully import Bully
from .tools.bully import Bully
if not Bully.exists():
Color.pl('{!} {R}Bully not found. Defaulting to {O}reaver{W}')
cls.use_bully = False
@@ -384,6 +389,16 @@ class Configuration(object):
cls.wps_ignore_lock = True
Color.pl('{+} {C}option:{W} will {O}ignore{W} WPS lock-outs')
@classmethod
def parse_pmkid_args(cls, args):
if args.use_pmkid_only:
cls.use_pmkid_only = True
Color.pl('{+} {C}option:{W} will ONLY use {C}PMKID{W} attack on WPA networks')
if args.pmkid_timeout:
cls.pmkid_timeout = args.pmkid_timeout
Color.pl('{+} {C}option:{W} will wait {G}%d seconds{W} during {C}PMKID{W} capture' % args.pmkid_timeout)
@classmethod
def parse_encryption(cls):
'''Adjusts encryption filter (WEP and/or WPA and/or WPS)'''
@@ -406,9 +421,9 @@ class Configuration(object):
def parse_wep_attacks(cls):
'''Parses and sets WEP-specific args (-chopchop, -fragment, etc)'''
cls.wep_attacks = []
import sys
from sys import argv
seen = set()
for arg in sys.argv:
for arg in argv:
if arg in seen: continue
seen.add(arg)
if arg == '-arpreplay': cls.wep_attacks.append('replay')
@@ -465,14 +480,15 @@ class Configuration(object):
Macchanger.reset_if_changed()
from .tools.airmon import Airmon
if cls.interface is not None and Airmon.base_interface is not None:
if not cls.demon:
Color.pl('{!} {O}Note:{W} Leaving interface in Monitor Mode!')
Color.pl('{!} To disable Monitor Mode when finished: ' +
'{C}airmon-ng stop %s{W}' % cls.interface)
else:
# Stop monitor mode
#Airmon.stop(cls.interface)
Airmon.stop(cls.interface)
# Bring original interface back up
#Airmon.put_interface_up(Airmon.base_interface)
Airmon.put_interface_up(Airmon.base_interface)
if Airmon.killed_network_manager:
Color.pl('{!} You can restart NetworkManager when finished ({C}service network-manager start{W})')

View File

@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
from ..util.color import Color
from ..config import Configuration
import os
import time
@@ -11,7 +12,7 @@ class CrackResult(object):
''' Abstract class containing results from a crack session '''
# File to save cracks to, in PWD
cracked_file = 'cracked.txt'
cracked_file = Configuration.cracked_file
def __init__(self):
self.date = int(time.time())
@@ -55,8 +56,8 @@ class CrackResult(object):
this_dict['date'] = entry.get('date')
if entry == this_dict:
# Skip if we already saved this BSSID+ESSID+TYPE+KEY
Color.pl('{+} {C}%s{O} already exists in {G}cracked.txt{O}, skipping.' % (
self.essid))
Color.pl('{+} {C}%s{O} already exists in {G}%s{O}, skipping.' % (
self.essid, Configuration.cracked_file))
return
saved_results.append(self.to_dict())
@@ -67,7 +68,7 @@ class CrackResult(object):
@classmethod
def display(cls):
''' Show cracked targets from cracked.txt '''
''' Show cracked targets from cracked file '''
name = cls.cracked_file
if not os.path.exists(name):
Color.pl('{!} {O}file {C}%s{O} not found{W}' % name)

View File

@@ -5,6 +5,11 @@ from ..util.color import Color
import re
class WPSState:
NONE, UNLOCKED, LOCKED, UNKNOWN = range(0, 4)
class Target(object):
'''
Holds details for a 'Target' aka Access Point (e.g. router).
@@ -60,8 +65,7 @@ class Target(object):
self.essid = None # '(%s)' % self.bssid
self.essid_known = False
# False=No WPS, None=Locked WPS, True=Unlocked WPS
self.wps = False
self.wps = WPSState.UNKNOWN
self.decloaked = False # If ESSID was hidden but we decloaked it.
@@ -133,13 +137,14 @@ class Target(object):
color = 'R'
power = Color.s('{%s}%s' % (color, power))
wps = Color.s('{O} n/a')
if self.wps == True:
if self.wps == WPSState.UNLOCKED:
wps = Color.s('{G} yes')
elif self.wps == False:
elif self.wps == WPSState.NONE:
wps = Color.s('{O} no')
elif self.wps is None:
elif self.wps == WPSState.LOCKED:
wps = Color.s('{R}lock')
elif self.wps == WPSState.UNKNOWN:
wps = Color.s('{O} n/a')
clients = ' '
if len(self.clients) > 0:

View File

@@ -2,8 +2,8 @@
# -*- coding: utf-8 -*-
from .dependency import Dependency
from .ifconfig import Ifconfig
from .iwconfig import Iwconfig
from .ip import Ip
from .iw import Iw
from ..util.process import Process
from ..util.color import Color
from ..util.input import raw_input
@@ -113,9 +113,9 @@ class Airmon(Dependency):
Manually put interface into monitor mode (no airmon-ng or vif).
Fix for bad drivers like the rtl8812AU.
'''
Ifconfig.down(iface)
Iwconfig.mode(iface, 'monitor')
Ifconfig.up(iface)
Ip.down(iface)
Iw.mode(iface, 'monitor')
Ip.up(iface)
# /sys/class/net/wlan0/type
iface_type_path = os.path.join('/sys/class/net', iface, 'type')
@@ -132,9 +132,9 @@ class Airmon(Dependency):
Manually put interface into managed mode (no airmon-ng or vif).
Fix for bad drivers like the rtl8812AU.
'''
Ifconfig.down(iface)
Iwconfig.mode(iface, 'managed')
Ifconfig.up(iface)
Ip.down(iface)
Iw.mode(iface, 'managed')
Ip.up(iface)
# /sys/class/net/wlan0/type
iface_type_path = os.path.join('/sys/class/net', iface, 'type')
@@ -182,17 +182,17 @@ class Airmon(Dependency):
if enabled_iface is None:
Color.pl('{R}failed{W}')
monitor_interfaces = Iwconfig.get_interfaces(mode='Monitor')
monitor_interfaces = Iw.get_interfaces(mode='monitor')
# Assert that there is an interface in monitor mode
if len(monitor_interfaces) == 0:
Color.pl('{R}failed{W}')
raise Exception('Cannot find any interfaces in Mode:Monitor')
raise Exception('Cannot find any interfaces in monitor mode')
# Assert that the interface enabled by airmon-ng is in monitor mode
if enabled_iface not in monitor_interfaces:
Color.pl('{R}failed{W}')
raise Exception('Cannot find %s with Mode:Monitor' % enabled_iface)
raise Exception('Cannot find %s with type:monitor' % enabled_iface)
# No errors found; the device 'enabled_iface' was put into Mode:Monitor.
Color.pl('{G}enabled {C}%s{W}' % enabled_iface)
@@ -216,20 +216,20 @@ class Airmon(Dependency):
@staticmethod
def stop(iface):
Color.p('{!} {R}disabling {O}monitor mode{O} on {R}%s{O}... ' % iface)
Color.p('{!}{W} Disabling {O}monitor{W} mode on {R}%s{W}...\n' % iface)
airmon_output = Process(['airmon-ng', 'stop', iface]).stdout()
(disabled_iface, enabled_iface) = Airmon._parse_airmon_stop(airmon_output)
if not disabled_iface and iface in Airmon.BAD_DRIVERS:
Color.p('{O}"bad driver" detected{W} ')
Color.p('{!} {O}"bad driver" detected{W} ')
disabled_iface = Airmon.stop_bad_driver(iface)
if disabled_iface:
Color.pl('{G}disabled %s{W}' % disabled_iface)
Color.pl('{+}{W} Disabled monitor mode on {G}%s{W}' % disabled_iface)
else:
Color.pl('{O}could not disable on {R}%s{W}' % iface)
Color.pl('{!} {O}Could not disable {R}%s{W}' % iface)
return (disabled_iface, enabled_iface)
@@ -278,7 +278,7 @@ class Airmon(Dependency):
Airmon.terminate_conflicting_processes()
Color.p('\n{+} Looking for {C}wireless interfaces{W}...')
monitor_interfaces = Iwconfig.get_interfaces(mode='Monitor')
monitor_interfaces = Iw.get_interfaces(mode='monitor')
if len(monitor_interfaces) == 1:
# Assume we're using the device already in montior mode
iface = monitor_interfaces[0]
@@ -373,9 +373,9 @@ class Airmon(Dependency):
@staticmethod
def put_interface_up(iface):
Color.p('{!} {O}putting interface {R}%s up{O}...' % (iface))
Ifconfig.up(iface)
Color.pl(' {G}done{W}')
Color.p('{!}{W} Putting interface {R}%s{W} {G}up{W}...\n' % (iface))
Ip.up(iface)
Color.pl('{+}{W} Done !')
@staticmethod
def start_network_manager():

View File

@@ -6,7 +6,7 @@ from .tshark import Tshark
from .wash import Wash
from ..util.process import Process
from ..config import Configuration
from ..model.target import Target
from ..model.target import Target, WPSState
from ..model.client import Client
import os, time
@@ -18,7 +18,8 @@ class Airodump(Dependency):
dependency_url = 'https://www.aircrack-ng.org/install.html'
def __init__(self, interface=None, channel=None, encryption=None,\
wps=False, target_bssid=None, output_file_prefix='airodump',\
wps=WPSState.UNKNOWN, target_bssid=None,
output_file_prefix='airodump',\
ivs_only=False, skip_wps=False, delete_existing_files=True):
'''Sets up airodump arguments, doesn't start process yet.'''
@@ -260,7 +261,7 @@ class Airodump(Dependency):
result.append(target)
elif 'WPA' in Configuration.encryption_filter and 'WPA' in target.encryption:
result.append(target)
elif 'WPS' in Configuration.encryption_filter and target.wps != False:
elif 'WPS' in Configuration.encryption_filter and target.wps in [WPSState.UNLOCKED, WPSState.LOCKED]:
result.append(target)
elif skip_wps:
result.append(target)

View File

@@ -134,7 +134,8 @@ class Bully(Attack, Dependency):
return
else:
if self.locked and not Configuration.wps_ignore_lock:
self.pattack('{R}Failed: {O}AP became {R}Locked{O}', newline=True)
self.pattack('{R}Failed: {O}Access point is {R}Locked{O}',
newline=True)
self.stop()
return

View File

@@ -28,8 +28,8 @@ class Dependency(object):
from .airodump import Airodump
from .aircrack import Aircrack
from .aireplay import Aireplay
from .ifconfig import Ifconfig
from .iwconfig import Iwconfig
from .ip import Ip
from .iw import Iw
from .bully import Bully
from .reaver import Reaver
from .wash import Wash
@@ -42,7 +42,7 @@ class Dependency(object):
# Aircrack
Aircrack, #Airodump, Airmon, Aireplay,
# wireless/net tools
Iwconfig, Ifconfig,
Iw, Ip,
# WPS
Reaver, Bully,
# Cracking/handshakes

View File

@@ -5,17 +5,17 @@ import re
from .dependency import Dependency
class Ifconfig(Dependency):
class Ip(Dependency):
dependency_required = True
dependency_name = 'ifconfig'
dependency_url = 'apt-get install net-tools'
dependency_name = 'ip'
dependency_url = 'apt-get install ip'
@classmethod
def up(cls, interface, args=[]):
'''Put interface up'''
from ..util.process import Process
command = ['ifconfig', interface]
command = ['ip', 'link', 'set', interface]
if type(args) is list:
command.extend(args)
elif type(args) is 'str':
@@ -33,7 +33,7 @@ class Ifconfig(Dependency):
'''Put interface down'''
from ..util.process import Process
pid = Process(['ifconfig', interface, 'down'])
pid = Process(['ip', 'link', 'set', interface, 'down'])
pid.wait()
if pid.poll() != 0:
raise Exception('Error putting interface %s down:\n%s\n%s' % (interface, pid.stdout(), pid.stderr()))
@@ -43,19 +43,11 @@ class Ifconfig(Dependency):
def get_mac(cls, interface):
from ..util.process import Process
output = Process(['ifconfig', interface]).stdout()
output = Process(['ip', 'link show', interface]).stdout()
# Mac address separated by dashes
mac_dash_regex = ('[a-zA-Z0-9]{2}-' * 6)[:-1]
match = re.search(' ({})'.format(mac_dash_regex), output)
match = re.search(r'([a-fA-F0-9]{2}[-:]){5}[a-fA-F0-9]{2}', output)
if match:
return match.group(1).replace('-', ':')
# Mac address separated by colons
mac_colon_regex = ('[a-zA-Z0-9]{2}:' * 6)[:-1]
match = re.search(' ({})'.format(mac_colon_regex), output)
if match:
return match.group(1)
return match.group(0).replace('-', ':')
raise Exception('Could not find the mac address for %s' % interface)

53
wifite/tools/iw.py Executable file
View File

@@ -0,0 +1,53 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from .dependency import Dependency
class Iw(Dependency):
dependency_required = True
dependency_name = 'iw'
dependency_url = 'apt-get install iw'
@classmethod
def mode(cls, iface, mode_name):
from ..util.process import Process
pid = None
if mode_name == "monitor":
pid = Process(['iw', iface, 'set monitor control'])
else:
pid = Process(['iw', iface, 'type', mode_name])
pid.wait()
return pid.poll()
@classmethod
def get_interfaces(cls, mode=None):
from ..util.process import Process
import re
ireg = re.compile(r"\s+Interface\s[a-zA-Z0-9]+")
mreg = re.compile(r"\s+type\s[a-zA-z]+")
ires = None
mres = None
interfaces = set()
iface = ''
(out, err) = Process.call('iw dev')
if mode is None:
for line in out.split('\n'):
ires = ireg.search(line)
if ires:
interfaces.add(ires.group().split("Interface")[-1])
else:
for line in out.split('\n'):
ires = ireg.search(line)
mres = mreg.search(line)
if mres:
if mode == mres.group().split("type")[-1][1:]:
interfaces.add(iface)
if ires:
iface = ires.group().split("Interface")[-1][1:]
return list(interfaces)

View File

@@ -1,49 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from .dependency import Dependency
class Iwconfig(Dependency):
dependency_required = True
dependency_name = 'iwconfig'
dependency_url = 'apt-get install wireless-tools'
@classmethod
def mode(cls, iface, mode_name):
from ..util.process import Process
pid = Process(['iwconfig', iface, 'mode', mode_name])
pid.wait()
return pid.poll()
@classmethod
def get_interfaces(cls, mode=None):
from ..util.process import Process
interfaces = set()
iface = ''
(out, err) = Process.call('iwconfig')
for line in out.split('\n'):
if len(line) == 0: continue
if not line.startswith(' '):
iface = line.split(' ')[0]
if '\t' in iface:
iface = iface.split('\t')[0].strip()
iface = iface.strip()
if len(iface) == 0:
continue
if mode is None:
interfaces.add(iface)
if mode is not None and 'Mode:{}'.format(mode) in line and len(iface) > 0:
interfaces.add(iface)
return list(interfaces)

View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
from .dependency import Dependency
from ..tools.ifconfig import Ifconfig
from ..tools.ip import Ip
from ..util.color import Color
class Macchanger(Dependency):
@@ -20,7 +20,7 @@ class Macchanger(Dependency):
Color.clear_entire_line()
Color.p('\r{+} {C}macchanger{W}: taking interface {C}%s{W} down...' % iface)
Ifconfig.down(iface)
Ip.down(iface)
Color.clear_entire_line()
Color.p('\r{+} {C}macchanger{W}: changing mac address of interface {C}%s{W}...' % iface)
@@ -38,7 +38,7 @@ class Macchanger(Dependency):
Color.clear_entire_line()
Color.p('\r{+} {C}macchanger{W}: bringing interface {C}%s{W} up...' % iface)
Ifconfig.up(iface)
Ip.up(iface)
return True
@@ -56,7 +56,7 @@ class Macchanger(Dependency):
Color.pl('\r{+} {C}macchanger{W}: resetting mac address on %s...' % iface)
# -p to reset to permanent MAC address
if cls.down_macch_up(iface, ['-p']):
new_mac = Ifconfig.get_mac(iface)
new_mac = Ip.get_mac(iface)
Color.clear_entire_line()
Color.pl('\r{+} {C}macchanger{W}: reset mac address back to {C}%s{W} on {C}%s{W}' % (new_mac, iface))
@@ -76,7 +76,7 @@ class Macchanger(Dependency):
# -e to keep vendor bytes the same
if cls.down_macch_up(iface, ['-e']):
cls.is_changed = True
new_mac = Ifconfig.get_mac(iface)
new_mac = Ip.get_mac(iface)
Color.clear_entire_line()
Color.pl('\r{+} {C}macchanger{W}: changed mac address to {C}%s{W} on {C}%s{W}' % (new_mac, iface))

View File

@@ -117,7 +117,7 @@ class Reaver(Attack, Dependency):
# Check if locked
if self.locked and not Configuration.wps_ignore_lock:
raise Exception('{O}Because access point is {R}Locked{W}')
raise Exception('{O}Access point is {R}Locked{W}')
time.sleep(0.5)

View File

@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
from .dependency import Dependency
from ..model.target import WPSState
from ..util.process import Process
import re
@@ -188,7 +189,6 @@ class Tshark(Dependency):
if ',' not in line:
continue
bssid, locked = line.split(',')
# Ignore if WPS is locked?
if '1' not in locked:
wps_bssids.add(bssid.upper())
else:
@@ -197,11 +197,11 @@ class Tshark(Dependency):
for t in targets:
target_bssid = t.bssid.upper()
if target_bssid in wps_bssids:
t.wps = True
t.wps = WPSState.UNLOCKED
elif target_bssid in locked_bssids:
t.wps = None
t.wps = WPSState.LOCKED
else:
t.wps = False
t.wps = WPSState.NONE
if __name__ == '__main__':
@@ -224,7 +224,8 @@ if __name__ == '__main__':
# Should update 'wps' field of a target
Tshark.check_for_wps_and_update_targets(test_file, targets)
print('Target(BSSID={}).wps = {} (Expected: True)'.format(targets[0].bssid, targets[0].wps))
assert targets[0].wps == True
print('Target(BSSID={}).wps = {} (Expected: 1)'.format(
targets[0].bssid, targets[0].wps))
assert targets[0].wps == WPSState.UNLOCKED
print(Tshark.bssids_with_handshakes(test_file, bssid=target_bssid))

View File

@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
from .dependency import Dependency
from ..model.target import WPSState
from ..util.process import Process
import json
@@ -53,11 +54,11 @@ class Wash(Dependency):
for t in targets:
target_bssid = t.bssid.upper()
if target_bssid in wps_bssids:
t.wps = True
t.wps = WPSState.UNLOCKED
elif target_bssid in locked_bssids:
t.wps = None
t.wps = WPSState.LOCKED
else:
t.wps = False
t.wps = WPSState.NONE
if __name__ == '__main__':
@@ -80,7 +81,8 @@ if __name__ == '__main__':
# Should update 'wps' field of a target
Wash.check_for_wps_and_update_targets(test_file, targets)
print('Target(BSSID={}).wps = {} (Expected: True)'.format(targets[0].bssid, targets[0].wps))
print('Target(BSSID={}).wps = {} (Expected: 1)'.format(
targets[0].bssid, targets[0].wps))
assert targets[0].wps == True
assert targets[0].wps == WPSState.UNLOCKED

View File

@@ -97,6 +97,10 @@ class Color(object):
'''Prints an exception. Includes stack trace if necessary.'''
Color.pl('\n{!} {R}Error: {O}%s' % str(exception))
# Don't dump trace for the "no targets found" case.
if 'No targets found' in str(exception):
return
from ..config import Configuration
if Configuration.verbose > 0 or Configuration.print_stack_traces:
Color.pl('\n{!} {O}Full stack trace below')

View File

@@ -13,15 +13,13 @@ from ..tools.cowpatty import Cowpatty
from ..tools.hashcat import Hashcat, HcxPcapTool
from ..tools.john import John
from datetime import datetime
from json import loads
import os
# TODO: Bring back the 'print' option, for easy copy/pasting. Just one-liners people can paste into terminal.
# TODO: Do not show handshake files that are in cracked.txt with a key (match on filename).
# TODO: --no-crack option while attacking targets (implies user will run --crack later)
class CrackHelper:
@@ -32,7 +30,6 @@ class CrackHelper:
'PMKID': 'PMKID Hash'
}
@classmethod
def run(cls):
Configuration.initialize(False)
@@ -53,7 +50,7 @@ class CrackHelper:
return
hs_to_crack = cls.get_user_selection(handshakes)
any_pmkid = any([hs['type'] == 'PMKID' for hs in hs_to_crack])
all_pmkid = all([hs['type'] == 'PMKID' for hs in hs_to_crack])
# Tools for cracking & their dependencies.
available_tools = {
@@ -79,26 +76,46 @@ class CrackHelper:
dep_list = ', '.join([dep.dependency_name for dep in deps])
Color.pl(' {R}* {R}%s {W}({O}%s{W})' % (tool, dep_list))
if all_pmkid:
Color.pl('{!} {O}Note: PMKID hashes can only be cracked using {C}hashcat{W}')
tool_name = 'hashcat'
else:
Color.p('\n{+} Enter the {C}cracking tool{W} to use ({C}%s{W}): {G}' % (
'{W}, {C}'.join(available_tools.keys())))
tool_name = raw_input()
if tool_name not in available_tools:
Color.pl('{!} {R}"%s"{O} tool not found, defaulting to {C}aircrack{W}' % tool_name)
tool_name = 'aircrack'
elif any_pmkid and tool_name != 'hashcat':
Color.pl('{!} {O}Note: PMKID hashes will be cracked using {C}hashcat{W}')
try:
for hs in hs_to_crack:
if tool_name != 'hashcat' and hs['type'] == 'PMKID':
if 'hashcat' in missing_tools:
Color.pl('{!} {O}Hashcat is missing, therefore we cannot crack PMKID hash{W}')
cls.crack(hs, tool_name)
except KeyboardInterrupt:
Color.pl('\n{!} {O}Interrupted{W}')
@classmethod
def is_cracked(cls, file):
if not os.path.exists(Configuration.cracked_file):
return False
with open(Configuration.cracked_file) as f:
json = loads(f.read())
if json is None:
return False
for result in json:
for k in result.keys():
v = result[k]
if 'file' in k and os.path.basename(v) == file:
return True
return False
@classmethod
def get_handshakes(cls):
handshakes = []
skipped_pmkid_files = 0
skipped_pmkid_files = skipped_cracked_files = 0
hs_dir = Configuration.wpa_handshake_dir
if not os.path.exists(hs_dir) or not os.path.isdir(hs_dir):
@@ -110,6 +127,10 @@ class CrackHelper:
if hs_file.count('_') != 3:
continue
if cls.is_cracked(hs_file):
skipped_cracked_files += 1
continue
if hs_file.endswith('.cap'):
# WPA Handshake
hs_type = '4-WAY'
@@ -148,7 +169,9 @@ class CrackHelper:
handshakes.append(handshake)
if skipped_pmkid_files > 0:
Color.pl('{!} {O}Skipping %d {R}*.16800{O} files because {R}hashcat{O} is missing.' % skipped_pmkid_files)
Color.pl('{!} {O}Skipping %d {R}*.16800{O} files because {R}hashcat{O} is missing.{W}\n' % skipped_pmkid_files)
if skipped_cracked_files > 0:
Color.pl('{!} {O}Skipping %d already cracked files.{W}\n' % skipped_cracked_files)
# Sort by Date (Descending)
return sorted(handshakes, key=lambda x: x.get('date'), reverse=True)
@@ -158,7 +181,7 @@ class CrackHelper:
def print_handshakes(cls, handshakes):
# Header
max_essid_len = max([len(hs['essid']) for hs in handshakes] + [len('ESSID (truncated)')])
Color.p('{D} NUM')
Color.p('{W}{D} NUM')
Color.p(' ' + 'ESSID (truncated)'.ljust(max_essid_len))
Color.p(' ' + 'BSSID'.ljust(17))
Color.p(' ' + 'TYPE'.ljust(5))
@@ -170,8 +193,6 @@ class CrackHelper:
Color.p(' ' + ('-' * 19) + '{W}\n')
# Handshakes
for index, handshake in enumerate(handshakes, start=1):
bssid = handshake['bssid']
date = handshake['date']
Color.p(' {G}%s{W}' % str(index).rjust(3))
Color.p(' {C}%s{W}' % handshake['essid'].ljust(max_essid_len))
Color.p(' {O}%s{W}' % handshake['bssid'].ljust(17))
@@ -253,7 +274,10 @@ class CrackHelper:
@classmethod
def crack_pmkid(cls, hs, tool_name):
def crack_pmkid(cls, hs, tool):
if tool != 'hashcat':
Color.pl('{!} {O}Note: PMKID hashes can only be cracked using {C}hashcat{W}')
key = Hashcat.crack_pmkid(hs['filename'], verbose=True)
if key is not None:

View File

@@ -4,7 +4,7 @@
from ..util.color import Color
from ..tools.airodump import Airodump
from ..util.input import raw_input, xrange
from ..model.target import Target
from ..model.target import Target, WPSState
from ..config import Configuration
from time import sleep, time
@@ -88,7 +88,7 @@ class Scanner(object):
return False # No specific target from user.
for target in self.targets:
if Configuration.wps_only and target.wps == False:
if Configuration.wps_only and target.wps not in [WPSState.UNLOCKED, WPSState.LOCKED]:
continue
if bssid and target.bssid and bssid.lower() == target.bssid.lower():
self.target = target