6 Commits
2.2.1 ... 2.2.2

Author SHA1 Message Date
derv82
04e67dba21 2.2.2: Version bump for --crack improvements. Fix wordlists.
Finally clears up #102.
2018-08-21 14:02:54 -07:00
derv82
f641ea53c4 Fix but when cracking with John, small fixes.
* --crack commands printed consistently (same color/format).
* Only warn about PMKID -> hashcat once if any selected handshakes are PMKIDs
2018-08-21 13:55:22 -07:00
derv82
d01470a8e4 Bringing back Wifite.py
Because why not.
2018-08-21 00:16:15 -07:00
derv82
dd0e44cf53 --crack: Dependency management, avoid dupes in cracked.txt
* Dupes are skipped if everything *except* date matches (same bssid/ssid/type/key)
* John: Detect and use OpenCL or CUDA using `john --list=formats`
* Removed `wifite.py` as it's no longer used & is confusing.
2018-08-21 00:04:21 -07:00
derv82
4173ef46e5 --crack supports hashcat, aircrack, john, cowpatty, and pyrit.
* Still not "print" option for --crack.
* Checks hashcat for devices, uses --force if no devices are found.
* Interrupting --crack stops entire process, not just a single crack attempt
* Changed wordlist location, hopefully completes #102.
2018-08-20 19:33:42 -07:00
derv82
a063f08388 Updating README
Moved things around, added more info, added links to required tools.
2018-08-20 11:44:10 -07:00
14 changed files with 499 additions and 321 deletions

171
README.md
View File

@@ -1,18 +1,70 @@
Wifite 2 Wifite
======== ======
A complete re-write of [`wifite`](https://github.com/derv82/wifite), a Python script for auditing wireless networks. This repo is a complete re-write of [`wifite`](https://github.com/derv82/wifite), a Python script for auditing wireless networks.
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!
This version is compatible with both `python2` and `python3`. Wifite is compatible with both `python2` and `python3`.
Installation 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.
4. WEP: Various known attacks against WEP, including *fragmentation*, *chop-chop*, *aireplay*, etc.
From the root directory of this package: Run wifite, select your targets, and Wifite will automatically start trying to capture or crack the password.
Run *wifite* using: `python -m wifite` 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*.
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.
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.
* [`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.
* [`aircrack-ng`](https://tools.kali.org/wireless-attacks/aircrack-ng): For cracking WEP .cap files and WPA handshake captures.
* [`aireplay-ng`](https://tools.kali.org/wireless-attacks/aireplay-ng): For deauthing access points, replaying capture files, various WEP attacks.
* [`airodump-ng`](https://tools.kali.org/wireless-attacks/airodump-ng): For target scanning & capture file generation.
* [`packetforge-ng`](https://tools.kali.org/wireless-attacks/packetforge-ng): For forging capture files.
**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.
* 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.
* 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.
* [`pyrit`](https://github.com/JPaulMora/Pyrit): For detecting handshake captures.
* [`hashcat`](https://hashcat.net/): For cracking 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.
Run Wifite
----------
```
git clone https://github.com/derv82/wifite2.git
cd wifite2
python -m 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:
@@ -20,18 +72,37 @@ To install onto your computer (so you can just run `wifite` from any terminal),
sudo python setup.py install sudo python setup.py install
``` ```
---- This will install `wifite` to `/usr/sbin/wifite` which should be in your terminal path.
Note: Uninstalling is [not as easy](https://stackoverflow.com/questions/1550226/python-setup-py-uninstall#1550235). The only way to uninstall is to record the files installed by the above command and *remove* those files: **Note:** Uninstalling is [not as easy](https://stackoverflow.com/questions/1550226/python-setup-py-uninstall#1550235). The only way to uninstall is to record the files installed by the above command and *remove* those files:
```bash ```bash
sudo python setup.py install --record files.txt sudo python setup.py install --record files.txt \
cat files.txt | xargs sudo rm -f && cat files.txt | xargs sudo rm \
sudo rm -f files.txt && rm -f files.txt
``` ```
What's new in Wifite2? 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`)
* 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
* 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.
* 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** * **Less bugs**
* Cleaner process management. Does not leave processes running in the background (the old `wifite` was bad about this). * Cleaner process management. Does not leave processes running in the background (the old `wifite` was bad about this).
@@ -44,17 +115,18 @@ What's new in Wifite2?
* **Educational** * **Educational**
* The `--verbose` option (expandable to `-vv` or `-vvv`) shows which commands are executed & the output of those commands. * The `--verbose` option (expandable to `-vv` or `-vvv`) shows which commands are executed & the output of those commands.
* This can help debug why Wifite is not working for you. Or so you can learn how these tools are used. * This can help debug why Wifite is not working for you. Or so you can learn how these tools are used.
* Actively developed (as of March 2018). * More-actively developed.
* Python 3 support. * Python 3 support.
* Sweet new ASCII banner. * Sweet new ASCII banner.
What's gone in Wifite2? What's gone?
----------------------- ------------
* No more WPS PIN attack, because it can take days on-average. * No more WPS PIN attack, because it can take days on-average.
* However, the Pixie-Dust attack is still an option. * 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, try `./Wifite.py -h -v` * You can still access some of these obscure options, try `wifite -h -v`
What's not new? What's not new?
--------------- ---------------
@@ -62,65 +134,6 @@ 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.
Brief Feature List
------------------
* Reaver (or `-bully`) Pixie-Dust attack (enabled by-default, force with: `--wps-only`)
* WPA 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
* 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.
* Provides commands to crack captured WPA handshakes (`--crack`)
* Includes all commands needed to crack using `aircrack-ng`, `john`, `hashcat`, or `pyrit`.
Linux Distribution Support
--------------------------
Wifite2 is designed specifically for the latest version of **Kali**'s rolling release (tested on Kali 2017.2, updated Jan 2018).
Other pen-testing distributions (such as BackBox) have outdated versions of the tools used by Wifite; these distributions are not supported.
Required Tools
--------------
Only the latest versions of these programs are supported:
**Required:**
* `iwconfig`: For identifying wireless devices already in Monitor Mode.
* `ifconfig`: For starting/stopping wireless devices.
* `Aircrack-ng` suite, includes:
* `aircrack-ng`: For cracking WEP .cap files and WPA handshake captures.
* `aireplay-ng`: For deauthing access points, replaying capture files, various WEP attacks.
* `airmon-ng`: For enumerating and enabling Monitor Mode on wireless devices.
* `airodump-ng`: For target scanning & capture file generation.
* `packetforge-ng`: For forging capture files.
**Optional, but Recommended:**
* `tshark`: For detecting WPS networks and inspecting handshake capture files.
* `reaver`: For WPS Pixie-Dust attacks.
* Note: Reaver's `wash` tool can be used to detect WPS networks if `tshark` is not found.
* `bully`: For WPS Pixie-Dust 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`: For detecting handshake captures.
* `pyrit`: For detecting handshake captures.
Installing & Running
--------------------
```
git clone https://github.com/derv82/wifite2.git
cd wifite2
./Wifite.py
```
Screenshots Screenshots
----------- -----------

7
Wifite.py Executable file
View File

@@ -0,0 +1,7 @@
#!/usr/bin/env python
# Note: This script runs Wifite from within a cloned git repo.
# The script `bin/wifite` is designed to be run after installing (from /usr/sbin), not from the cwd.
from wifite import __main__
__main__.entry_point()

View File

@@ -97,7 +97,12 @@ class AttackPMKID(Attack):
return False # No hash found. return False # No hash found.
# Crack it. # Crack it.
try:
self.success = self.crack_pmkid_file(pmkid_file) self.success = self.crack_pmkid_file(pmkid_file)
except KeyboardInterrupt:
Color.pl('\n{!} {R}Failed to crack PMKID: {O}Cracking interrupted by user{W}')
self.success = False
return False
return True # Even if we don't crack it, capturing a PMKID is 'successful' return True # Even if we don't crack it, capturing a PMKID is 'successful'

View File

@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from ..model.attack import Attack from ..model.attack import Attack
from ..tools.aircrack import Aircrack
from ..tools.airodump import Airodump from ..tools.airodump import Airodump
from ..tools.aireplay import Aireplay from ..tools.aireplay import Aireplay
from ..config import Configuration from ..config import Configuration
@@ -47,11 +48,29 @@ class AttackWPA(Attack):
Color.pl('\n{+} analysis of captured handshake file:') Color.pl('\n{+} analysis of captured handshake file:')
handshake.analyze() handshake.analyze()
# Check wordlist
if Configuration.wordlist is None:
Color.pl('{!} {O}Not cracking handshake because' +
' wordlist ({R}--dict{O}) is not set')
self.success = False
return False
elif not os.path.exists(Configuration.wordlist):
Color.pl('{!} {O}Not cracking handshake because' +
' wordlist {R}%s{O} was not found' % Configuration.wordlist)
self.success = False
return False
Color.pl('\n{+} {C}Cracking WPA Handshake:{W} Running {C}aircrack-ng{W} with' +
' {C}%s{W} wordlist' % os.path.split(Configuration.wordlist)[-1])
# Crack it # Crack it
key = self.crack_handshake(handshake, Configuration.wordlist) key = Aircrack.crack_handshake(handshake, show_command=False)
if key is None: if key is None:
Color.pl('{!} {R}Failed to crack handshake: {O}%s{R} did not contain password{W}' % Configuration.wordlist.split(os.sep)[-1])
self.success = False self.success = False
else: else:
Color.pl('{+} {G}Cracked WPA Handshake{W} PSK: {G}%s{W}\n' % key)
self.crack_result = CrackResultWPA(handshake.bssid, handshake.essid, handshake.capfile, key) self.crack_result = CrackResultWPA(handshake.bssid, handshake.essid, handshake.capfile, key)
self.crack_result.dump() self.crack_result.dump()
self.success = True self.success = True
@@ -157,84 +176,6 @@ class AttackWPA(Attack):
self.save_handshake(handshake) self.save_handshake(handshake)
return handshake return handshake
@staticmethod
def crack_handshake(handshake, wordlist, verbose=False):
'''Tries to crack a handshake. Returns WPA key if found, otherwise None.'''
if wordlist is None:
Color.pl('{!} {O}Not cracking handshake because' +
' wordlist ({R}--dict{O}) is not set')
return None
elif not os.path.exists(wordlist):
Color.pl('{!} {O}Not cracking handshake because' +
' wordlist {R}%s{O} was not found' % wordlist)
return None
if not verbose:
Color.pl('\n{+} {C}Cracking WPA Handshake:{W} Using {C}aircrack-ng{W} via' +
' {C}%s{W} wordlist' % os.path.split(wordlist)[-1])
key_file = Configuration.temp('wpakey.txt')
command = [
'aircrack-ng',
'-a', '2',
'-w', wordlist,
'--bssid', handshake.bssid,
'-l', key_file,
handshake.capfile
]
if verbose:
Color.pl('{+} {D}Running: {W}{P}%s{W}' % ' '.join(command))
crack_proc = Process(command)
# Report progress of cracking
aircrack_nums_re = re.compile(r'(\d+)/(\d+) keys tested.*\(([\d.]+)\s+k/s')
aircrack_key_re = re.compile(r'Current passphrase:\s*([^\s].*[^\s])\s*$')
num_tried = num_total = 0
percent = num_kps = 0.0
eta_str = 'unknown'
current_key = ''
while crack_proc.poll() is None:
line = crack_proc.pid.stdout.readline()
match_nums = aircrack_nums_re.search(line.decode('utf-8'))
match_keys = aircrack_key_re.search(line.decode('utf-8'))
if match_nums:
num_tried = int(match_nums.group(1))
num_total = int(match_nums.group(2))
num_kps = float(match_nums.group(3))
eta_seconds = (num_total - num_tried) / num_kps
eta_str = Timer.secs_to_str(eta_seconds)
percent = 100.0 * float(num_tried) / float(num_total)
elif match_keys:
current_key = match_keys.group(1)
else:
continue
status = '\r{+} {C}Cracking WPA Handshake: %0.2f%%{W}' % percent
status += ' ETA: {C}%s{W}' % eta_str
status += ' @ {C}%0.1fkps{W}' % num_kps
#status += ' ({C}%d{W}/{C}%d{W} keys)' % (num_tried, num_total)
status += ' (current key: {C}%s{W})' % current_key
if not verbose:
Color.clear_entire_line()
Color.p(status)
if not verbose:
Color.pl('')
# Check crack result
if os.path.exists(key_file):
with open(key_file, 'r') as fid:
key = fid.read().strip()
os.remove(key_file)
if not verbose:
Color.pl('{+} {G}Cracked WPA Handshake{W} PSK: {G}%s{W}\n' % key)
return key
else:
if not verbose:
Color.pl('{!} {R}Failed to crack handshake: {O}%s{R} did not contain password{W}' % wordlist.split(os.sep)[-1])
return None
def load_handshake(self, bssid, essid): def load_handshake(self, bssid, essid):
if not os.path.exists(Configuration.wpa_handshake_dir): if not os.path.exists(Configuration.wpa_handshake_dir):
return None return None

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.1' version = '2.2.2'
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
@@ -84,9 +84,10 @@ class Configuration(object):
# Default dictionary for cracking # Default dictionary for cracking
cls.wordlist = None cls.wordlist = None
wordlists = [ wordlists = [
'./wordlist-top4800-probable.txt', './wordlist-top4800-probable.txt', # Local file (ran from cloned repo)
'/usr/share/wordlists/wordlist-top4800-probable.txt', '/usr/share/dict/wordlist-top4800-probable.txt', # setup.py with prefix=/usr
'/usr/local/share/wordlists/wordlist-top4800-probable.txt', '/usr/local/share/dict/wordlist-top4800-probable.txt', # setup.py with prefix=/usr/local
# Other passwords found on Kali
'/usr/share/wfuzz/wordlist/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt', '/usr/share/wfuzz/wordlist/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt',
'/usr/share/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt', '/usr/share/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt',
'/usr/share/wordlists/fern-wifi/common.txt' '/usr/share/wordlists/fern-wifi/common.txt'

View File

@@ -38,7 +38,7 @@ class Handshake(object):
if len(pairs) == 0 and not self.bssid and not self.essid: if len(pairs) == 0 and not self.bssid and not self.essid:
# Tshark and Pyrit failed us, nothing else we can do. # Tshark and Pyrit failed us, nothing else we can do.
raise Exception('Cannot find BSSID or ESSID in cap file') raise ValueError('Cannot find BSSID or ESSID in cap file %s' % self.capfile)
if not self.essid and not self.bssid: if not self.essid and not self.bssid:
# We do not know the bssid nor the essid # We do not know the bssid nor the essid

View File

@@ -39,19 +39,31 @@ class CrackResult(object):
def save(self): def save(self):
''' Adds this crack result to the cracked file and saves it. ''' ''' Adds this crack result to the cracked file and saves it. '''
name = CrackResult.cracked_file name = CrackResult.cracked_file
json = [] saved_results = []
if os.path.exists(name): if os.path.exists(name):
with open(name, 'r') as fid: with open(name, 'r') as fid:
text = fid.read() text = fid.read()
try: try:
json = loads(text) saved_results = loads(text)
except Exception as e: except Exception as e:
Color.pl('{!} error while loading %s: %s' % (name, str(e))) Color.pl('{!} error while loading %s: %s' % (name, str(e)))
json.append(self.to_dict())
# Check for duplicates
this_dict = self.to_dict()
this_dict.pop('date')
for entry in saved_results:
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))
return
saved_results.append(self.to_dict())
with open(name, 'w') as fid: with open(name, 'w') as fid:
fid.write(dumps(json, indent=2)) fid.write(dumps(saved_results, indent=2))
Color.pl('{+} saved crack result to {C}%s{W} ({G}%d total{W})' Color.pl('{+} saved crack result to {C}%s{W} ({G}%d total{W})'
% (name, len(json))) % (name, len(saved_results)))
@classmethod @classmethod
def display(cls): def display(cls):

View File

@@ -7,6 +7,7 @@ from ..util.input import xrange
from ..config import Configuration from ..config import Configuration
import os import os
import re
class Aircrack(Dependency): class Aircrack(Dependency):
dependency_required = True dependency_required = True
@@ -77,6 +78,70 @@ class Aircrack(Dependency):
if os.path.exists(self.cracked_file): if os.path.exists(self.cracked_file):
os.remove(self.cracked_file) os.remove(self.cracked_file)
@staticmethod
def crack_handshake(handshake, show_command=False):
from ..util.color import Color
from ..util.timer import Timer
'''Tries to crack a handshake. Returns WPA key if found, otherwise None.'''
key_file = Configuration.temp('wpakey.txt')
command = [
'aircrack-ng',
'-a', '2',
'-w', Configuration.wordlist,
'--bssid', handshake.bssid,
'-l', key_file,
handshake.capfile
]
if show_command:
Color.pl('{+} {D}Running: {W}{P}%s{W}' % ' '.join(command))
crack_proc = Process(command)
# Report progress of cracking
aircrack_nums_re = re.compile(r'(\d+)/(\d+) keys tested.*\(([\d.]+)\s+k/s')
aircrack_key_re = re.compile(r'Current passphrase:\s*([^\s].*[^\s])\s*$')
num_tried = num_total = 0
percent = num_kps = 0.0
eta_str = 'unknown'
current_key = ''
while crack_proc.poll() is None:
line = crack_proc.pid.stdout.readline()
match_nums = aircrack_nums_re.search(line.decode('utf-8'))
match_keys = aircrack_key_re.search(line.decode('utf-8'))
if match_nums:
num_tried = int(match_nums.group(1))
num_total = int(match_nums.group(2))
num_kps = float(match_nums.group(3))
eta_seconds = (num_total - num_tried) / num_kps
eta_str = Timer.secs_to_str(eta_seconds)
percent = 100.0 * float(num_tried) / float(num_total)
elif match_keys:
current_key = match_keys.group(1)
else:
continue
status = '\r{+} {C}Cracking WPA Handshake: %0.2f%%{W}' % percent
status += ' ETA: {C}%s{W}' % eta_str
status += ' @ {C}%0.1fkps{W}' % num_kps
#status += ' ({C}%d{W}/{C}%d{W} keys)' % (num_tried, num_total)
status += ' (current key: {C}%s{W})' % current_key
Color.clear_entire_line()
Color.p(status)
Color.pl('')
# Check crack result
if os.path.exists(key_file):
with open(key_file, 'r') as fid:
key = fid.read().strip()
os.remove(key_file)
return key
else:
return None
if __name__ == '__main__': if __name__ == '__main__':
(hexkey, asciikey) = Aircrack._hex_and_ascii_key('A1B1C1D1E1') (hexkey, asciikey) = Aircrack._hex_and_ascii_key('A1B1C1D1E1')
assert hexkey == 'A1:B1:C1:D1:E1', 'hexkey was "%s", expected "A1:B1:C1:D1:E1"' % hexkey assert hexkey == 'A1:B1:C1:D1:E1', 'hexkey was "%s", expected "A1:B1:C1:D1:E1"' % hexkey

41
wifite/tools/cowpatty.py Normal file
View File

@@ -0,0 +1,41 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from .dependency import Dependency
from ..config import Configuration
from ..util.color import Color
from ..util.process import Process
from ..tools.hashcat import HcxPcapTool
import os
import re
class Cowpatty(Dependency):
''' Wrapper for Cowpatty program. '''
dependency_required = False
dependency_name = 'cowpatty'
dependency_url = 'https://tools.kali.org/wireless-attacks/cowpatty'
@staticmethod
def crack_handshake(handshake, show_command=False):
# Crack john file
command = [
'cowpatty',
'-f', Configuration.wordlist,
'-r', handshake.capfile,
'-s', handshake.essid
]
if show_command:
Color.pl('{+} {D}Running: {W}{P}%s{W}' % ' '.join(command))
process = Process(command)
stdout, stderr = process.get_output()
key = None
for line in stdout.split('\n'):
if 'The PSK is "' in line:
key = line.split('"', 1)[1][:-2]
break
return key

View File

@@ -14,6 +14,47 @@ class Hashcat(Dependency):
dependency_name = 'hashcat' dependency_name = 'hashcat'
dependency_url = 'https://hashcat.net/hashcat/' dependency_url = 'https://hashcat.net/hashcat/'
@staticmethod
def should_use_force():
command = ['hashcat', '-I']
stderr = Process(command).stderr()
return 'No devices found/left' in stderr
@staticmethod
def crack_handshake(handshake, show_command=False):
# Generate hccapx
hccapx_file = HcxPcapTool.generate_hccapx_file(
handshake, show_command=show_command)
key = None
# Crack hccapx
for additional_arg in [ [], ['--show']]:
command = [
'hashcat',
'--quiet',
'-m', '2500',
hccapx_file,
Configuration.wordlist
]
if Hashcat.should_use_force():
command.append('--force')
command.extend(additional_arg)
if show_command:
Color.pl('{+} {D}Running: {W}{P}%s{W}' % ' '.join(command))
process = Process(command)
stdout, stderr = process.get_output()
if ':' not in stdout:
continue
else:
key = stdout.split(':', 5)[-1].strip()
break
if os.path.exists(hccapx_file):
os.remove(hccapx_file)
return key
@staticmethod @staticmethod
def crack_pmkid(pmkid_file, verbose=False): def crack_pmkid(pmkid_file, verbose=False):
''' '''
@@ -27,27 +68,23 @@ class Hashcat(Dependency):
for additional_arg in [ [], ['--show']]: for additional_arg in [ [], ['--show']]:
command = [ command = [
'hashcat', 'hashcat',
'--force',
'--quiet', # Only output the password if found. '--quiet', # Only output the password if found.
'-m', '16800', # WPA-PMKID-PBKDF2 '-m', '16800', # WPA-PMKID-PBKDF2
'-a', '0', # TODO: Configure '-a', '0', # Wordlist attack-mode
'-w', '2', # TODO: Configure
pmkid_file, pmkid_file,
Configuration.wordlist Configuration.wordlist
] ]
if Hashcat.should_use_force():
command.append('--force')
command.extend(additional_arg) command.extend(additional_arg)
if verbose and additional_arg == []: if verbose and additional_arg == []:
Color.pl('{+} {D}Running: {W}{P}%s{W}' % ' '.join(command)) Color.pl('{+} {D}Running: {W}{P}%s{W}' % ' '.join(command))
# TODO: Check status of hashcat (%); it's impossible with --quiet # TODO: Check status of hashcat (%); it's impossible with --quiet
try:
hashcat_proc = Process(command) hashcat_proc = Process(command)
hashcat_proc.wait() hashcat_proc.wait()
stdout = hashcat_proc.stdout() stdout = hashcat_proc.stdout()
except KeyboardInterrupt: # In case user gets impatient
Color.pl('\n{!} {O}Interrupted hashcat cracking{W}')
stdout = ''
if ':' not in stdout: if ':' not in stdout:
# Failed # Failed
@@ -100,6 +137,52 @@ class HcxPcapTool(Dependency):
self.bssid = self.target.bssid.lower().replace(':', '') self.bssid = self.target.bssid.lower().replace(':', '')
self.pmkid_file = Configuration.temp('pmkid-%s.16800' % self.bssid) self.pmkid_file = Configuration.temp('pmkid-%s.16800' % self.bssid)
@staticmethod
def generate_hccapx_file(handshake, show_command=False):
hccapx_file = Configuration.temp('generated.hccapx')
if os.path.exists(hccapx_file):
os.remove(hccapx_file)
command = [
'hcxpcaptool',
'-o', hccapx_file,
handshake.capfile
]
if show_command:
Color.pl('{+} {D}Running: {W}{P}%s{W}' % ' '.join(command))
process = Process(command)
stdout, stderr = process.get_output()
if not os.path.exists(hccapx_file):
raise ValueError('Failed to generate .hccapx file, output: \n%s\n%s' % (
stdout, stderr))
return hccapx_file
@staticmethod
def generate_john_file(handshake, show_command=False):
john_file = Configuration.temp('generated.john')
if os.path.exists(john_file):
os.remove(john_file)
command = [
'hcxpcaptool',
'-j', john_file,
handshake.capfile
]
if show_command:
Color.pl('{+} {D}Running: {W}{P}%s{W}' % ' '.join(command))
process = Process(command)
stdout, stderr = process.get_output()
if not os.path.exists(john_file):
raise ValueError('Failed to generate .john file, output: \n%s\n%s' % (
stdout, stderr))
return john_file
def get_pmkid_hash(self, pcapng_file): def get_pmkid_hash(self, pcapng_file):
if os.path.exists(self.pmkid_file): if os.path.exists(self.pmkid_file):
os.remove(self.pmkid_file) os.remove(self.pmkid_file)

65
wifite/tools/john.py Normal file
View File

@@ -0,0 +1,65 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from .dependency import Dependency
from ..config import Configuration
from ..util.color import Color
from ..util.process import Process
from ..tools.hashcat import HcxPcapTool
import os
class John(Dependency):
''' Wrapper for John program. '''
dependency_required = False
dependency_name = 'john'
dependency_url = 'http://www.openwall.com/john/'
@staticmethod
def crack_handshake(handshake, show_command=False):
john_file = HcxPcapTool.generate_john_file(handshake, show_command=show_command)
# Use `john --list=formats` to find if OpenCL or CUDA is supported.
formats_stdout = Process(['john', '--list=formats']).stdout()
if 'wpapsk-opencl' in formats_stdout:
john_format = 'wpapsk-opencl'
elif 'wpapsk-cuda' in formats_stdout:
john_format = 'wpapsk-cuda'
else:
john_format = 'wpapsk'
# Crack john file
command = [
'john',
'--format=%s' % john_format,
'--wordlist', Configuration.wordlist,
john_file
]
if show_command:
Color.pl('{+} {D}Running: {W}{P}%s{W}' % ' '.join(command))
process = Process(command)
process.wait()
# Run again with --show to consistently get the password
command = ['john', '--show', john_file]
if show_command:
Color.pl('{+} {D}Running: {W}{P}%s{W}' % ' '.join(command))
process = Process(command)
stdout, stderr = process.get_output()
# Parse password (regex doesn't work for some reason)
if '0 password hashes cracked' in stdout:
key = None
else:
for line in stdout.split('\n'):
if handshake.capfile in line:
key = line.split(':')[1]
break
if os.path.exists(john_file):
os.remove(john_file)
return key

View File

@@ -1,10 +1,17 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from ..config import Configuration
from ..model.handshake import Handshake
from ..model.wpa_result import CrackResultWPA
from ..model.pmkid_result import CrackResultPMKID
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
from ..config import Configuration from ..tools.aircrack import Aircrack
from ..tools.cowpatty import Cowpatty
from ..tools.hashcat import Hashcat, HcxPcapTool
from ..tools.john import John
from datetime import datetime from datetime import datetime
@@ -15,12 +22,14 @@ import os
# TODO: Do not show handshake files that are in cracked.txt with a key (match on filename). # 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: class CrackHelper:
'''Manages handshake retrieval, selection, and running the cracking commands.''' '''Manages handshake retrieval, selection, and running the cracking commands.'''
TYPES = { TYPES = {
'4-WAY': 'WPA 4-Way Handshake', '4-WAY': '4-Way Handshake',
'PMKID': 'WPA PKID Hash' 'PMKID': 'PMKID Hash'
} }
@@ -28,6 +37,7 @@ class CrackHelper:
def run(cls): def run(cls):
Configuration.initialize(False) Configuration.initialize(False)
# Get wordlist
if not Configuration.wordlist: if not Configuration.wordlist:
Color.p('\n{+} Enter wordlist file to use for cracking: {G}') Color.p('\n{+} Enter wordlist file to use for cracking: {G}')
Configuration.wordlist = raw_input() Configuration.wordlist = raw_input()
@@ -36,16 +46,53 @@ class CrackHelper:
return return
Color.pl('') Color.pl('')
# Get handshakes
handshakes = cls.get_handshakes() handshakes = cls.get_handshakes()
if len(handshakes) == 0: if len(handshakes) == 0:
Color.pl('{!} {O}No handshakes found{W}') Color.pl('{!} {O}No handshakes found{W}')
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])
# TODO: Ask what method to use for WPA (aircrack, pyrit, john, hashcat, cowpatty) # Tools for cracking & their dependencies.
available_tools = {
'aircrack': [Aircrack],
'hashcat': [Hashcat, HcxPcapTool],
'john': [John, HcxPcapTool],
'cowpatty': [Cowpatty]
}
# Identify missing tools
missing_tools = []
for tool, dependencies in available_tools.items():
missing = [
dep for dep in dependencies
if not Process.exists(dep.dependency_name)
]
if len(missing) > 0:
available_tools.pop(tool)
missing_tools.append( (tool, missing) )
if len(missing_tools) > 0:
Color.pl('\n{!} {O}Unavailable tools (install to enable):{W}')
for tool, deps in missing_tools:
dep_list = ', '.join([dep.dependency_name for dep in deps])
Color.pl(' {R}* {R}%s {W}({O}%s{W})' % (tool, dep_list))
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: for hs in hs_to_crack:
cls.crack(hs) cls.crack(hs, tool_name)
except KeyboardInterrupt:
Color.pl('\n{!} {O}Interrupted{W}')
@classmethod @classmethod
def get_handshakes(cls): def get_handshakes(cls):
@@ -58,7 +105,7 @@ class CrackHelper:
Color.pl('\n{!} {O}directory not found: {R}%s{W}' % hs_dir) Color.pl('\n{!} {O}directory not found: {R}%s{W}' % hs_dir)
return [] return []
Color.pl('\n{+} Listing captured handshakes from {C}%s{W} ...\n' % os.path.abspath(hs_dir)) Color.pl('\n{+} Listing captured handshakes from {C}%s{W}:\n' % os.path.abspath(hs_dir))
for hs_file in os.listdir(hs_dir): for hs_file in os.listdir(hs_dir):
if hs_file.count('_') != 3: if hs_file.count('_') != 3:
continue continue
@@ -119,7 +166,7 @@ class CrackHelper:
Color.p(' ---') Color.p(' ---')
Color.p(' ' + ('-' * max_essid_len)) Color.p(' ' + ('-' * max_essid_len))
Color.p(' ' + ('-' * 17)) Color.p(' ' + ('-' * 17))
Color.p(' ' + ('-' * 6)) Color.p(' ' + ('-' * 5))
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):
@@ -136,7 +183,7 @@ class CrackHelper:
def get_user_selection(cls, handshakes): def get_user_selection(cls, handshakes):
cls.print_handshakes(handshakes) cls.print_handshakes(handshakes)
Color.p('{+} Select handshake(s) to crack ({G}%d{W}-{G}%d{W}, select multiple with {C},{W} or {C}-{W}): {G}' % (1, len(handshakes))) Color.p('{+} Select handshake(s) to crack ({G}%d{W}-{G}%d{W}, select multiple with {C},{W} or {C}-{W} or {C}all{W}): {G}' % (1, len(handshakes)))
choices = raw_input() choices = raw_input()
selection = [] selection = []
@@ -145,7 +192,10 @@ class CrackHelper:
first, last = [int(x) for x in choice.split('-')] first, last = [int(x) for x in choice.split('-')]
for index in range(first, last + 1): for index in range(first, last + 1):
selection.append(handshakes[index-1]) selection.append(handshakes[index-1])
else: elif choice.strip().lower() == 'all':
selection = handshakes[:]
break
elif [c.isdigit() for c in choice]:
index = int(choice) index = int(choice)
selection.append(handshakes[index-1]) selection.append(handshakes[index-1])
@@ -153,12 +203,14 @@ class CrackHelper:
@classmethod @classmethod
def crack(cls, hs): def crack(cls, hs, tool):
Color.pl('\n{+} Cracking {C}%s{W} ({C}%s{W}) using {G}%s{W} method' % (hs['essid'], hs['bssid'], hs['type'])) Color.pl('\n{+} Cracking {G}%s {C}%s{W} ({C}%s{W})' % (
cls.TYPES[hs['type']], hs['essid'], hs['bssid']))
if hs['type'] == 'PMKID': if hs['type'] == 'PMKID':
crack_result = cls.crack_pmkid(hs) crack_result = cls.crack_pmkid(hs, tool)
elif hs['type'] == '4-WAY': elif hs['type'] == '4-WAY':
crack_result = cls.crack_4way(hs) crack_result = cls.crack_4way(hs, tool)
else: else:
raise ValueError('Cannot crack handshake: Type is not PMKID or 4-WAY. Handshake=%s' % hs) raise ValueError('Cannot crack handshake: Type is not PMKID or 4-WAY. Handshake=%s' % hs)
@@ -174,20 +226,25 @@ class CrackHelper:
@classmethod @classmethod
def crack_4way(cls, hs): def crack_4way(cls, hs, tool):
from ..attack.wpa import AttackWPA
from ..model.handshake import Handshake
from ..model.wpa_result import CrackResultWPA
handshake = Handshake(hs['filename'], handshake = Handshake(hs['filename'],
bssid=hs['bssid'], bssid=hs['bssid'],
essid=hs['essid']) essid=hs['essid'])
key = None
try: try:
key = AttackWPA.crack_handshake(handshake, Configuration.wordlist, verbose=True) handshake.divine_bssid_and_essid()
except KeyboardInterrupt: except ValueError as e:
Color.pl('\n{!} Interrupted') Color.pl('{!} {R}Error: {O}%s{W}' % e)
return None
if tool == 'aircrack':
key = Aircrack.crack_handshake(handshake, show_command=True)
elif tool == 'hashcat':
key = Hashcat.crack_handshake(handshake, show_command=True)
elif tool == 'john':
key = John.crack_handshake(handshake, show_command=True)
elif tool == 'cowpatty':
key = Cowpatty.crack_handshake(handshake, show_command=True)
if key is not None: if key is not None:
return CrackResultWPA(hs['bssid'], hs['essid'], hs['filename'], key) return CrackResultWPA(hs['bssid'], hs['essid'], hs['filename'], key)
@@ -196,15 +253,8 @@ class CrackHelper:
@classmethod @classmethod
def crack_pmkid(cls, hs): def crack_pmkid(cls, hs, tool_name):
from ..tools.hashcat import Hashcat
from ..model.pmkid_result import CrackResultPMKID
key = None
try:
key = Hashcat.crack_pmkid(hs['filename'], verbose=True) key = Hashcat.crack_pmkid(hs['filename'], verbose=True)
except KeyboardInterrupt:
Color.pl('\n{!} Interrupted')
if key is not None: if key is not None:
return CrackResultPMKID(hs['bssid'], hs['essid'], hs['filename'], key) return CrackResultPMKID(hs['bssid'], hs['essid'], hs['filename'], key)

View File

@@ -1,105 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
try:
from .config import Configuration
except (ValueError, ImportError) as e:
raise Exception('You may need to run wifite from the root directory (which includes README.md)', e)
from .util.color import Color
import os
import sys
class Wifite(object):
def __init__(self):
'''
Initializes Wifite. Checks for root permissions and ensures dependencies are installed.
'''
self.print_banner()
Configuration.initialize(load_interface=False)
if os.getuid() != 0:
Color.pl('{!} {R}error: {O}wifite{R} must be run as {O}root{W}')
Color.pl('{!} {R}re-run with {O}sudo{W}')
Configuration.exit_gracefully(0)
from .tools.dependency import Dependency
Dependency.run_dependency_check()
def start(self):
'''
Starts target-scan + attack loop, or launches utilities dpeending on user input.
'''
from .model.result import CrackResult
from .model.handshake import Handshake
from .util.crack import CrackHelper
if Configuration.show_cracked:
CrackResult.display()
elif Configuration.check_handshake:
Handshake.check()
elif Configuration.crack_handshake:
CrackHelper.run()
else:
Configuration.get_monitor_mode_interface()
self.scan_and_attack()
def print_banner(self):
'''Displays ASCII art of the highest caliber.'''
Color.pl(r'{G} . {GR}{D} {W}{G} . {W}')
Color.pl(r'{G}.´ · .{GR}{D} {W}{G}. · `. {G}wifite {D}%s{W}' % Configuration.version)
Color.pl(r'{G}: : : {GR}{D} (¯) {W}{G} : : : {W}{D}automated wireless auditor{W}')
Color.pl(r'{G}`. · `{GR}{D}\ {W}{G}´ · .´ {C}{D}https://github.com/derv82/wifite2{W}')
Color.pl(r'{G} ` {GR}{D}/¯¯¯\{W}{G} ´ {W}')
Color.pl('')
def scan_and_attack(self):
'''
1) Scans for targets, asks user to select targets
2) Attacks each target
'''
from .util.scanner import Scanner
from .attack.all import AttackAll
Color.pl('')
# Scan
s = Scanner()
targets = s.select_targets()
# Attack
attacked_targets = AttackAll.attack_multiple(targets)
Color.pl('{+} Finished attacking {C}%d{W} target(s), exiting' % attacked_targets)
##############################################################
def entry_point():
try:
wifite = Wifite()
wifite.start()
except Exception as e:
Color.pexception(e)
Color.pl('\n{!} {R}Exiting{W}\n')
except KeyboardInterrupt:
Color.pl('\n{!} {O}interrupted, shutting down...{W}')
Configuration.exit_gracefully(0)
if __name__ == '__main__':
entry_point()