diff --git a/wifite/args.py b/wifite/args.py index e6059fd..ef71b94 100755 --- a/wifite/args.py +++ b/wifite/args.py @@ -148,7 +148,7 @@ class Arguments(object): def _add_eviltwin_args(self, group): - group.add_argument('-ev', + group.add_argument('-et', '--eviltwin', action='store_true', dest='use_eviltwin', diff --git a/wifite/attack/eviltwin.py b/wifite/attack/eviltwin.py new file mode 100644 index 0000000..2a149ce --- /dev/null +++ b/wifite/attack/eviltwin.py @@ -0,0 +1,143 @@ +#!/usr/bin/python2.7 +# -*- coding: utf-8 -*- + +import time + +from ..model.attack import Attack +from ..tools.ifconfig import Ifconfig +from ..tools.iptables import Iptables +from ..tools.eviltwin_server import EviltwinServer +from ..util.color import Color +from ..config import Configuration + +class EvilTwinAttack(Attack): + def __init__(self, target): + super(EvilTwinAttack, self).__init__(target) + self.target = target + self.success = False + self.completed = False + self.crack_result = None + + self.crack_result = None + self.hostapd = None + self.dnsmasq = None + + self.deauther = None # Mdk3Deauther? + + + def success_callback(self, crack_result): + # TODO: Stop all processes & reset IP tables + self.crack_result = crack_result + self.success = True + self.completed = True + + + def error_callback(self, error_msg): + 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) + + + def cleanup(self): + ''' + TODO: + * Kill all processes + * Delete config files from temp + * Reset iptables + * Reset interface state? + ''' + pass + + def set_port_forwrading(self, enabled=True): + # echo "1" > /proc/sys/net/ipv4/ip_forward + # TODO: Are there other 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): + # 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', + ]) + + 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, + '--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', base_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', + ]) + diff --git a/wifite/tools/dnsmasq.py b/wifite/tools/dnsmasq.py new file mode 100755 index 0000000..9a5d978 --- /dev/null +++ b/wifite/tools/dnsmasq.py @@ -0,0 +1,67 @@ +#!/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 + + + def create_config_file(self): + config_file = os.path.join(Configuration.temp(), 'dnsmasq.conf') + if os.path.exists(config_file): + os.remove(config_file) + + with open(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') + return config_file + + + def start(self): + config_file = self.create_config_file() + + # Stop already-running dnsmasq process + self.killall() + + # Start new dnsmasq process + self.pid = Process([ + 'dnsmasq', + '-C', config_file + ]) + + + def stop(self): + # Kill dnsmasq process + if self.pid: + 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 + + + def killall(self): + Process(['killall', 'dnsmasq']).wait() + diff --git a/wifite/tools/eviltwin_server.py b/wifite/tools/eviltwin_server.py new file mode 100644 index 0000000..82885ae --- /dev/null +++ b/wifite/tools/eviltwin_server.py @@ -0,0 +1,64 @@ +#!/usr/bin/python2.7 +# -*- coding: utf-8 -*- + +from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler + +class EviltwinServer(HTTPServer): + + def __init__(self, success_callback, port=80): + super(EviltwinServer, self).__init__('', port, EviltwinRequestHandler) + + + def serve_forever(self): + super(EviltwinServer, self).serve_forever() + + +class EviltwinRequestHandler(BaseHTTPRequestHandler): + + def __init__(self, success_callback): + self.success_callback = success_callback + + def do_GET(self): + request_path = self.path + + # TODO: URL mappings to load specific pages. + + print("\n----- Request Start ----->\n") + print(request_path) + print(self.headers) + print("<----- Request End -----\n") + + self.send_response(200) + self.send_header("Set-Cookie", "foo=bar") + + def do_POST(self): + request_path = self.path + + # TODO: If path includes router password, call self.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 + + +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 new file mode 100755 index 0000000..d3a786c --- /dev/null +++ b/wifite/tools/hostapd.py @@ -0,0 +1,74 @@ +#!/usr/bin/python2.7 +# -*- coding: utf-8 -*- + +import re +import os + +from .dependency import Dependency +from ..config import Configuration + +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 + # Save hostapd state? + + + def create_config_file(self): + if not self.target.essid_known: + raise Exception('Cannot start hostapd if target has unknown SSID') + + config_file = os.path.abspath(os.path.join(Configuration.temp(), 'hostapd.conf')) + + with open(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 + 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.killall() + + self.pid = Process([ + self.process_name, + '-C', config_file, + '-i', self.interface + ]) + + + def stop(self): + if self.pid: + self.pid.interrupt() + self.killall() + # TODO: Wait until hostapd is completely stopped. + + + 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 + + + def killall(self): + Process(['killall', self.process_name]).wait() + diff --git a/wifite/tools/iptables.py b/wifite/tools/iptables.py new file mode 100644 index 0000000..0609974 --- /dev/null +++ b/wifite/tools/iptables.py @@ -0,0 +1,47 @@ +#!/usr/bin/python2.7 +# -*- coding: utf-8 -*- + +import re + +from .dependency import Dependency + +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): + 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())) + + + @classmethod + def new_chain(cls, chain_name, table): + command = ['-N', name, '-t', table] + cls.__exec(command) + + + @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) + diff --git a/wifite/wifite.py b/wifite/wifite.py index ca7578e..e04df9e 100755 --- a/wifite/wifite.py +++ b/wifite/wifite.py @@ -14,6 +14,7 @@ from .util.input import raw_input 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.handshake import Handshake @@ -158,7 +159,7 @@ class Wifite(object): # TODO: Check if Eviltwin attack is selected. if Configuration.use_eviltwin: - pass + attack = EvilTwinAttack(t) elif 'WEP' in t.encryption: attack = AttackWEP(t)