19 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
derv82
5e204686fa 2.2.5: PMKID timeout changed to 30sec. --pmkid-timeout option to change.
For #134
2018-09-03 10:42:55 -07:00
derv82
838ea43a73 2.2.4: Version bump for recent fixes (more ctrl+c options).
Includes:
* More options when interrupting mid-attack (continue/skip/exit)
* Show error when --wps-only and --pmkid are both specified
* Use `--force` when calling Bully to force-continue.
* README (updated, new screenshots).
2018-09-02 12:33:03 -07:00
derv82
13e51576d5 Updating screenshots 2018-09-02 12:31:12 -07:00
derv82
0f8b6d6a66 Use --force with bully 2018-09-02 12:04:04 -07:00
derv82
467f40d68a Fixing logic with switches, updating README.
Some switches are not compatible (--wps-only + --pmkid).
Wifite detects & stops if options are incompatible.

README was oudated (said no PIN attack), updated some URLs.
2018-09-02 10:59:11 -07:00
derv82
7309dfcce6 Interrupting mid-attack, users can Continue/Skip/Exit. 2018-09-02 09:58:26 -07:00
derv82
d7c51461f6 Detect when reaver does not support --pixie-dust, use bully if possible. 2018-09-01 14:47:16 -07:00
derv82
5d77cb63a3 Avoid WPS if no reaver+bully. Use bully if reaver isn't available. 2018-08-26 22:29:23 -07:00
derv82
e30a8cad07 Fix Airmon output-parsing.
On latest ubuntu, apt-get install aircrack, output is slightly different.
2018-08-26 22:01:54 -07:00
24 changed files with 419 additions and 269 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
======
@@ -5,33 +11,31 @@ This repo is a complete re-write of [`wifite`](https://github.com/derv82/wifite)
Wifite runs existing wireless-auditing tools for you. Stop memorizing command arguments & switches!
Wifite is compatible with both `python2` and `python3`.
Wifite is designed to use all known methods for retrieving the password of a wireless access point (router). These methods include:
1. WPS: The [WPS Pixie-Dust attack](https://nakedsecurity.sophos.com/2014/09/02/using-wps-may-be-even-more-dangerous/)
2. WPA: The [WPA Handshake Capture](https://hashcat.net/forum/thread-7717.html) and offline crack.
3. WPA: The [PMKID Hash Capture](https://hashcat.net/forum/thread-7717.html) and offline crack.
1. WPS: The [Offline Pixie-Dust attack](https://en.wikipedia.org/wiki/Wi-Fi_Protected_Setup#Offline_brute-force_attack)
1. WPS: The [Online Brute-Force PIN attack](https://en.wikipedia.org/wiki/Wi-Fi_Protected_Setup#Online_brute-force_attack)
2. WPA: The [WPA Handshake Capture](https://hashcat.net/forum/thread-7717.html) + offline crack.
3. WPA: The [PMKID Hash Capture](https://hashcat.net/forum/thread-7717.html) + offline crack.
4. WEP: Various known attacks against WEP, including *fragmentation*, *chop-chop*, *aireplay*, etc.
Run wifite, select your targets, and Wifite will automatically start trying to capture or crack the password.
Supported Operating Systems
---------------------------
Wifite is designed specifically for the latest version of [**Kali** Linux](https://www.kali.org/). [ParrotSec](https://www.parrotsec.org/) is also supported.
Other pen-testing distributions (such as BackBox) have outdated versions of the tools used by Wifite. Do not expect support unless you are using the latest versions of the *Required Tools*.
Other pen-testing distributions (such as BackBox or Ubuntu) have outdated versions of the tools used by Wifite. Do not expect support unless you are using the latest versions of the *Required Tools*, and also [patched wireless drivers that support injection]().
Required Tools
--------------
First and foremost, you will need a wireless card capable of "Monitor Mode" and packet injection (see [this tutorial for checking if your wireless card is compatible](http://www.aircrack-ng.org/doku.php?id=compatible_cards)). There are many cheap wireless cards that plug into USB available from online stores.
First and foremost, you will need a wireless card capable of "Monitor Mode" and packet injection (see [this tutorial for checking if your wireless card is compatible](http://www.aircrack-ng.org/doku.php?id=compatible_cards) and also [this guide](https://en.wikipedia.org/wiki/Wi-Fi_Protected_Setup#Offline_brute-force_attack)). There are many cheap wireless cards that plug into USB available from online stores.
Second, only the latest versions of these programs are supported and must be installed for Wifite to work properly:
**Required:**
* [`iwconfig`](https://wiki.debian.org/iwconfig): For identifying wireless devices already in Monitor Mode.
* `python`: Wifite is compatible with both `python2` and `python3`.
* [`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.
@@ -43,9 +47,9 @@ Second, only the latest versions of these programs are supported and must be ins
**Optional, but Recommended:**
* [`tshark`](https://www.wireshark.org/docs/man-pages/tshark.html): For detecting WPS networks and inspecting handshake capture files.
* [`reaver`](https://github.com/t6x/reaver-wps-fork-t6x): For WPS Pixie-Dust attacks.
* [`reaver`](https://github.com/t6x/reaver-wps-fork-t6x): For WPS Pixie-Dust & brute-force attacks.
* Note: Reaver's `wash` tool can be used to detect WPS networks if `tshark` is not found.
* [`bully`](https://github.com/aanarchyy/bully): For WPS Pixie-Dust attacks.
* [`bully`](https://github.com/aanarchyy/bully): For WPS Pixie-Dust & brute-force attacks.
* Alternative to Reaver. Specify `--bully` to use Bully instead of Reaver.
* Bully is also used to fetch PSK if `reaver` cannot after cracking WPS PIN.
* [`coWPAtty`](https://tools.kali.org/wireless-attacks/cowpatty): For detecting handshake captures.
@@ -54,18 +58,17 @@ Second, only the latest versions of these programs are supported and must be ins
* [`hcxdumptool`](https://github.com/ZerBea/hcxdumptool): For capturing PMKID hashes.
* [`hcxpcaptool`](https://github.com/ZerBea/hcxtools): For converting PMKID packet captures into `hashcat`'s format.
Run Wifite
----------
```
git clone https://github.com/derv82/wifite2.git
cd wifite2
python -m wifite
sudo ./Wifite.py
```
Install Wifite
--------------
To install onto your computer (so you can just run `wifite` from any terminal), run:
```bash
@@ -84,24 +87,23 @@ sudo python setup.py install --record files.txt \
Brief Feature List
------------------
* [PMKID hash capture](https://hashcat.net/forum/thread-7717.html) (enabled by-default, force with: `--pmkid`)
* Reaver (or `-bully`) WPS Pixie-Dust attack (enabled by-default, force with: `--wps-only`)
* WPA handshake capture (enabled by-default, force with: `--no-wps`)
* WPS Offline Brute-Force Attack aka "Pixie-Dust". (enabled by-default, force with: `--wps-only --pixie`)
* WPS Online Brute-Force Attack aka "PIN attack". (enabled by-default, force with: `--wps-only --no-pixie`)
* WPA/2 Offline Brute-Force Attack via 4-Way Handshake capture (enabled by-default, force with: `--no-wps`)
* Validates handshakes against `pyrit`, `tshark`, `cowpatty`, and `aircrack-ng` (when available)
* Various WEP attacks (replay, chopchop, fragment, hirte, p0841, caffe-latte)
* Automatically decloaks hidden access points while scanning or attacking.
* Note: Only works when channel is fixed. Use the `-c <channel>` switch.
* Disable this via `--no-deauths` switch
* Note: Only works when channel is fixed. Use `-c <channel>`
* Disable this using `--no-deauths`
* 5Ghz support for some wireless cards (via `-5` switch).
* Note: Some tools don't play well on 5GHz channels (e.g. `aireplay-ng`)
* Stores cracked passwords and handshakes to the current directory (`--cracked`)
* Includes metadata about the access point.
* Includes information about the cracked access point (Name, BSSID, Date, etc).
* Easy to try to crack handshakes or PMKID hashes against a wordlist (`--crack`)
What's new?
-----------
Comparing this repo to the "old wifite" @ https://github.com/derv82/wifite
* **Less bugs**
@@ -121,36 +123,35 @@ Comparing this repo to the "old wifite" @ https://github.com/derv82/wifite
What's gone?
------------
* No more WPS PIN attack, because it can take days on-average.
* However, this feature may be added back into Wiite2 (See [#90](https://github.com/derv82/wifite2/issues/90))
* And the Pixie-Dust attack is still an option.
* Some command-line arguments (`--wept`, `--wpst`, and other confusing switches).
* You can still access some of these obscure options, try `wifite -h -v`
What's not new?
---------------
* (Mostly) Backwards compatible with the original `wifite`'s arguments.
* Same text-based interface everyone knows and loves.
Screenshots
-----------
Cracking WPS PIN using `reaver`'s Pixie-Dust attack, then fetching WPA key using `bully`:
![Pixie-Dust with Reaver to get PIN and Bully to get PSK](https://i.imgur.com/Q5KSDbg.gif)
Cracking WPS PIN using `reaver`'s Pixie-Dust attack, then retrieving WPA PSK using `bully`:
![Pixie-Dust with Reaver to get PIN and Bully to get PSK](https://i.imgur.com/I2W0wND.gif)
-------------
Cracking WPA key using PMKID attack:
![PMKID attack](https://i.imgur.com/CR8oOp0.gif)
-------------
Decloaking & cracking a hidden access point (via the WPA Handshake attack):
![Decloaking and Cracking a hidden access point](http://i.imgur.com/MTMwSzM.gif)
![Decloaking and Cracking a hidden access point](https://i.imgur.com/F6VPhbm.gif)
-------------
Cracking a weak WEP password (using the WEP Replay attack):
![Cracking a weak WEP password](http://i.imgur.com/VIeltx9.gif)
![Cracking a weak WEP password](https://i.imgur.com/jP72rVo.gif)
-------------
Various cracking options (using `--crack` option):
![--crack option](http://i.imgur.com/rydOakW.png)
Cracking a pre-captured handshake using John The Ripper (via the `--crack` option):
![--crack option](https://i.imgur.com/iHcfCjp.gif)

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,21 +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('--new-hs',
action='store_true',
dest='ignore_old_handshakes',
help=Color.s('Captures new handshakes, ignores existing handshakes ' +
'in ./hs (default: {G}off{W})'))
wpa.add_argument('--hs-dir',
action='store',
dest='wpa_handshake_dir',
@@ -317,6 +308,12 @@ class Arguments(object):
wpa.add_argument('-hs-dir', help=argparse.SUPPRESS, action='store',
dest='wpa_handshake_dir', type=str)
wpa.add_argument('--new-hs',
action='store_true',
dest='ignore_old_handshakes',
help=Color.s('Captures new handshakes, ignores existing handshakes ' +
'in {C}%s{W} (default: {G}off{W})' % self.config.wpa_handshake_dir))
wpa.add_argument('--dict',
action='store',
dest='wordlist',
@@ -435,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',
@@ -462,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

@@ -1,6 +1,10 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from .wep import AttackWEP
from .wpa import AttackWPA
from .wps import AttackWPS
from .pmkid import AttackPMKID
from ..config import Configuration
from ..util.color import Color
@@ -12,6 +16,10 @@ class AttackAll(object):
Attacks all given `targets` (list[wifite.model.target]) until user interruption.
Returns: Number of targets that were attacked (int)
'''
if any(t.wps for t in targets) and not AttackWPS.can_attack_wps():
# Warn that WPS attacks are not available.
Color.pl('{!} {O}Note: WPS attacks are not possible because you do not have {C}reaver{O} nor {C}bully{W}')
attacked_targets = 0
targets_remaining = len(targets)
for index, target in enumerate(targets, start=1):
@@ -36,10 +44,6 @@ class AttackAll(object):
Attacks a single `target` (wifite.model.target).
Returns: True if attacks should continue, False otherwise.
'''
from .wep import AttackWEP
from .wpa import AttackWPA
from .wps import AttackWPS
from .pmkid import AttackPMKID
attacks = []
@@ -54,21 +58,27 @@ class AttackAll(object):
# WPA can have multiple attack vectors:
# WPS
if target.wps != False:
if not Configuration.use_pmkid_only:
if target.wps != False and AttackWPS.can_attack_wps():
# Pixie-Dust
if Configuration.wps_pixie:
attacks.append(AttackWPS(target, pixie_dust=True))
# PIN attack
if Configuration.wps_pin:
attacks.append(AttackWPS(target, pixie_dust=False))
if not Configuration.wps_only:
# PMKID
attacks.append(AttackPMKID(target))
# Handshake capture
if not Configuration.use_pmkid_only:
attacks.append(AttackWPA(target))
if len(attacks) == 0:
Color.pl('{!} {R}Error: {O}Unable to attack: encryption not WEP or WPA')
return
Color.pl('{!} {R}Error: {O}Unable to attack: no attacks available')
return True # Keep attacking other targets (skip)
while len(attacks) > 0:
attack = attacks.pop(0)
@@ -81,8 +91,13 @@ class AttackAll(object):
continue
except KeyboardInterrupt:
Color.pl('\n{!} {O}Interrupted{W}\n')
if not cls.user_wants_to_continue(targets_remaining, len(attacks)):
return False # Stop attacking other targets
answer = cls.user_wants_to_continue(targets_remaining, len(attacks))
if answer is True:
continue # Keep attacking the same target (continue)
elif answer is None:
return True # Keep attacking other targets (skip)
else:
return False # Stop all attacks (exit)
if attack.success:
attack.crack_result.save()
@@ -105,15 +120,30 @@ class AttackAll(object):
prompt_list.append(Color.s('{C}%d{W} attack(s)' % attacks_remaining))
if targets_remaining > 0:
prompt_list.append(Color.s('{C}%d{W} target(s)' % targets_remaining))
prompt = ' and '.join(prompt_list)
Color.pl('{+} %s remain, Do you want to continue?' % prompt)
prompt = ' and '.join(prompt_list) + ' remain'
Color.pl('{+} %s' % prompt)
prompt = Color.s('{+} Type {G}c{W} to {G}continue{W}' +
' or {R}s{W} to {R}stop{W}: ')
prompt = '{+} Do you want to'
options = '('
if attacks_remaining > 0:
prompt += ' {G}continue{W} attacking,'
options += '{G}C{W}{D}, {W}'
if targets_remaining > 0:
prompt += ' {O}skip{W} to the next target,'
options += '{O}s{W}{D}, {W}'
options += '{R}e{W})'
prompt += ' or {R}exit{W} %s? {C}' % options
from ..util.input import raw_input
if raw_input(prompt).lower().startswith('s'):
return False
else:
return True
answer = raw_input(Color.s(prompt)).lower()
if answer.startswith('s'):
return None # Skip
elif answer.startswith('e'):
return False # Exit
else:
return True # Continue

View File

@@ -62,12 +62,6 @@ class AttackPMKID(Attack):
Returns:
True if handshake is captured. False otherwise.
'''
# Skip if user only wants to attack WPS targets
if Configuration.wps_only and self.target.wps == False:
Color.pl('\r{!} {O}Skipping PMKID attack on {R}%s{O} because {R}--wps-only{O} is set{W}' % self.target.essid)
self.success = False
return False
from ..util.process import Process
# Check that we have all hashcat programs
dependencies = [
@@ -114,7 +108,7 @@ class AttackPMKID(Attack):
The PMKID hash (str) if found, otherwise None.
'''
self.keep_capturing = True
self.timer = Timer(15)
self.timer = Timer(Configuration.pmkid_timeout)
# Start hcxdumptool
t = Thread(target=self.dumptool_thread)
@@ -174,7 +168,6 @@ class AttackPMKID(Attack):
Color.clear_entire_line()
Color.pattack('PMKID', self.target, '{R}CRACK',
'{R}Failed {O}Passphrase not found in dictionary.\n')
Color.pl('')
return False
else:
# Successfully cracked.

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

@@ -3,9 +3,17 @@
from ..model.attack import Attack
from ..util.color import Color
from ..util.process import Process
from ..config import Configuration
from ..tools.bully import Bully
from ..tools.reaver import Reaver
class AttackWPS(Attack):
@staticmethod
def can_attack_wps():
return Reaver.exists() or Bully.exists()
def __init__(self, target, pixie_dust=False):
super(AttackWPS, self).__init__(target)
self.success = False
@@ -36,16 +44,31 @@ class AttackWPS(Attack):
self.success = False
return False
if Configuration.use_bully:
if not Reaver.exists() and Bully.exists():
# Use bully if reaver isn't available
return self.run_bully()
elif self.pixie_dust and not Reaver.is_pixiedust_supported() and Bully.exists():
# Use bully if reaver can't do pixie-dust
return self.run_bully()
elif Configuration.use_bully:
# Use bully if asked by user
return self.run_bully()
elif not Reaver.exists():
# Print error if reaver isn't found (bully not available)
if self.pixie_dust:
Color.pl('\r{!} {R}Skipping WPS Pixie-Dust attack: {O}reaver{R} not found.{W}')
else:
Color.pl('\r{!} {R}Skipping WPS PIN attack: {O}reaver{R} not found.{W}')
return False
elif self.pixie_dust and not Reaver.is_pixiedust_supported():
# Print error if reaver can't support pixie-dust (bully not available)
Color.pl('\r{!} {R}Skipping WPS attack: {O}reaver{R} does not support {O}--pixie-dust{W}')
return False
else:
return self.run_reaver()
return False
def run_bully(self):
from ..tools.bully import Bully
bully = Bully(self.target, pixie_dust=self.pixie_dust)
bully.run()
bully.stop()
@@ -55,8 +78,6 @@ class AttackWPS(Attack):
def run_reaver(self):
from ..tools.reaver import Reaver
reaver = Reaver(self.target, pixie_dust=self.pixie_dust)
reaver.run()
self.crack_result = reaver.crack_result

View File

@@ -8,7 +8,7 @@ from .tools.macchanger import Macchanger
class Configuration(object):
''' Stores configuration variables and functions for Wifite. '''
version = '2.2.3'
version = '2.2.5'
initialized = False # Flag indicating config has been initialized
temp_dir = None # Temporary directory
@@ -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,9 +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)
@@ -139,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
@@ -148,18 +154,27 @@ class Configuration(object):
Color.pl('{+} {C}option:{W} using {G}eviltwin attacks{W} against all targets')
'''
# Adjust WEP attack list
cls.parse_wep_attacks()
cls.validate()
# Commands
if args.cracked: cls.show_cracked = True
if args.check_handshake: cls.check_handshake = args.check_handshake
if args.crack_handshake: cls.crack_handshake = True
@classmethod
def validate(cls):
if cls.use_pmkid_only and cls.wps_only:
Color.pl('{!} {R}Bad Configuration:{O} --pmkid and --wps-only are not compatible')
raise RuntimeError('Unable to attack networks: --pmkid and --wps-only are not compatible together')
@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} ' +
@@ -193,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' % (
@@ -273,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
@@ -295,10 +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.wpa_handshake_dir:
cls.wpa_handshake_dir = args.wpa_handshake_dir
Color.pl('{+} {C}option:{W} will store handshakes to ' +
@@ -343,6 +361,11 @@ class Configuration(object):
'(no {O}Pixie-Dust{W}) on targets')
if args.use_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
else:
cls.use_bully = args.use_bully
Color.pl('{+} {C}option:{W} use {C}bully{W} instead of {C}reaver{W} ' +
'for WPS Attacks')
@@ -366,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)'''
@@ -388,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')
@@ -447,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)
@@ -204,7 +204,7 @@ class Airmon(Dependency):
'''Find the interface put into monitor mode (if any)'''
# airmon-ng output: (mac80211 monitor mode vif enabled for [phy10]wlan0 on [phy10]wlan0mon)
enabled_re = re.compile(r'\s*\(mac80211 monitor mode (?:vif )?enabled for [^ ]+ on (?:\[\w+\])?(\w+)\)\s*')
enabled_re = re.compile(r'.*\(mac80211 monitor mode (?:vif )?enabled (?:for [^ ]+ )?on (?:\[\w+\])?(\w+)\)?.*')
for line in airmon_output.split('\n'):
matches = enabled_re.match(line)
@@ -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]
@@ -359,6 +359,10 @@ class Airmon(Dependency):
# Can't just pkill network manager; it's a service
Process(['service', 'network-manager', 'stop']).wait()
Airmon.killed_network_manager = True
elif pname == 'avahi-daemon' and Process.exists('service'):
Color.pl('{!} {O}stopping avahi-daemon ({R}service avahi-daemon stop{O})')
# Can't just pkill avahi-daemon; it's a service
Process(['service', 'avahi-daemon', 'stop']).wait()
else:
Color.pl('{!} {R}Terminating {O}conflicting process {R}%s{O} (PID {R}%s{O})' % (pname, pid))
try:
@@ -369,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():
@@ -408,7 +412,27 @@ class Airmon(Dependency):
Color.pl(' {R}cannot restart NetworkManager: {O}systemctl{R} or {O}service{R} not found{W}')
if __name__ == '__main__':
Airmon.terminate_conflicting_processes()
stdout = '''
Found 2 processes that could cause trouble.
If airodump-ng, aireplay-ng or airtun-ng stops working after
a short period of time, you may want to run 'airmon-ng check kill'
PID Name
5563 avahi-daemon
5564 avahi-daemon
PHY Interface Driver Chipset
phy0 wlx00c0ca4ecae0 rtl8187 Realtek Semiconductor Corp. RTL8187
Interface 15mon is too long for linux so it will be renamed to the old style (wlan#) name.
(mac80211 monitor mode vif enabled on [phy0]wlan0mon
(mac80211 station mode vif disabled for [phy0]wlx00c0ca4ecae0)
'''
start_iface = Airmon._parse_airmon_start(stdout)
print('start_iface from stdout:', start_iface)
Configuration.initialize(False)
iface = Airmon.ask()
(disabled_iface, enabled_iface) = Airmon.stop(iface)
print('Disabled:', disabled_iface)

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

@@ -49,7 +49,12 @@ class Bully(Attack, Dependency):
'--bssid', target.bssid,
'--channel', target.channel,
#'--detectlock', # Detect WPS lockouts unreported by AP
#'--force',
# Restoring session from '/root/.bully/34210901927c.run'
# WARNING: WPS checksum was bruteforced in prior session, now autogenerated
# Use --force to ignore above warning(s) and continue anyway
'--force',
'-v', '4',
Configuration.interface
])
@@ -129,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

@@ -14,6 +14,12 @@ class Dependency(object):
)
@classmethod
def exists(cls):
from ..util.process import Process
return Process.exists(cls.dependency_name)
@classmethod
def run_dependency_check(cls):
from ..util.color import Color
@@ -22,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
@@ -36,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,54 +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 exists(cls):
from ..util.process import Process
return Process.exists('iwconfig')
@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

@@ -14,9 +14,6 @@ class Pyrit(Dependency):
def __init__(self):
pass
@staticmethod
def exists():
return Process.exists('pyrit')
@staticmethod
def bssid_essid_with_handshakes(capfile, bssid=None, essid=None):

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
@@ -14,9 +15,6 @@ class Tshark(Dependency):
def __init__(self):
pass
@staticmethod
def exists():
return Process.exists('tshark')
@staticmethod
def _extract_src_dst_index_total(line):
@@ -29,6 +27,7 @@ class Tshark(Dependency):
(src, dst, index, total) = match.groups()
return src, dst, index, total
@staticmethod
def _build_target_client_handshake_map(output, bssid=None):
# Map of target_ssid,client_ssid -> handshake #s
@@ -190,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:
@@ -199,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__':
@@ -226,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
@@ -14,9 +15,6 @@ class Wash(Dependency):
def __init__(self):
pass
@staticmethod
def exists():
return Process.exists('wash')
@staticmethod
def check_for_wps_and_update_targets(capfile, targets):
@@ -56,11 +54,12 @@ 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__':
test_file = './tests/files/contains_wps_network.cap'
@@ -82,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