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 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 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: 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/) 1. WPS: The [Offline Pixie-Dust attack](https://en.wikipedia.org/wiki/Wi-Fi_Protected_Setup#Offline_brute-force_attack)
2. WPA: The [WPA Handshake Capture](https://hashcat.net/forum/thread-7717.html) and offline crack. 1. WPS: The [Online Brute-Force PIN attack](https://en.wikipedia.org/wiki/Wi-Fi_Protected_Setup#Online_brute-force_attack)
3. WPA: The [PMKID Hash Capture](https://hashcat.net/forum/thread-7717.html) and offline crack. 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. 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. Run wifite, select your targets, and Wifite will automatically start trying to capture or crack the password.
Supported Operating Systems 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. 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 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) 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.
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.
Second, only the latest versions of these programs are supported and must be installed for Wifite to work properly: Second, only the latest versions of these programs are supported and must be installed for Wifite to work properly:
**Required:** **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. * [`ifconfig`](https://en.wikipedia.org/wiki/Ifconfig): For starting/stopping wireless devices.
* [`Aircrack-ng`](http://aircrack-ng.org/) suite, includes: * [`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. * [`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:** **Optional, but Recommended:**
* [`tshark`](https://www.wireshark.org/docs/man-pages/tshark.html): For detecting WPS networks and inspecting handshake capture files. * [`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. * 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. * 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. * 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. * [`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. * [`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. * [`hcxpcaptool`](https://github.com/ZerBea/hcxtools): For converting PMKID packet captures into `hashcat`'s format.
Run Wifite Run Wifite
---------- ----------
``` ```
git clone https://github.com/derv82/wifite2.git git clone https://github.com/derv82/wifite2.git
cd wifite2 cd wifite2
python -m wifite sudo ./Wifite.py
``` ```
Install Wifite Install Wifite
-------------- --------------
To install onto your computer (so you can just run `wifite` from any terminal), run: To install onto your computer (so you can just run `wifite` from any terminal), run:
```bash ```bash
@@ -84,24 +87,23 @@ sudo python setup.py install --record files.txt \
Brief Feature List Brief Feature List
------------------ ------------------
* [PMKID hash capture](https://hashcat.net/forum/thread-7717.html) (enabled by-default, force with: `--pmkid`) * [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`) * WPS Offline Brute-Force Attack aka "Pixie-Dust". (enabled by-default, force with: `--wps-only --pixie`)
* WPA handshake capture (enabled by-default, force with: `--no-wps`) * 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) * Validates handshakes against `pyrit`, `tshark`, `cowpatty`, and `aircrack-ng` (when available)
* Various WEP attacks (replay, chopchop, fragment, hirte, p0841, caffe-latte) * Various WEP attacks (replay, chopchop, fragment, hirte, p0841, caffe-latte)
* Automatically decloaks hidden access points while scanning or attacking. * Automatically decloaks hidden access points while scanning or attacking.
* Note: Only works when channel is fixed. Use the `-c <channel>` switch. * Note: Only works when channel is fixed. Use `-c <channel>`
* Disable this via `--no-deauths` switch * Disable this using `--no-deauths`
* 5Ghz support for some wireless cards (via `-5` switch). * 5Ghz support for some wireless cards (via `-5` switch).
* Note: Some tools don't play well on 5GHz channels (e.g. `aireplay-ng`) * Note: Some tools don't play well on 5GHz channels (e.g. `aireplay-ng`)
* Stores cracked passwords and handshakes to the current directory (`--cracked`) * 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`) * Easy to try to crack handshakes or PMKID hashes against a wordlist (`--crack`)
What's new? What's new?
----------- -----------
Comparing this repo to the "old wifite" @ https://github.com/derv82/wifite Comparing this repo to the "old wifite" @ https://github.com/derv82/wifite
* **Less bugs** * **Less bugs**
@@ -121,36 +123,35 @@ Comparing this repo to the "old wifite" @ https://github.com/derv82/wifite
What's gone? 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). * Some command-line arguments (`--wept`, `--wpst`, and other confusing switches).
* You can still access some of these obscure options, try `wifite -h -v` * You can still access some of these obscure options, try `wifite -h -v`
What's not new? What's not new?
--------------- ---------------
* (Mostly) Backwards compatible with the original `wifite`'s arguments. * (Mostly) Backwards compatible with the original `wifite`'s arguments.
* Same text-based interface everyone knows and loves. * Same text-based interface everyone knows and loves.
Screenshots 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 & 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 (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): Cracking a pre-captured handshake using John The Ripper (via the `--crack` option):
![--crack option](http://i.imgur.com/rydOakW.png) ![--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_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_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_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_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}'))) 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: ' + help=self._verbose('Number of deauth packets to send (default: ' +
'{G}%d{W})' % self.config.num_deauths)) '{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): def _add_eviltwin_args(self, group):
pass pass
@@ -292,21 +298,6 @@ class Arguments(object):
wpa.add_argument('-wpa', help=argparse.SUPPRESS, action='store_true', wpa.add_argument('-wpa', help=argparse.SUPPRESS, action='store_true',
dest='wpa_filter') 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', wpa.add_argument('--hs-dir',
action='store', action='store',
dest='wpa_handshake_dir', dest='wpa_handshake_dir',
@@ -317,6 +308,12 @@ class Arguments(object):
wpa.add_argument('-hs-dir', help=argparse.SUPPRESS, action='store', wpa.add_argument('-hs-dir', help=argparse.SUPPRESS, action='store',
dest='wpa_handshake_dir', type=str) 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', wpa.add_argument('--dict',
action='store', action='store',
dest='wordlist', dest='wordlist',
@@ -435,6 +432,22 @@ class Arguments(object):
wps.add_argument('-wpsto', help=argparse.SUPPRESS, action='store', wps.add_argument('-wpsto', help=argparse.SUPPRESS, action='store',
dest='wps_timeout_threshold', type=int) 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): def _add_command_args(self, commands):
commands.add_argument('--cracked', commands.add_argument('--cracked',
@@ -462,7 +475,7 @@ class Arguments(object):
if __name__ == '__main__': if __name__ == '__main__':
from .util.color import Color from .util.color import Color
from config import Configuration from .config import Configuration
Configuration.initialize(False) Configuration.initialize(False)
a = Arguments(Configuration) a = Arguments(Configuration)
args = a.args args = a.args

View File

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

View File

@@ -62,12 +62,6 @@ class AttackPMKID(Attack):
Returns: Returns:
True if handshake is captured. False otherwise. 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 from ..util.process import Process
# Check that we have all hashcat programs # Check that we have all hashcat programs
dependencies = [ dependencies = [
@@ -114,7 +108,7 @@ class AttackPMKID(Attack):
The PMKID hash (str) if found, otherwise None. The PMKID hash (str) if found, otherwise None.
''' '''
self.keep_capturing = True self.keep_capturing = True
self.timer = Timer(15) self.timer = Timer(Configuration.pmkid_timeout)
# Start hcxdumptool # Start hcxdumptool
t = Thread(target=self.dumptool_thread) t = Thread(target=self.dumptool_thread)
@@ -174,7 +168,6 @@ class AttackPMKID(Attack):
Color.clear_entire_line() Color.clear_entire_line()
Color.pattack('PMKID', self.target, '{R}CRACK', Color.pattack('PMKID', self.target, '{R}CRACK',
'{R}Failed {O}Passphrase not found in dictionary.\n') '{R}Failed {O}Passphrase not found in dictionary.\n')
Color.pl('')
return False return False
else: else:
# Successfully cracked. # Successfully cracked.

View File

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

View File

@@ -3,9 +3,17 @@
from ..model.attack import Attack from ..model.attack import Attack
from ..util.color import Color from ..util.color import Color
from ..util.process import Process
from ..config import Configuration from ..config import Configuration
from ..tools.bully import Bully
from ..tools.reaver import Reaver
class AttackWPS(Attack): class AttackWPS(Attack):
@staticmethod
def can_attack_wps():
return Reaver.exists() or Bully.exists()
def __init__(self, target, pixie_dust=False): def __init__(self, target, pixie_dust=False):
super(AttackWPS, self).__init__(target) super(AttackWPS, self).__init__(target)
self.success = False self.success = False
@@ -36,16 +44,31 @@ class AttackWPS(Attack):
self.success = False self.success = False
return 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() 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: else:
return self.run_reaver() return self.run_reaver()
return False
def run_bully(self): def run_bully(self):
from ..tools.bully import Bully
bully = Bully(self.target, pixie_dust=self.pixie_dust) bully = Bully(self.target, pixie_dust=self.pixie_dust)
bully.run() bully.run()
bully.stop() bully.stop()
@@ -55,8 +78,6 @@ class AttackWPS(Attack):
def run_reaver(self): def run_reaver(self):
from ..tools.reaver import Reaver
reaver = Reaver(self.target, pixie_dust=self.pixie_dust) reaver = Reaver(self.target, pixie_dust=self.pixie_dust)
reaver.run() reaver.run()
self.crack_result = reaver.crack_result self.crack_result = reaver.crack_result

View File

@@ -8,7 +8,7 @@ from .tools.macchanger import Macchanger
class Configuration(object): class Configuration(object):
''' Stores configuration variables and functions for Wifite. ''' ''' Stores configuration variables and functions for Wifite. '''
version = '2.2.3' version = '2.2.5'
initialized = False # Flag indicating config has been initialized initialized = False # Flag indicating config has been initialized
temp_dir = None # Temporary directory 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.random_mac = False # Should generate a random Mac address at startup.
cls.no_deauth = False # Deauth hidden networks & WPA handshake targets cls.no_deauth = False # Deauth hidden networks & WPA handshake targets
cls.num_deauths = 1 # Number of deauth packets to send to each target. 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'] cls.encryption_filter = ['WEP', 'WPA', 'WPS']
@@ -78,9 +79,13 @@ class Configuration(object):
cls.wpa_handshake_dir = 'hs' # Dir to store handshakes cls.wpa_handshake_dir = 'hs' # Dir to store handshakes
cls.wpa_strip_handshake = False # Strip non-handshake packets cls.wpa_strip_handshake = False # Strip non-handshake packets
cls.ignore_old_handshakes = False # Always fetch a new handshake cls.ignore_old_handshakes = False # Always fetch a new handshake
# PMKID variables
cls.use_pmkid_only = False # Only use PMKID Capture+Crack attack 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 # Default dictionary for cracking
cls.cracked_file = 'cracked.txt'
cls.wordlist = None cls.wordlist = None
wordlists = [ wordlists = [
'./wordlist-top4800-probable.txt', # Local file (ran from cloned repo) './wordlist-top4800-probable.txt', # Local file (ran from cloned repo)
@@ -139,6 +144,7 @@ class Configuration(object):
cls.parse_wep_args(args) cls.parse_wep_args(args)
cls.parse_wpa_args(args) cls.parse_wpa_args(args)
cls.parse_wps_args(args) cls.parse_wps_args(args)
cls.parse_pmkid_args(args)
cls.parse_encryption() cls.parse_encryption()
# EvilTwin # EvilTwin
@@ -148,18 +154,27 @@ class Configuration(object):
Color.pl('{+} {C}option:{W} using {G}eviltwin attacks{W} against all targets') Color.pl('{+} {C}option:{W} using {G}eviltwin attacks{W} against all targets')
''' '''
# Adjust WEP attack list
cls.parse_wep_attacks() cls.parse_wep_attacks()
cls.validate()
# Commands # Commands
if args.cracked: cls.show_cracked = True if args.cracked: cls.show_cracked = True
if args.check_handshake: cls.check_handshake = args.check_handshake if args.check_handshake: cls.check_handshake = args.check_handshake
if args.crack_handshake: cls.crack_handshake = True 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 @classmethod
def parse_settings_args(cls, args): def parse_settings_args(cls, args):
'''Parses basic settings/configurations from arguments.''' '''Parses basic settings/configurations from arguments.'''
if args.random_mac: if args.random_mac:
cls.random_mac = True cls.random_mac = True
Color.pl('{+} {C}option:{W} using {G}random mac address{W} ' + 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 ' + Color.pl('{+} {C}option:{W} will {R}not{W} {O}deauth{W} clients ' +
'during scans or captures') '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: if args.num_deauths and args.num_deauths > 0:
cls.num_deauths = args.num_deauths cls.num_deauths = args.num_deauths
Color.pl('{+} {C}option:{W} send {G}%d{W} deauth packets when deauthing' % ( 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 cls.wpa_filter = args.wpa_filter
if args.wordlist: if args.wordlist:
if os.path.exists(args.wordlist): if not 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:
cls.wordlist = None cls.wordlist = None
Color.pl('{+} {C}option:{O} wordlist {R}%s{O} was not found, wifite will NOT attempt to crack handshakes' % args.wordlist) 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: if args.wpa_deauth_timeout:
cls.wpa_deauth_timeout = 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 ' + Color.pl('{+} {C}option:{W} will {O}ignore{W} existing handshakes ' +
'(force capture)') '(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: if args.wpa_handshake_dir:
cls.wpa_handshake_dir = args.wpa_handshake_dir cls.wpa_handshake_dir = args.wpa_handshake_dir
Color.pl('{+} {C}option:{W} will store handshakes to ' + Color.pl('{+} {C}option:{W} will store handshakes to ' +
@@ -343,6 +361,11 @@ class Configuration(object):
'(no {O}Pixie-Dust{W}) on targets') '(no {O}Pixie-Dust{W}) on targets')
if args.use_bully: 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 cls.use_bully = args.use_bully
Color.pl('{+} {C}option:{W} use {C}bully{W} instead of {C}reaver{W} ' + Color.pl('{+} {C}option:{W} use {C}bully{W} instead of {C}reaver{W} ' +
'for WPS Attacks') 'for WPS Attacks')
@@ -366,6 +389,16 @@ class Configuration(object):
cls.wps_ignore_lock = True cls.wps_ignore_lock = True
Color.pl('{+} {C}option:{W} will {O}ignore{W} WPS lock-outs') 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 @classmethod
def parse_encryption(cls): def parse_encryption(cls):
'''Adjusts encryption filter (WEP and/or WPA and/or WPS)''' '''Adjusts encryption filter (WEP and/or WPA and/or WPS)'''
@@ -388,9 +421,9 @@ class Configuration(object):
def parse_wep_attacks(cls): def parse_wep_attacks(cls):
'''Parses and sets WEP-specific args (-chopchop, -fragment, etc)''' '''Parses and sets WEP-specific args (-chopchop, -fragment, etc)'''
cls.wep_attacks = [] cls.wep_attacks = []
import sys from sys import argv
seen = set() seen = set()
for arg in sys.argv: for arg in argv:
if arg in seen: continue if arg in seen: continue
seen.add(arg) seen.add(arg)
if arg == '-arpreplay': cls.wep_attacks.append('replay') if arg == '-arpreplay': cls.wep_attacks.append('replay')
@@ -447,14 +480,15 @@ class Configuration(object):
Macchanger.reset_if_changed() Macchanger.reset_if_changed()
from .tools.airmon import Airmon from .tools.airmon import Airmon
if cls.interface is not None and Airmon.base_interface is not None: 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('{!} {O}Note:{W} Leaving interface in Monitor Mode!')
Color.pl('{!} To disable Monitor Mode when finished: ' + Color.pl('{!} To disable Monitor Mode when finished: ' +
'{C}airmon-ng stop %s{W}' % cls.interface) '{C}airmon-ng stop %s{W}' % cls.interface)
else:
# Stop monitor mode # Stop monitor mode
#Airmon.stop(cls.interface) Airmon.stop(cls.interface)
# Bring original interface back up # Bring original interface back up
#Airmon.put_interface_up(Airmon.base_interface) Airmon.put_interface_up(Airmon.base_interface)
if Airmon.killed_network_manager: if Airmon.killed_network_manager:
Color.pl('{!} You can restart NetworkManager when finished ({C}service network-manager start{W})') Color.pl('{!} You can restart NetworkManager when finished ({C}service network-manager start{W})')

View File

@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from ..util.color import Color from ..util.color import Color
from ..config import Configuration
import os import os
import time import time
@@ -11,7 +12,7 @@ class CrackResult(object):
''' Abstract class containing results from a crack session ''' ''' Abstract class containing results from a crack session '''
# File to save cracks to, in PWD # File to save cracks to, in PWD
cracked_file = 'cracked.txt' cracked_file = Configuration.cracked_file
def __init__(self): def __init__(self):
self.date = int(time.time()) self.date = int(time.time())
@@ -55,8 +56,8 @@ class CrackResult(object):
this_dict['date'] = entry.get('date') this_dict['date'] = entry.get('date')
if entry == this_dict: if entry == this_dict:
# Skip if we already saved this BSSID+ESSID+TYPE+KEY # Skip if we already saved this BSSID+ESSID+TYPE+KEY
Color.pl('{+} {C}%s{O} already exists in {G}cracked.txt{O}, skipping.' % ( Color.pl('{+} {C}%s{O} already exists in {G}%s{O}, skipping.' % (
self.essid)) self.essid, Configuration.cracked_file))
return return
saved_results.append(self.to_dict()) saved_results.append(self.to_dict())
@@ -67,7 +68,7 @@ class CrackResult(object):
@classmethod @classmethod
def display(cls): def display(cls):
''' Show cracked targets from cracked.txt ''' ''' Show cracked targets from cracked file '''
name = cls.cracked_file name = cls.cracked_file
if not os.path.exists(name): if not os.path.exists(name):
Color.pl('{!} {O}file {C}%s{O} not found{W}' % 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 import re
class WPSState:
NONE, UNLOCKED, LOCKED, UNKNOWN = range(0, 4)
class Target(object): class Target(object):
''' '''
Holds details for a 'Target' aka Access Point (e.g. router). 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 = None # '(%s)' % self.bssid
self.essid_known = False self.essid_known = False
# False=No WPS, None=Locked WPS, True=Unlocked WPS self.wps = WPSState.UNKNOWN
self.wps = False
self.decloaked = False # If ESSID was hidden but we decloaked it. self.decloaked = False # If ESSID was hidden but we decloaked it.
@@ -133,13 +137,14 @@ class Target(object):
color = 'R' color = 'R'
power = Color.s('{%s}%s' % (color, power)) power = Color.s('{%s}%s' % (color, power))
wps = Color.s('{O} n/a') if self.wps == WPSState.UNLOCKED:
if self.wps == True:
wps = Color.s('{G} yes') wps = Color.s('{G} yes')
elif self.wps == False: elif self.wps == WPSState.NONE:
wps = Color.s('{O} no') wps = Color.s('{O} no')
elif self.wps is None: elif self.wps == WPSState.LOCKED:
wps = Color.s('{R}lock') wps = Color.s('{R}lock')
elif self.wps == WPSState.UNKNOWN:
wps = Color.s('{O} n/a')
clients = ' ' clients = ' '
if len(self.clients) > 0: if len(self.clients) > 0:

View File

@@ -2,8 +2,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from .dependency import Dependency from .dependency import Dependency
from .ifconfig import Ifconfig from .ip import Ip
from .iwconfig import Iwconfig from .iw import Iw
from ..util.process import Process from ..util.process import Process
from ..util.color import Color from ..util.color import Color
from ..util.input import raw_input from ..util.input import raw_input
@@ -113,9 +113,9 @@ class Airmon(Dependency):
Manually put interface into monitor mode (no airmon-ng or vif). Manually put interface into monitor mode (no airmon-ng or vif).
Fix for bad drivers like the rtl8812AU. Fix for bad drivers like the rtl8812AU.
''' '''
Ifconfig.down(iface) Ip.down(iface)
Iwconfig.mode(iface, 'monitor') Iw.mode(iface, 'monitor')
Ifconfig.up(iface) Ip.up(iface)
# /sys/class/net/wlan0/type # /sys/class/net/wlan0/type
iface_type_path = os.path.join('/sys/class/net', iface, '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). Manually put interface into managed mode (no airmon-ng or vif).
Fix for bad drivers like the rtl8812AU. Fix for bad drivers like the rtl8812AU.
''' '''
Ifconfig.down(iface) Ip.down(iface)
Iwconfig.mode(iface, 'managed') Iw.mode(iface, 'managed')
Ifconfig.up(iface) Ip.up(iface)
# /sys/class/net/wlan0/type # /sys/class/net/wlan0/type
iface_type_path = os.path.join('/sys/class/net', iface, 'type') iface_type_path = os.path.join('/sys/class/net', iface, 'type')
@@ -182,17 +182,17 @@ class Airmon(Dependency):
if enabled_iface is None: if enabled_iface is None:
Color.pl('{R}failed{W}') 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 # Assert that there is an interface in monitor mode
if len(monitor_interfaces) == 0: if len(monitor_interfaces) == 0:
Color.pl('{R}failed{W}') 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 # Assert that the interface enabled by airmon-ng is in monitor mode
if enabled_iface not in monitor_interfaces: if enabled_iface not in monitor_interfaces:
Color.pl('{R}failed{W}') 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. # No errors found; the device 'enabled_iface' was put into Mode:Monitor.
Color.pl('{G}enabled {C}%s{W}' % enabled_iface) 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)''' '''Find the interface put into monitor mode (if any)'''
# airmon-ng output: (mac80211 monitor mode vif enabled for [phy10]wlan0 on [phy10]wlan0mon) # 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'): for line in airmon_output.split('\n'):
matches = enabled_re.match(line) matches = enabled_re.match(line)
@@ -216,20 +216,20 @@ class Airmon(Dependency):
@staticmethod @staticmethod
def stop(iface): 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() airmon_output = Process(['airmon-ng', 'stop', iface]).stdout()
(disabled_iface, enabled_iface) = Airmon._parse_airmon_stop(airmon_output) (disabled_iface, enabled_iface) = Airmon._parse_airmon_stop(airmon_output)
if not disabled_iface and iface in Airmon.BAD_DRIVERS: 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) disabled_iface = Airmon.stop_bad_driver(iface)
if disabled_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: 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) return (disabled_iface, enabled_iface)
@@ -278,7 +278,7 @@ class Airmon(Dependency):
Airmon.terminate_conflicting_processes() Airmon.terminate_conflicting_processes()
Color.p('\n{+} Looking for {C}wireless interfaces{W}...') 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: if len(monitor_interfaces) == 1:
# Assume we're using the device already in montior mode # Assume we're using the device already in montior mode
iface = monitor_interfaces[0] iface = monitor_interfaces[0]
@@ -359,6 +359,10 @@ class Airmon(Dependency):
# Can't just pkill network manager; it's a service # Can't just pkill network manager; it's a service
Process(['service', 'network-manager', 'stop']).wait() Process(['service', 'network-manager', 'stop']).wait()
Airmon.killed_network_manager = True 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: else:
Color.pl('{!} {R}Terminating {O}conflicting process {R}%s{O} (PID {R}%s{O})' % (pname, pid)) Color.pl('{!} {R}Terminating {O}conflicting process {R}%s{O} (PID {R}%s{O})' % (pname, pid))
try: try:
@@ -369,9 +373,9 @@ class Airmon(Dependency):
@staticmethod @staticmethod
def put_interface_up(iface): def put_interface_up(iface):
Color.p('{!} {O}putting interface {R}%s up{O}...' % (iface)) Color.p('{!}{W} Putting interface {R}%s{W} {G}up{W}...\n' % (iface))
Ifconfig.up(iface) Ip.up(iface)
Color.pl(' {G}done{W}') Color.pl('{+}{W} Done !')
@staticmethod @staticmethod
def start_network_manager(): 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}') Color.pl(' {R}cannot restart NetworkManager: {O}systemctl{R} or {O}service{R} not found{W}')
if __name__ == '__main__': 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() iface = Airmon.ask()
(disabled_iface, enabled_iface) = Airmon.stop(iface) (disabled_iface, enabled_iface) = Airmon.stop(iface)
print('Disabled:', disabled_iface) print('Disabled:', disabled_iface)

View File

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

View File

@@ -49,7 +49,12 @@ class Bully(Attack, Dependency):
'--bssid', target.bssid, '--bssid', target.bssid,
'--channel', target.channel, '--channel', target.channel,
#'--detectlock', # Detect WPS lockouts unreported by AP #'--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', '-v', '4',
Configuration.interface Configuration.interface
]) ])
@@ -129,7 +134,8 @@ class Bully(Attack, Dependency):
return return
else: else:
if self.locked and not Configuration.wps_ignore_lock: 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() self.stop()
return 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 @classmethod
def run_dependency_check(cls): def run_dependency_check(cls):
from ..util.color import Color from ..util.color import Color
@@ -22,8 +28,8 @@ class Dependency(object):
from .airodump import Airodump from .airodump import Airodump
from .aircrack import Aircrack from .aircrack import Aircrack
from .aireplay import Aireplay from .aireplay import Aireplay
from .ifconfig import Ifconfig from .ip import Ip
from .iwconfig import Iwconfig from .iw import Iw
from .bully import Bully from .bully import Bully
from .reaver import Reaver from .reaver import Reaver
from .wash import Wash from .wash import Wash
@@ -36,7 +42,7 @@ class Dependency(object):
# Aircrack # Aircrack
Aircrack, #Airodump, Airmon, Aireplay, Aircrack, #Airodump, Airmon, Aireplay,
# wireless/net tools # wireless/net tools
Iwconfig, Ifconfig, Iw, Ip,
# WPS # WPS
Reaver, Bully, Reaver, Bully,
# Cracking/handshakes # Cracking/handshakes

View File

@@ -5,17 +5,17 @@ import re
from .dependency import Dependency from .dependency import Dependency
class Ifconfig(Dependency): class Ip(Dependency):
dependency_required = True dependency_required = True
dependency_name = 'ifconfig' dependency_name = 'ip'
dependency_url = 'apt-get install net-tools' dependency_url = 'apt-get install ip'
@classmethod @classmethod
def up(cls, interface, args=[]): def up(cls, interface, args=[]):
'''Put interface up''' '''Put interface up'''
from ..util.process import Process from ..util.process import Process
command = ['ifconfig', interface] command = ['ip', 'link', 'set', interface]
if type(args) is list: if type(args) is list:
command.extend(args) command.extend(args)
elif type(args) is 'str': elif type(args) is 'str':
@@ -33,7 +33,7 @@ class Ifconfig(Dependency):
'''Put interface down''' '''Put interface down'''
from ..util.process import Process from ..util.process import Process
pid = Process(['ifconfig', interface, 'down']) pid = Process(['ip', 'link', 'set', interface, 'down'])
pid.wait() pid.wait()
if pid.poll() != 0: if pid.poll() != 0:
raise Exception('Error putting interface %s down:\n%s\n%s' % (interface, pid.stdout(), pid.stderr())) 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): def get_mac(cls, interface):
from ..util.process import Process from ..util.process import Process
output = Process(['ifconfig', interface]).stdout() output = Process(['ip', 'link show', interface]).stdout()
# Mac address separated by dashes match = re.search(r'([a-fA-F0-9]{2}[-:]){5}[a-fA-F0-9]{2}', output)
mac_dash_regex = ('[a-zA-Z0-9]{2}-' * 6)[:-1]
match = re.search(' ({})'.format(mac_dash_regex), output)
if match: if match:
return match.group(1).replace('-', ':') return match.group(0).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)
raise Exception('Could not find the mac address for %s' % interface) 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 -*- # -*- coding: utf-8 -*-
from .dependency import Dependency from .dependency import Dependency
from ..tools.ifconfig import Ifconfig from ..tools.ip import Ip
from ..util.color import Color from ..util.color import Color
class Macchanger(Dependency): class Macchanger(Dependency):
@@ -20,7 +20,7 @@ class Macchanger(Dependency):
Color.clear_entire_line() Color.clear_entire_line()
Color.p('\r{+} {C}macchanger{W}: taking interface {C}%s{W} down...' % iface) Color.p('\r{+} {C}macchanger{W}: taking interface {C}%s{W} down...' % iface)
Ifconfig.down(iface) Ip.down(iface)
Color.clear_entire_line() Color.clear_entire_line()
Color.p('\r{+} {C}macchanger{W}: changing mac address of interface {C}%s{W}...' % iface) 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.clear_entire_line()
Color.p('\r{+} {C}macchanger{W}: bringing interface {C}%s{W} up...' % iface) Color.p('\r{+} {C}macchanger{W}: bringing interface {C}%s{W} up...' % iface)
Ifconfig.up(iface) Ip.up(iface)
return True return True
@@ -56,7 +56,7 @@ class Macchanger(Dependency):
Color.pl('\r{+} {C}macchanger{W}: resetting mac address on %s...' % iface) Color.pl('\r{+} {C}macchanger{W}: resetting mac address on %s...' % iface)
# -p to reset to permanent MAC address # -p to reset to permanent MAC address
if cls.down_macch_up(iface, ['-p']): if cls.down_macch_up(iface, ['-p']):
new_mac = Ifconfig.get_mac(iface) new_mac = Ip.get_mac(iface)
Color.clear_entire_line() 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)) 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 # -e to keep vendor bytes the same
if cls.down_macch_up(iface, ['-e']): if cls.down_macch_up(iface, ['-e']):
cls.is_changed = True cls.is_changed = True
new_mac = Ifconfig.get_mac(iface) new_mac = Ip.get_mac(iface)
Color.clear_entire_line() Color.clear_entire_line()
Color.pl('\r{+} {C}macchanger{W}: changed mac address to {C}%s{W} on {C}%s{W}' % (new_mac, iface)) 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): def __init__(self):
pass pass
@staticmethod
def exists():
return Process.exists('pyrit')
@staticmethod @staticmethod
def bssid_essid_with_handshakes(capfile, bssid=None, essid=None): def bssid_essid_with_handshakes(capfile, bssid=None, essid=None):

View File

@@ -117,7 +117,7 @@ class Reaver(Attack, Dependency):
# Check if locked # Check if locked
if self.locked and not Configuration.wps_ignore_lock: 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) time.sleep(0.5)

View File

@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from .dependency import Dependency from .dependency import Dependency
from ..model.target import WPSState
from ..util.process import Process from ..util.process import Process
import re import re
@@ -14,9 +15,6 @@ class Tshark(Dependency):
def __init__(self): def __init__(self):
pass pass
@staticmethod
def exists():
return Process.exists('tshark')
@staticmethod @staticmethod
def _extract_src_dst_index_total(line): def _extract_src_dst_index_total(line):
@@ -29,6 +27,7 @@ class Tshark(Dependency):
(src, dst, index, total) = match.groups() (src, dst, index, total) = match.groups()
return src, dst, index, total return src, dst, index, total
@staticmethod @staticmethod
def _build_target_client_handshake_map(output, bssid=None): def _build_target_client_handshake_map(output, bssid=None):
# Map of target_ssid,client_ssid -> handshake #s # Map of target_ssid,client_ssid -> handshake #s
@@ -190,7 +189,6 @@ class Tshark(Dependency):
if ',' not in line: if ',' not in line:
continue continue
bssid, locked = line.split(',') bssid, locked = line.split(',')
# Ignore if WPS is locked?
if '1' not in locked: if '1' not in locked:
wps_bssids.add(bssid.upper()) wps_bssids.add(bssid.upper())
else: else:
@@ -199,11 +197,11 @@ class Tshark(Dependency):
for t in targets: for t in targets:
target_bssid = t.bssid.upper() target_bssid = t.bssid.upper()
if target_bssid in wps_bssids: if target_bssid in wps_bssids:
t.wps = True t.wps = WPSState.UNLOCKED
elif target_bssid in locked_bssids: elif target_bssid in locked_bssids:
t.wps = None t.wps = WPSState.LOCKED
else: else:
t.wps = False t.wps = WPSState.NONE
if __name__ == '__main__': if __name__ == '__main__':
@@ -226,7 +224,8 @@ if __name__ == '__main__':
# Should update 'wps' field of a target # Should update 'wps' field of a target
Tshark.check_for_wps_and_update_targets(test_file, targets) Tshark.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(
assert targets[0].wps == True targets[0].bssid, targets[0].wps))
assert targets[0].wps == WPSState.UNLOCKED
print(Tshark.bssids_with_handshakes(test_file, bssid=target_bssid)) print(Tshark.bssids_with_handshakes(test_file, bssid=target_bssid))

View File

@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from .dependency import Dependency from .dependency import Dependency
from ..model.target import WPSState
from ..util.process import Process from ..util.process import Process
import json import json
@@ -14,9 +15,6 @@ class Wash(Dependency):
def __init__(self): def __init__(self):
pass pass
@staticmethod
def exists():
return Process.exists('wash')
@staticmethod @staticmethod
def check_for_wps_and_update_targets(capfile, targets): def check_for_wps_and_update_targets(capfile, targets):
@@ -56,11 +54,12 @@ class Wash(Dependency):
for t in targets: for t in targets:
target_bssid = t.bssid.upper() target_bssid = t.bssid.upper()
if target_bssid in wps_bssids: if target_bssid in wps_bssids:
t.wps = True t.wps = WPSState.UNLOCKED
elif target_bssid in locked_bssids: elif target_bssid in locked_bssids:
t.wps = None t.wps = WPSState.LOCKED
else: else:
t.wps = False t.wps = WPSState.NONE
if __name__ == '__main__': if __name__ == '__main__':
test_file = './tests/files/contains_wps_network.cap' test_file = './tests/files/contains_wps_network.cap'
@@ -82,7 +81,8 @@ if __name__ == '__main__':
# Should update 'wps' field of a target # Should update 'wps' field of a target
Wash.check_for_wps_and_update_targets(test_file, targets) 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.''' '''Prints an exception. Includes stack trace if necessary.'''
Color.pl('\n{!} {R}Error: {O}%s' % str(exception)) 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 from ..config import Configuration
if Configuration.verbose > 0 or Configuration.print_stack_traces: if Configuration.verbose > 0 or Configuration.print_stack_traces:
Color.pl('\n{!} {O}Full stack trace below') 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.hashcat import Hashcat, HcxPcapTool
from ..tools.john import John from ..tools.john import John
from datetime import datetime from json import loads
import os import os
# TODO: Bring back the 'print' option, for easy copy/pasting. Just one-liners people can paste into terminal. # 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) # TODO: --no-crack option while attacking targets (implies user will run --crack later)
class CrackHelper: class CrackHelper:
@@ -32,7 +30,6 @@ class CrackHelper:
'PMKID': 'PMKID Hash' 'PMKID': 'PMKID Hash'
} }
@classmethod @classmethod
def run(cls): def run(cls):
Configuration.initialize(False) Configuration.initialize(False)
@@ -53,7 +50,7 @@ class CrackHelper:
return return
hs_to_crack = cls.get_user_selection(handshakes) 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. # Tools for cracking & their dependencies.
available_tools = { available_tools = {
@@ -79,26 +76,46 @@ class CrackHelper:
dep_list = ', '.join([dep.dependency_name for dep in deps]) dep_list = ', '.join([dep.dependency_name for dep in deps])
Color.pl(' {R}* {R}%s {W}({O}%s{W})' % (tool, dep_list)) 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}' % ( Color.p('\n{+} Enter the {C}cracking tool{W} to use ({C}%s{W}): {G}' % (
'{W}, {C}'.join(available_tools.keys()))) '{W}, {C}'.join(available_tools.keys())))
tool_name = raw_input() tool_name = raw_input()
if tool_name not in available_tools: if tool_name not in available_tools:
Color.pl('{!} {R}"%s"{O} tool not found, defaulting to {C}aircrack{W}' % tool_name) Color.pl('{!} {R}"%s"{O} tool not found, defaulting to {C}aircrack{W}' % tool_name)
tool_name = 'aircrack' tool_name = 'aircrack'
elif any_pmkid and tool_name != 'hashcat':
Color.pl('{!} {O}Note: PMKID hashes will be cracked using {C}hashcat{W}')
try: try:
for hs in hs_to_crack: 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) cls.crack(hs, tool_name)
except KeyboardInterrupt: except KeyboardInterrupt:
Color.pl('\n{!} {O}Interrupted{W}') 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 @classmethod
def get_handshakes(cls): def get_handshakes(cls):
handshakes = [] handshakes = []
skipped_pmkid_files = 0 skipped_pmkid_files = skipped_cracked_files = 0
hs_dir = Configuration.wpa_handshake_dir hs_dir = Configuration.wpa_handshake_dir
if not os.path.exists(hs_dir) or not os.path.isdir(hs_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: if hs_file.count('_') != 3:
continue continue
if cls.is_cracked(hs_file):
skipped_cracked_files += 1
continue
if hs_file.endswith('.cap'): if hs_file.endswith('.cap'):
# WPA Handshake # WPA Handshake
hs_type = '4-WAY' hs_type = '4-WAY'
@@ -148,7 +169,9 @@ class CrackHelper:
handshakes.append(handshake) handshakes.append(handshake)
if skipped_pmkid_files > 0: 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) # Sort by Date (Descending)
return sorted(handshakes, key=lambda x: x.get('date'), reverse=True) return sorted(handshakes, key=lambda x: x.get('date'), reverse=True)
@@ -158,7 +181,7 @@ class CrackHelper:
def print_handshakes(cls, handshakes): def print_handshakes(cls, handshakes):
# Header # Header
max_essid_len = max([len(hs['essid']) for hs in handshakes] + [len('ESSID (truncated)')]) 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(' ' + 'ESSID (truncated)'.ljust(max_essid_len))
Color.p(' ' + 'BSSID'.ljust(17)) Color.p(' ' + 'BSSID'.ljust(17))
Color.p(' ' + 'TYPE'.ljust(5)) Color.p(' ' + 'TYPE'.ljust(5))
@@ -170,8 +193,6 @@ class CrackHelper:
Color.p(' ' + ('-' * 19) + '{W}\n') Color.p(' ' + ('-' * 19) + '{W}\n')
# Handshakes # Handshakes
for index, handshake in enumerate(handshakes, start=1): 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(' {G}%s{W}' % str(index).rjust(3))
Color.p(' {C}%s{W}' % handshake['essid'].ljust(max_essid_len)) Color.p(' {C}%s{W}' % handshake['essid'].ljust(max_essid_len))
Color.p(' {O}%s{W}' % handshake['bssid'].ljust(17)) Color.p(' {O}%s{W}' % handshake['bssid'].ljust(17))
@@ -253,7 +274,10 @@ class CrackHelper:
@classmethod @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) key = Hashcat.crack_pmkid(hs['filename'], verbose=True)
if key is not None: if key is not None:

View File

@@ -4,7 +4,7 @@
from ..util.color import Color from ..util.color import Color
from ..tools.airodump import Airodump from ..tools.airodump import Airodump
from ..util.input import raw_input, xrange from ..util.input import raw_input, xrange
from ..model.target import Target from ..model.target import Target, WPSState
from ..config import Configuration from ..config import Configuration
from time import sleep, time from time import sleep, time
@@ -88,7 +88,7 @@ class Scanner(object):
return False # No specific target from user. return False # No specific target from user.
for target in self.targets: 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 continue
if bssid and target.bssid and bssid.lower() == target.bssid.lower(): if bssid and target.bssid and bssid.lower() == target.bssid.lower():
self.target = target self.target = target