fragattack: add separate connected event

This commit is contained in:
Mathy 2020-03-27 13:23:49 -04:00
parent 16fa93c888
commit 22f603ceac

View File

@ -60,7 +60,11 @@ class TestOptions():
class MetaFrag():
# StartingAuth, AfterAuthRace
BeforeAuth, BeforeAuthDone, AfterAuth = range(3)
# StartAuth: when starting the handshake
# BeforeAuth: right before last message of the handshake
# AfterAuth: right after last message of the handshake
# Connected: 1 second after handshake completed (allows peer to install keys)
StartAuth, BeforeAuth, AfterAuth, Connected = range(4)
def __init__(self, frag, trigger, encrypted, inc_pn=1):
self.frag = frag
@ -113,6 +117,8 @@ class Station():
self.othermac = None
self.otherip = None
self.time_connected = None
def reset_keys(self):
self.tk = None
# TODO: Get the current PN from the kernel, increment by 0x99,
@ -404,13 +410,13 @@ class Station():
# Inject any fragments before authenticating
if not self.txed_before_auth:
log(STATUS, "MetaFrag.BeforeAuth", color="green")
self.inject_next_frags(MetaFrag.BeforeAuth)
log(STATUS, "MetaFrag.StartAuth", color="green")
self.inject_next_frags(MetaFrag.StartAuth)
self.txed_before_auth = True
# Inject any fragments when almost done authenticating
elif is_msg3_or_4 and not self.txed_before_auth_done:
log(STATUS, "MetaFrag.BeforeAuthDone", color="green")
self.inject_next_frags(MetaFrag.BeforeAuthDone)
log(STATUS, "MetaFrag.BeforeAuth", color="green")
self.inject_next_frags(MetaFrag.BeforeAuth)
self.txed_before_auth_done = True
def handle_eapol_tx(self, eapol):
@ -428,23 +434,36 @@ class Station():
def handle_authenticated(self):
"""Called after completion of the 4-way handshake or similar"""
if not self.obtained_ip: return
log(STATUS, "MetaFrag.AfterAuth", color="green")
self.tk = self.daemon.get_tk(self)
self.gtk, self.gtk_idx = self.daemon.get_gtk()
time.sleep(1)
if not self.obtained_ip: return
log(STATUS, "MetaFrag.AfterAuth", color="green")
self.inject_next_frags(MetaFrag.AfterAuth)
self.time_connected = time.time() + 1
def handle_connected(self):
"""This is called ~1 second after completing the handshake"""
log(STATUS, "MetaFrag.Connected", color="green")
self.inject_next_frags(MetaFrag.Connected)
def set_ip_addresses(self, ip, peerip):
self.ip = ip
self.peerip = peerip
self.obtained_ip = True
# We can generate tests once we have an IP
# We can generate tests once we know the IP addresses
self.generate_tests()
def time_tick(self):
# XXX extra check on self.obtained_ip so when the only test is on Connected event,
# this test can be run without requiring a reconnect.
if self.time_connected != None and time.time() > self.time_connected and self.obtained_ip:
self.handle_connected()
self.time_connected = None
class Daemon():
def __init__(self, options):
self.options = options
@ -470,6 +489,10 @@ class Daemon():
def handle_eth(self, p):
pass
@abc.abstractmethod
def time_tick(self, station):
pass
@abc.abstractmethod
def get_tk(self, station):
pass
@ -535,7 +558,7 @@ class Daemon():
# Monitor the virtual monitor interface of the client and perform the needed actions
while True:
sel = select.select([self.sock_mon, self.sock_eth, self.wpaspy_ctrl.s], [], [], 1)
sel = select.select([self.sock_mon, self.sock_eth, self.wpaspy_ctrl.s], [], [], 0.5)
if self.sock_mon in sel[0]:
p = self.sock_mon.recv()
if p != None: self.handle_mon(p)
@ -548,6 +571,8 @@ class Daemon():
msg = self.wpaspy_ctrl.recv()
self.handle_wpaspy(msg)
self.time_tick()
def stop(self):
log(STATUS, "Closing Hostap daemon and cleaning up ...")
if self.process:
@ -572,6 +597,10 @@ class Authenticator(Daemon):
tk = wpaspy_command(self.wpaspy_ctrl, "GET_TK " + station.peermac)
return bytes.fromhex(tk)
def time_tick(self):
for station in self.stations.items():
station.time_tick()
def force_reconnect(self, station):
# Confirmed to *instantly* reconnect: Arch Linux, Windows 10 with Intel WiFi chip, iPad Pro 13.3.1
# Reconnects only after a few seconds: MacOS (same with other reasons and with deauthentication)
@ -675,6 +704,7 @@ class Supplicant(Daemon):
super().__init__(options)
self.station = None
self.arp_sock = None
self.time_dhcp_discover = None
def get_tk(self, station):
tk = wpaspy_command(self.wpaspy_ctrl, "GET tk")
@ -683,6 +713,14 @@ class Supplicant(Daemon):
else:
return bytes.fromhex(tk)
def time_tick(self):
self.station.time_tick()
if self.time_dhcp_discover != None and time.time() > self.time_dhcp_discover:
# TODO: Create a timer in case retransmissions are needed
self.send_dhcp_discover()
self.time_dhcp_discover = None
def send_dhcp_discover(self):
rawmac = bytes.fromhex(self.station.mac.replace(':', ''))
req = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.station.mac)/IP(src="0.0.0.0", dst="255.255.255.255")
@ -742,15 +780,11 @@ class Supplicant(Daemon):
log(STATUS, "daemon: " + msg)
if "CTRL-EVENT-CONNECTED" in msg:
if not self.station.obtained_ip:
# TODO: Create a timer in case retransmissions are needed
# This get's the current keys
self.station.handle_authenticated()
# Sleep to make sure the AP installed the key
time.sleep(1)
self.send_dhcp_discover()
self.send_dhcp_discover()
else:
self.station.handle_authenticated()
if not self.station.obtained_ip:
self.time_dhcp_discover = time.time() + 0.5
# Trying to authenticate with 38:2c:4a:c1:69:bc (SSID='backupnetwork2' freq=2462 MHz)
elif "Trying to authenticate with" in msg: