Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04e67dba21 | ||
|
|
f641ea53c4 | ||
|
|
d01470a8e4 | ||
|
|
dd0e44cf53 | ||
|
|
4173ef46e5 | ||
|
|
a063f08388 |
171
README.md
171
README.md
@@ -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
7
Wifite.py
Executable 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()
|
||||||
@@ -56,11 +56,11 @@ class Wifite(object):
|
|||||||
|
|
||||||
def print_banner(self):
|
def print_banner(self):
|
||||||
'''Displays ASCII art of the highest caliber.'''
|
'''Displays ASCII art of the highest caliber.'''
|
||||||
Color.pl(r'{G} . {GR}{D} {W}{G} . {W}')
|
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}. · `. {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} : : : {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}´ · .´ {C}{D}https://github.com/derv82/wifite2{W}')
|
||||||
Color.pl(r'{G} ` {GR}{D}/¯¯¯\{W}{G} ´ {W}')
|
Color.pl(r' {G} ` {GR}{D}/¯¯¯\{W}{G} ´ {W}')
|
||||||
Color.pl('')
|
Color.pl('')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -97,7 +97,12 @@ class AttackPMKID(Attack):
|
|||||||
return False # No hash found.
|
return False # No hash found.
|
||||||
|
|
||||||
# Crack it.
|
# Crack it.
|
||||||
self.success = self.crack_pmkid_file(pmkid_file)
|
try:
|
||||||
|
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'
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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'
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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
41
wifite/tools/cowpatty.py
Normal 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
|
||||||
@@ -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
65
wifite/tools/john.py
Normal 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
|
||||||
@@ -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) )
|
||||||
|
|
||||||
for hs in hs_to_crack:
|
if len(missing_tools) > 0:
|
||||||
cls.crack(hs)
|
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:
|
||||||
|
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
|
key = Hashcat.crack_pmkid(hs['filename'], verbose=True)
|
||||||
from ..model.pmkid_result import CrackResultPMKID
|
|
||||||
|
|
||||||
key = None
|
|
||||||
try:
|
|
||||||
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)
|
||||||
|
|||||||
105
wifite/wifite.py
105
wifite/wifite.py
@@ -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()
|
|
||||||
Reference in New Issue
Block a user