mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2025-02-07 12:44:03 -05:00
fragattack: ability to test injection capabilities of device
This commit is contained in:
parent
3331b80fb7
commit
173e11d400
97
research/NOTES.md
Normal file
97
research/NOTES.md
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
# Monitor mode injectin
|
||||||
|
|
||||||
|
Device that purely operate in monitor mode might overwrite certain fields of
|
||||||
|
injected frames. Here we document the default behaviour of some devices.
|
||||||
|
|
||||||
|
When using a single physical interface to create a virtual managed _and_ monitor
|
||||||
|
interface, there are additional unexpected consequences to injection of frames.
|
||||||
|
These depend on the specific driver/device being used, and we discuss some of
|
||||||
|
these issues here as well.
|
||||||
|
|
||||||
|
|
||||||
|
## Intel 8265 / 8275 (rev 78) devices
|
||||||
|
|
||||||
|
Summary: this can be used without driver/firmware changes in pure monitor mode,
|
||||||
|
but care is still needed that frames with different priority are not
|
||||||
|
reordered (**TODO: Explain parameter to force this**).
|
||||||
|
|
||||||
|
- When connecting normally on Arch Linux, while connecting it sends frames with
|
||||||
|
all three address equal to it's own address. This frame contains the numbers
|
||||||
|
1 to 0x27 as 32-bit numbers for some reason. This is a strange bug, but at
|
||||||
|
least it is not caused by our driver modifications.
|
||||||
|
|
||||||
|
- Had to patch driver to prevent sequence number and QoS TID to be overwritten
|
||||||
|
**TODO: Also in pure monitor?**
|
||||||
|
|
||||||
|
- Unable to transmit any frames from a different transmitter address. This is
|
||||||
|
because in `ieee80211_monitor_start_xmit` it cannot find a channel to transmit
|
||||||
|
on (finding a valid chandef fails).
|
||||||
|
**TODO: Also in pure monitor?**
|
||||||
|
|
||||||
|
- Cannot inject frames using a TID that is used for the first time. There's no
|
||||||
|
queue in the driver allocated for it yet it seems, and this causes issues.
|
||||||
|
To prevent this, and prevent frame reordering, we inject all frames on the
|
||||||
|
same queue in the driver.
|
||||||
|
**TODO: Also in pure monitor?**
|
||||||
|
|
||||||
|
- It ignores `IEEE80211_RADIOTAP_DATA_RETRIES` and retransmites frames 15 times
|
||||||
|
both in purely monitor more and mixed managed/monitor mode (before and after
|
||||||
|
authenticating).
|
||||||
|
|
||||||
|
- Unlike, ath9k_htc, in mixed managed/monitor, we can inject frames before the
|
||||||
|
association request is sent. Strangely, the Intel device also sends some strange
|
||||||
|
frames while connecting (even on Windows 10). But that only seems to slow down
|
||||||
|
the injection of frames.
|
||||||
|
|
||||||
|
|
||||||
|
## Ath9k_htc devices
|
||||||
|
|
||||||
|
Summary: when using this device, you must use a modified driver/firmware.
|
||||||
|
Since this is a USB device, this can be done inside a virtual machine.
|
||||||
|
|
||||||
|
- The ath9k_htc devices by default overwrite the injected sequence number,
|
||||||
|
**even when purely operating in monitor mode**.
|
||||||
|
|
||||||
|
Interestingly, the device will not increment the sequence number when the
|
||||||
|
MoreFragments flag is set, meaning we can inject fragmented frames (albeit
|
||||||
|
with a different sequence number than then one we use in the user-space
|
||||||
|
script).
|
||||||
|
|
||||||
|
- The above trick does not work when we want to inject other frames between
|
||||||
|
two fragmented frames (the chip will assign them difference sequence numbers).
|
||||||
|
Even when the fragments use different QoS TIDs, sending frames between them
|
||||||
|
will make the chip assign difference sequence numbers to both fragments.
|
||||||
|
**TODO: This only is the case in mixed manager/monitor mode I think?**
|
||||||
|
|
||||||
|
- Overwriting the sequence can be avoided by patching `ath_tgt_tx_seqno_normal`
|
||||||
|
and commenting out the two lines that modify `i_seq`. Note that these changes
|
||||||
|
are in the firmware of the device.
|
||||||
|
|
||||||
|
- See also the comment in Station.perform_actions to avoid other bugs with
|
||||||
|
ath9k_htc when injecting frames with the MF flag and while being in AP mode.
|
||||||
|
|
||||||
|
- The at9k_htc dongle, like other Wi-Fi devices, will reorder frames with
|
||||||
|
different QoS priorities. This means injected frames with differen priorities
|
||||||
|
may get reordered by the driver/chip. We avoided this by modifying the ath9k_htc
|
||||||
|
driver to send all frames using the transmission queue of priority zero,
|
||||||
|
independent of the actual QoS priority value used in the frame.
|
||||||
|
**This happens even when purely operating in monitor mode.**
|
||||||
|
|
||||||
|
- It doesn't retransmit frames in pure monitor mode. In mixed managed/monitor
|
||||||
|
after (or right before authentication) it retransmits frames at most ones.
|
||||||
|
But it **injects a lot of RTS** as times?!
|
||||||
|
|
||||||
|
- In mixed/managed mode, we can inject frames when the managed interface is up
|
||||||
|
but not being controlled by wpa_supplicant (but unknown which channel will be
|
||||||
|
used). When connecting using wpa_supplicant, it seems we can only inject frames
|
||||||
|
after the association request has been sent.
|
||||||
|
|
||||||
|
- In mixed AP/monitor mode, when injecting the first fragment of a frame, it will
|
||||||
|
be injected properly, but afterards the chip won't second beacons for one second.
|
||||||
|
This can be prevented by injected a dummy packet after the injected fragment.
|
||||||
|
|
||||||
|
# TODOs
|
||||||
|
|
||||||
|
- When using the mac80211_hwsim trick with one monitor interface, there is
|
||||||
|
still the risk of frames with different QoS TIDs being reordered.
|
||||||
|
|
@ -46,8 +46,8 @@ class TestOptions():
|
|||||||
self.peerip = None
|
self.peerip = None
|
||||||
|
|
||||||
def log_level2switch():
|
def log_level2switch():
|
||||||
if global_log_level == 1: return ["-d", "-K"]
|
if options.debug >= 2: return ["-dd", "-K"]
|
||||||
elif global_log_level <= 0: return ["-dd", "-K"]
|
elif options.debug >= 1: return ["-d", "-K"]
|
||||||
return ["-K"]
|
return ["-K"]
|
||||||
|
|
||||||
#TODO: Move to libwifi?
|
#TODO: Move to libwifi?
|
||||||
@ -102,62 +102,6 @@ def freebsd_encap_eapolmsdu(p, src, dst, payload):
|
|||||||
p = p/freebsd_create_eapolmsdu(src, dst, payload)
|
p = p/freebsd_create_eapolmsdu(src, dst, payload)
|
||||||
return p
|
return p
|
||||||
|
|
||||||
def set_monitor_mode(iface):
|
|
||||||
# Some kernels (Debian jessie - 3.16.0-4-amd64) don't properly add the monitor interface. The following ugly
|
|
||||||
# sequence of commands assures the virtual interface is properly registered as a 802.11 monitor interface.
|
|
||||||
subprocess.check_output(["ifconfig", iface, "down"])
|
|
||||||
subprocess.check_output(["iw", iface, "set", "type", "monitor"])
|
|
||||||
time.sleep(0.5)
|
|
||||||
subprocess.check_output(["iw", iface, "set", "type", "monitor"])
|
|
||||||
subprocess.check_output(["ifconfig", iface, "up"])
|
|
||||||
subprocess.check_output(["ifconfig", iface, "mtu", "2200"])
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------- Injection Tests -----------------------------------
|
|
||||||
|
|
||||||
def test_packet_injection(sout, sin, p, test_func):
|
|
||||||
log(WARNING, "Testing injection")
|
|
||||||
|
|
||||||
# Append unique label to recognize frame & inject it
|
|
||||||
label = b"AAAA" + struct.pack(">II", random.randint(0, 2**32), random.randint(0, 2**32))
|
|
||||||
sout.send(RadioTap()/p/Raw(label))
|
|
||||||
|
|
||||||
#TODO: Should we prevent ath9k_htc injection bug after injecting a fragment?
|
|
||||||
|
|
||||||
# 1. When using a 2nd interface: capture the actual packet that was injected in the air.
|
|
||||||
# 2. Not using 2nd interface: capture the "reflected" frame sent back by the kernel. This allows
|
|
||||||
# us to at least detect if the kernel (and perhaps driver) is overwriting fields. It generally
|
|
||||||
# doesn't allow us to detect if the device/firmware itself is overwriting fields.
|
|
||||||
packets = sniff(opened_socket=sin, timeout=2, count=1, lfilter=lambda p: p != None and label in raw(p))
|
|
||||||
if len(packets) < 1:
|
|
||||||
raise IOError("Unable to inject test frame. Does your driver/device support monitor mode?")
|
|
||||||
|
|
||||||
# Property must hold for all frames
|
|
||||||
return all([test_func(cap) for cap in packets])
|
|
||||||
|
|
||||||
def test_injection(iface_out, iface_in=None):
|
|
||||||
# We start monitoring iface_in already so injected frame won't be missed
|
|
||||||
sout = L2Socket(type=ETH_P_ALL, iface=iface_out)
|
|
||||||
if iface_in == None:
|
|
||||||
sin = sout
|
|
||||||
else:
|
|
||||||
sin = L2Socket(type=ETH_P_ALL, iface=iface_in)
|
|
||||||
|
|
||||||
p = Dot11(addr1="00:11:00:00:00:01", addr2="00:22:00:00:00:01", type=2, SC=33<<4)
|
|
||||||
if not test_packet_injection(sout, sin, p, lambda cap: cap.SC == p.SC):
|
|
||||||
raise IOError("Sequence number of injected frames is being overwritten!")
|
|
||||||
|
|
||||||
p = Dot11(addr1="00:11:00:00:00:02", addr2="00:22:00:00:00:02", type=2, SC=(33<<4)|1)
|
|
||||||
if not test_packet_injection(sout, sin, p, lambda cap: (cap.SC & 0xf) == 1):
|
|
||||||
raise IOError("Fragment number of injected frames is being overwritten!")
|
|
||||||
|
|
||||||
p = Dot11(addr1="00:11:00:00:00:03", addr2="00:22:00:00:00:03", type=2, subtype=8, SC=33)/Dot11QoS(TID=2)
|
|
||||||
if not test_packet_injection(sout, sin, p, lambda cap: cap.TID == p.TID):
|
|
||||||
raise IOError("QoS TID of injected frames is being overwritten!")
|
|
||||||
|
|
||||||
sout.close()
|
|
||||||
sin.close()
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------- Vulnerability Tests -----------------------------------
|
# ----------------------------------- Vulnerability Tests -----------------------------------
|
||||||
|
|
||||||
@ -647,6 +591,11 @@ class Station():
|
|||||||
script was sending data *before* the key had been installed (or the port
|
script was sending data *before* the key had been installed (or the port
|
||||||
authorized). This meant traffic was dropped. Use this function to manually
|
authorized). This meant traffic was dropped. Use this function to manually
|
||||||
send frames over the monitor interface to ensure delivery and encryption.
|
send frames over the monitor interface to ensure delivery and encryption.
|
||||||
|
|
||||||
|
By default we use a TID of 1. Since our tests by default use a TID of 2,
|
||||||
|
this reduces the chance the frames sent using this function (which most
|
||||||
|
are EAP or EAPOL frames) interfere with the reassembly of frames sent by
|
||||||
|
the tests.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# If it contains an Ethernet header, strip it, and take addresses from that
|
# If it contains an Ethernet header, strip it, and take addresses from that
|
||||||
@ -909,7 +858,6 @@ class Daemon(metaclass=abc.ABCMeta):
|
|||||||
self.nic_iface = None
|
self.nic_iface = None
|
||||||
self.nic_mon = None
|
self.nic_mon = None
|
||||||
self.nic_hwsim = None
|
self.nic_hwsim = None
|
||||||
self.performed_injection_selftest = False
|
|
||||||
|
|
||||||
self.process = None
|
self.process = None
|
||||||
self.sock_eth = None
|
self.sock_eth = None
|
||||||
@ -973,11 +921,6 @@ class Daemon(metaclass=abc.ABCMeta):
|
|||||||
# Use the provided interface to monitor/inject frames
|
# Use the provided interface to monitor/inject frames
|
||||||
self.nic_mon = self.options.inject
|
self.nic_mon = self.options.inject
|
||||||
|
|
||||||
# Avoid the monitor interface from retransmitting frames? This was not needed for the
|
|
||||||
# ath9k_htc and intel/mvm device that I tested. Perhaps for others it might be needed.
|
|
||||||
#subprocess.call(["ifconfig", self.nic_mon, "down"])
|
|
||||||
#subprocess.call(["macchanger", "-m", get_macaddress(self.nic_iface), self.nic_mon])
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Create second virtual interface in monitor mode. Note: some kernels
|
# Create second virtual interface in monitor mode. Note: some kernels
|
||||||
# don't support interface names of 15+ characters.
|
# don't support interface names of 15+ characters.
|
||||||
@ -1007,6 +950,10 @@ class Daemon(metaclass=abc.ABCMeta):
|
|||||||
if self.nic_hwsim:
|
if self.nic_hwsim:
|
||||||
set_monitor_mode(self.nic_hwsim)
|
set_monitor_mode(self.nic_hwsim)
|
||||||
|
|
||||||
|
# 3. Configure test interface if used
|
||||||
|
if self.options.inject_test:
|
||||||
|
set_monitor_mode(self.options.inject_test)
|
||||||
|
|
||||||
def inject_mon(self, p):
|
def inject_mon(self, p):
|
||||||
self.sock_mon.send(p)
|
self.sock_mon.send(p)
|
||||||
|
|
||||||
@ -1028,24 +975,36 @@ class Daemon(metaclass=abc.ABCMeta):
|
|||||||
log(ERROR, "Did you disable Wi-Fi in the network manager? Otherwise it won't start properly.")
|
log(ERROR, "Did you disable Wi-Fi in the network manager? Otherwise it won't start properly.")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def injection_selftest(self):
|
def follow_channel(self):
|
||||||
if self.performed_injection_selftest:
|
channel = get_channel(self.nic_iface)
|
||||||
return
|
if self.options.inject:
|
||||||
|
set_channel(self.nic_mon, channel)
|
||||||
|
log(STATUS, f"{self.nic_mon}: setting to channel {channel}")
|
||||||
|
elif self.options.hwsim:
|
||||||
|
set_channel(self.nic_hwsim, channel)
|
||||||
|
set_channel(self.nic_mon, channel)
|
||||||
|
log(STATUS, f"{self.nic_hwsim}: setting to channel {channel}")
|
||||||
|
log(STATUS, f"{self.nic_mon}: setting to channel {channel}")
|
||||||
|
|
||||||
# - When using a 2nd interface to inject frames, this self-test should trivially succeed.
|
if self.options.inject_test:
|
||||||
# - This is mainly useful when using one interface as both client and monitor interface,
|
set_channel(self.options.inject_test, channel)
|
||||||
# in which case a modified kernel/driver must be used.
|
log(STATUS, f"{self.options.inject_test}: setting to channel {channel}")
|
||||||
# - With the Intel/mvm injection in this case only works if hostapd/wpa_supp started.
|
# When explicitly testing we can afford a longer timeout. Otherwise we should avoid it.
|
||||||
# - When in client mode, it seems the scanning operation interferes with this test. So it
|
time.sleep(0.5)
|
||||||
# must be executed once we are trying to connect so the channel is "stable".
|
|
||||||
try: test_injection(self.nic_mon)
|
def injection_test(self, peermac):
|
||||||
|
# Only perform the test when explicitly requested
|
||||||
|
if self.options.inject_test == None: return
|
||||||
|
|
||||||
|
try:
|
||||||
|
test_injection(self.nic_mon, self.options.inject_test, peermac)
|
||||||
except IOError as ex:
|
except IOError as ex:
|
||||||
log(WARNING, ex.args[0])
|
log(WARNING, ex.args[0])
|
||||||
log(ERROR, "Injection self-test failed. Are you using the correct kernel/driver/device for injection?")
|
log(ERROR, "Unexpected error. Are you using the correct kernel/driver/device?")
|
||||||
quit(1)
|
quit(1)
|
||||||
|
|
||||||
log(DEBUG, f"Passed injection self-test on interface {self.nic_mon}.")
|
log(DEBUG, f"Passed injection self-test on interface {self.nic_mon}.")
|
||||||
self.performed_injection_selftest = True
|
quit(1)
|
||||||
|
|
||||||
def forward_hwsim(self, p, s):
|
def forward_hwsim(self, p, s):
|
||||||
if p == None: return
|
if p == None: return
|
||||||
@ -1072,6 +1031,7 @@ class Daemon(metaclass=abc.ABCMeta):
|
|||||||
self.sock_hwsim = MonitorSocket(type=ETH_P_ALL, iface=self.nic_hwsim)
|
self.sock_hwsim = MonitorSocket(type=ETH_P_ALL, iface=self.nic_hwsim)
|
||||||
|
|
||||||
# Post-startup configuration of the supplicant or AP
|
# Post-startup configuration of the supplicant or AP
|
||||||
|
wpaspy_command(self.wpaspy_ctrl, "SET ext_eapol_frame_io 1")
|
||||||
self.configure_daemon()
|
self.configure_daemon()
|
||||||
|
|
||||||
# Monitor the virtual monitor interface of the client and perform the needed actions
|
# Monitor the virtual monitor interface of the client and perform the needed actions
|
||||||
@ -1193,6 +1153,8 @@ class Authenticator(Daemon):
|
|||||||
station.set_ip_addresses(self.options.ip, self.options.peerip)
|
station.set_ip_addresses(self.options.ip, self.options.peerip)
|
||||||
|
|
||||||
def handle_wpaspy(self, msg):
|
def handle_wpaspy(self, msg):
|
||||||
|
log(DEBUG, "daemon: " + msg)
|
||||||
|
|
||||||
if "AP-STA-CONNECTING" in msg:
|
if "AP-STA-CONNECTING" in msg:
|
||||||
cmd, clientmac = msg.split()
|
cmd, clientmac = msg.split()
|
||||||
self.add_station(clientmac)
|
self.add_station(clientmac)
|
||||||
@ -1202,6 +1164,11 @@ class Authenticator(Daemon):
|
|||||||
station.handle_connecting(self.apmac)
|
station.handle_connecting(self.apmac)
|
||||||
station.set_peermac(clientmac)
|
station.set_peermac(clientmac)
|
||||||
|
|
||||||
|
# When in client mode, the scanning operation might interferes with this test.
|
||||||
|
# So it must be executed once we are connecting so the channel is stable.
|
||||||
|
# TODO: Avoid client from disconnecting during test.
|
||||||
|
self.injection_test(clientmac)
|
||||||
|
|
||||||
elif "EAPOL-TX" in msg:
|
elif "EAPOL-TX" in msg:
|
||||||
cmd, clientmac, payload = msg.split()
|
cmd, clientmac, payload = msg.split()
|
||||||
if not clientmac in self.stations:
|
if not clientmac in self.stations:
|
||||||
@ -1209,7 +1176,6 @@ class Authenticator(Daemon):
|
|||||||
return
|
return
|
||||||
self.stations[clientmac].handle_eapol_tx(bytes.fromhex(payload))
|
self.stations[clientmac].handle_eapol_tx(bytes.fromhex(payload))
|
||||||
|
|
||||||
# XXX WPA1: Take into account group key handshake on initial 4-way HS
|
|
||||||
elif "AP-STA-CONNECTED" in msg:
|
elif "AP-STA-CONNECTED" in msg:
|
||||||
cmd, clientmac = msg.split()
|
cmd, clientmac = msg.split()
|
||||||
if not clientmac in self.stations:
|
if not clientmac in self.stations:
|
||||||
@ -1231,9 +1197,6 @@ class Authenticator(Daemon):
|
|||||||
self.apmac = get_macaddress(self.nic_iface)
|
self.apmac = get_macaddress(self.nic_iface)
|
||||||
|
|
||||||
def configure_daemon(self):
|
def configure_daemon(self):
|
||||||
# Intercept EAPOL packets that the AP wants to send
|
|
||||||
wpaspy_command(self.wpaspy_ctrl, "SET ext_eapol_frame_io 1")
|
|
||||||
|
|
||||||
# Let scapy handle DHCP requests
|
# Let scapy handle DHCP requests
|
||||||
self.dhcp = DHCP_sock(sock=self.sock_eth,
|
self.dhcp = DHCP_sock(sock=self.sock_eth,
|
||||||
domain='mathyvanhoef.com',
|
domain='mathyvanhoef.com',
|
||||||
@ -1252,18 +1215,7 @@ class Authenticator(Daemon):
|
|||||||
#log(STATUS, f"Will inject ARP packets using sender IP {self.arp_sender_ip}")
|
#log(STATUS, f"Will inject ARP packets using sender IP {self.arp_sender_ip}")
|
||||||
|
|
||||||
# When using a separate interface to inject, switch to correct channel
|
# When using a separate interface to inject, switch to correct channel
|
||||||
if self.options.inject:
|
self.follow_channel()
|
||||||
channel = get_channel(self.nic_iface)
|
|
||||||
set_channel(self.nic_mon, channel)
|
|
||||||
log(STATUS, f"{self.nic_mon}: setting to channel {channel}")
|
|
||||||
elif self.options.hwsim:
|
|
||||||
channel = get_channel(self.nic_iface)
|
|
||||||
set_channel(self.nic_hwsim, channel)
|
|
||||||
set_channel(self.nic_mon, channel)
|
|
||||||
log(STATUS, f"{self.nic_hwsim}: setting to channel {channel}")
|
|
||||||
log(STATUS, f"{self.nic_mon}: setting to channel {channel}")
|
|
||||||
|
|
||||||
self.injection_selftest()
|
|
||||||
|
|
||||||
|
|
||||||
class Supplicant(Daemon):
|
class Supplicant(Daemon):
|
||||||
@ -1392,18 +1344,7 @@ class Supplicant(Daemon):
|
|||||||
|
|
||||||
elif "Trying to authenticate with" in msg:
|
elif "Trying to authenticate with" in msg:
|
||||||
# When using a separate interface to inject, switch to correct channel
|
# When using a separate interface to inject, switch to correct channel
|
||||||
if self.options.inject:
|
self.follow_channel()
|
||||||
channel = get_channel(self.nic_iface)
|
|
||||||
set_channel(self.nic_mon, channel)
|
|
||||||
log(STATUS, f"{self.nic_mon}: setting to channel {channel}")
|
|
||||||
|
|
||||||
elif self.options.hwsim:
|
|
||||||
# FIXME: There is some delay, causing the first authentication to fail
|
|
||||||
channel = get_channel(self.nic_iface)
|
|
||||||
set_channel(self.nic_mon, channel)
|
|
||||||
set_channel(self.nic_hwsim, channel)
|
|
||||||
log(STATUS, f"{self.nic_mon}: setting to channel {channel}")
|
|
||||||
log(STATUS, f"{self.nic_hwsim}: setting to channel {channel}")
|
|
||||||
|
|
||||||
p = re.compile("Trying to authenticate with (.*) \(SSID")
|
p = re.compile("Trying to authenticate with (.*) \(SSID")
|
||||||
bss = p.search(msg).group(1)
|
bss = p.search(msg).group(1)
|
||||||
@ -1412,8 +1353,7 @@ class Supplicant(Daemon):
|
|||||||
elif "Trying to associate with" in msg:
|
elif "Trying to associate with" in msg:
|
||||||
# With the ath9k_htc, injection in mixed managed/monitor only works after
|
# With the ath9k_htc, injection in mixed managed/monitor only works after
|
||||||
# sending the association request. So only perform injection test now.
|
# sending the association request. So only perform injection test now.
|
||||||
# TODO: Only do a self-test when in mixed managed/monitor mode?
|
self.injection_test(self.station.bss)
|
||||||
self.injection_selftest()
|
|
||||||
|
|
||||||
elif "EAPOL-TX" in msg:
|
elif "EAPOL-TX" in msg:
|
||||||
cmd, srcaddr, payload = msg.split()
|
cmd, srcaddr, payload = msg.split()
|
||||||
@ -1430,15 +1370,15 @@ class Supplicant(Daemon):
|
|||||||
|
|
||||||
def reconnect(self, station):
|
def reconnect(self, station):
|
||||||
log(STATUS, "Reconnecting to the AP.", color="green")
|
log(STATUS, "Reconnecting to the AP.", color="green")
|
||||||
|
|
||||||
|
# Optimize reassoc-to-same-BSS by default. This makes the "REASSOCIATE" command skip
|
||||||
|
# the authentication phase (reducing the chance that packet queues are reset).
|
||||||
optim = "0" if self.options.full_reconnect else "1"
|
optim = "0" if self.options.full_reconnect else "1"
|
||||||
|
|
||||||
wpaspy_command(self.wpaspy_ctrl, f"SET reassoc_same_bss_optim {optim}")
|
wpaspy_command(self.wpaspy_ctrl, f"SET reassoc_same_bss_optim {optim}")
|
||||||
wpaspy_command(self.wpaspy_ctrl, "REASSOCIATE")
|
wpaspy_command(self.wpaspy_ctrl, "REASSOCIATE")
|
||||||
|
|
||||||
def configure_daemon(self):
|
def configure_daemon(self):
|
||||||
# Optimize reassoc-to-same-BSS. This makes the "REASSOCIATE" command skip the
|
|
||||||
# authentication phase (reducing the chance that packet queues are reset).
|
|
||||||
wpaspy_command(self.wpaspy_ctrl, "SET ext_eapol_frame_io 1")
|
|
||||||
|
|
||||||
# If the user already supplied IPs we can immediately perform tests
|
# If the user already supplied IPs we can immediately perform tests
|
||||||
if self.options.ip and self.options.peerip:
|
if self.options.ip and self.options.peerip:
|
||||||
self.initialize_ips(self.options.ip, self.options.peerip)
|
self.initialize_ips(self.options.ip, self.options.peerip)
|
||||||
@ -1645,7 +1585,7 @@ if __name__ == "__main__":
|
|||||||
parser.add_argument('testname', help="Name or identifier of the test to run.")
|
parser.add_argument('testname', help="Name or identifier of the test to run.")
|
||||||
parser.add_argument('actions', nargs='?', help="Optional textual descriptions of actions")
|
parser.add_argument('actions', nargs='?', help="Optional textual descriptions of actions")
|
||||||
parser.add_argument('--inject', default=None, help="Interface to use to inject frames.")
|
parser.add_argument('--inject', default=None, help="Interface to use to inject frames.")
|
||||||
parser.add_argument('--inject-test', default=None, help="Use main interface to test injection through this interface.")
|
parser.add_argument('--inject-test', default=None, help="Use given interface to test injection through monitor interface.")
|
||||||
parser.add_argument('--hwsim', default=None, help="Use provided interface in monitor mode, and simulate AP/client through hwsim.")
|
parser.add_argument('--hwsim', default=None, help="Use provided interface in monitor mode, and simulate AP/client through hwsim.")
|
||||||
parser.add_argument('--ip', help="IP we as a sender should use.")
|
parser.add_argument('--ip', help="IP we as a sender should use.")
|
||||||
parser.add_argument('--peerip', help="IP of the device we will test.")
|
parser.add_argument('--peerip', help="IP of the device we will test.")
|
||||||
@ -1676,24 +1616,18 @@ if __name__ == "__main__":
|
|||||||
# Default value for options that should not be command line parameters
|
# Default value for options that should not be command line parameters
|
||||||
options.inject_workaround = False
|
options.inject_workaround = False
|
||||||
|
|
||||||
# Perform test using a second interface if requested
|
|
||||||
if options.inject_test:
|
|
||||||
log(WARNING, "TODO: Perform proper injection tests (including with active AP/STA")
|
|
||||||
quit(1)
|
|
||||||
|
|
||||||
# Sanity check and convert some arguments to more usable form
|
# Sanity check and convert some arguments to more usable form
|
||||||
options.ptype = args2ptype(options)
|
options.ptype = args2ptype(options)
|
||||||
options.as_msdu = args2msdu(options)
|
options.as_msdu = args2msdu(options)
|
||||||
|
|
||||||
# Construct the test
|
# Construct the test
|
||||||
options.test = prepare_tests(options)
|
options.test = prepare_tests(options)
|
||||||
|
|
||||||
if options.test == None:
|
if options.test == None:
|
||||||
log(STATUS, f"Test name/id '{options.testname}' not recognized. Specify a valid test case.")
|
log(STATUS, f"Test name/id '{options.testname}' not recognized. Specify a valid test case.")
|
||||||
quit(1)
|
quit(1)
|
||||||
|
|
||||||
# Parse remaining options
|
# Parse remaining options
|
||||||
global_log_level -= options.debug
|
change_log_level(-options.debug)
|
||||||
|
|
||||||
# Now start the tests --- TODO: Inject Deauths before connecting with client...
|
# Now start the tests --- TODO: Inject Deauths before connecting with client...
|
||||||
if options.ap:
|
if options.ap:
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 0665c34816c64f50e8a7c3dd7b9b4134bd0d1992
|
Subproject commit ef622fd62617e4375207c17a5ab4d8abc521b793
|
25
research/test-injection-puremon.py
Executable file
25
research/test-injection-puremon.py
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
from libwifi import *
|
||||||
|
import argparse, time
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Test packet injection properties of a device.")
|
||||||
|
parser.add_argument('inject', help="Interface to use to inject frames.")
|
||||||
|
parser.add_argument('monitor', help="Interface to use to monitor for frames.")
|
||||||
|
options = parser.parse_args()
|
||||||
|
|
||||||
|
subprocess.check_output(["rfkill", "unblock", "wifi"])
|
||||||
|
|
||||||
|
set_monitor_mode(options.inject)
|
||||||
|
set_monitor_mode(options.monitor)
|
||||||
|
|
||||||
|
if get_channel(options.inject) != get_channel(options.monitor):
|
||||||
|
log(ERROR, "Both devices are not on the same channel")
|
||||||
|
quit(1)
|
||||||
|
|
||||||
|
log(STATUS, "Performing injection tests ...")
|
||||||
|
test_injection(options.inject, options.monitor)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user