diff --git a/research/README.md b/research/README.md index c8f288ceb..9bc60cbaa 100644 --- a/research/README.md +++ b/research/README.md @@ -18,16 +18,18 @@ sequence number of injected frames, may overwrite the fragment number, or reorde and this interferes with our scripts (i.e. our script might incorrectly say a device is secure although it's not). We have confirmed that the following network cards work properly with our scripts: -| Network Card | USB | mixed mode | injection mode | hwsim mode (experimental) | -| ---------------------- | --- | ----------------------- | ----------------------- | ------------------------- | -| Intel Wireless-AC 8265 | No | patched driver | yes | as client | -| Intel Wireless-AC 3160 | No | patched driver | yes | as client | -| Technoethical N150 HGA | Yes | patched driver/firmware | patched driver/firmware | patched driver/firmware | -| TP-Link TL-WN722N v1.x | Yes | patched driver/firmware | patched driver/firmware | patched driver/firmware | -| Alfa AWUS036NHA | Yes | patched driver/firmware | patched driver/firmware | patched driver/firmware | -| Alfa AWUS036ACM | Yes | yes | yes | **yes?** | -| Alfa AWUS036ACH | Yes | no | patched driver | _under development_ | -| Netgear WN111v2 | Yes | patched driver | yes | yes | +| Network Card | USB | 5GHz | mixed mode | injection mode | hwsim mode (experimental) | +| ---------------------- | --- | ---- | ----------------------- | ----------------------- | ------------------------- | +| Intel Wireless-AC 8265 | No | Yes | patched driver | yes | as client | +| Intel Wireless-AC 3160 | No | Yes | patched driver | yes | as client | +| Technoethical N150 HGA | Yes | No | patched driver/firmware | patched driver/firmware | patched driver/firmware | +| TP-Link TL-WN722N v1.x | Yes | No | patched driver/firmware | patched driver/firmware | patched driver/firmware | +| Alfa AWUS036NHA | Yes | No | patched driver/firmware | patched driver/firmware | patched driver/firmware | +| Alfa AWUS036ACM | Yes | Yes | patched driver???? | yes | **yes?** | +| Alfa AWUS036ACH | Yes | Yes | no | patched driver | _under development_ | +| Netgear WN111v2 | Yes | No | patched driver | yes | yes | + +**TODO: Verify 5 GHz and test it in practice.** **TODO: No longer recommend Virtual Machine, but instead show whether it supports 5GHz?** @@ -53,13 +55,13 @@ use a USB2.0 (OHCI + ECHI) controller, because we found the USB3.0 controller to During our own tests, the AWUS036ACM dongle is supported by Linux, but at times was not correctly recognized during our experiments. It may be necessairy to use a recent Linux kernel, and manually -executing `modprobe mt76x2u` to load the driver. This devices then works out-of-the-box without -patched drives. However, we seek feedback from the community on its reliability before recommending -this device. +executing `sudo modprobe mt76x2u` to load the driver. This devices then works out-of-the-box without +patched drives. We also found it to be unreliable when used inside VirtualBox. The AWUS036ACH was tested on Kali Linux after installing the driver using `sudo apt install realtek-rtl88xxau-dkms`. This device is generally not supported by default in most Linux distributions and requires manual installation of drivers. +**modprobe 88XXau rtw_monitor_retransmit=1** We tested the Intel AX200 as well and found that it is _not_ compatible with our tool: its firmware crashes after sending a fragmented frame. @@ -243,18 +245,20 @@ Notable remarks: In case the script doesn't appear to be working, check the following: -1. Check that you are using modified drivers if needed for your wireless network card. +1. Check that no other process is using the network card (e.g. kill your network manager). -2. Check that you are using modified firmware if needed for your wireless network card. +2. Check that you are using modified drivers if needed for your wireless network card. -3. Run the [injection tests](#Network-card-injection-test) to make sure injection is working properly. +3. Check that you are using modified firmware if needed for your wireless network card. -4. Check that you machine isn't generating background traffic that interferes with the tests. In +4. Run the [injection tests](#Network-card-injection-test) to make sure injection is working properly. + +5. Check that you machine isn't generating background traffic that interferes with the tests. In particular, disable networking in your OS, manually kill your DHCP client/server, etc. -5. Confirm that you are connecting to the correct network. Double-check `client.conf`. +6. Confirm that you are connecting to the correct network. Double-check `client.conf`. -6. Make sure the network is using (AES-)CCMP as the encryption algorithm. +7. Make sure the network is using (AES-)CCMP as the encryption algorithm. ## Extended Vulnerability Tests @@ -387,6 +391,54 @@ We recommend cards based on `ath9khtc`. Not all cards that use `iwlmvm` will be using an alternative network card, we strongly recommend to first run the [injection tests](#Network-card-injection-test) to confirm that the network card is compatible. +### Notes on device support + +#### ath9k_htc + +There is a known problem with the `ath9k_htc` driver, used by the Technoethical N150 HGA, TP-Link +TL-WN722N v1.x, and Alfa AWUS036NHA, causing it not to work on kernel 5.7.3 and above. Downgrading +to kernel `5.7.2` fixes this issue for now. More details are available at: + +- https://bugzilla.kernel.org/show_bug.cgi?id=208251 + +- https://bugzilla.redhat.com/show_bug.cgi?id=1848631 + +- https://lore.kernel.org/lkml/CAEJqkgjV8p6LtBV8YUGbNb0vYzKOQt4-AMAvYw5mzFr3eicyTg@mail.gmail.com/ + +#### AWUS036ACM + +The reliability of our `AWUS036ACM` device, which uses the mt76x2u driver, varied depending on how +it was used. We found that: + +- On kernel 5.5.0 this device didn't work properly when connected to a USB3.0 port. In particular, + it kept showing `error: mt7602u_mcu_wait_resp failed with -108` when testing on Kali Linux. The + device did work properly when connected to a USB2.0 port. + + Frame injection in the 2.4 GHz band was also working properly in the above setup. Frame injection + was also working in the 5 GHz band (tested by running the `test-injection,py` script on channel 40 + and capturing the frame using an Intel 3160). + + Strangely, this device refuses to inject frames when: (1) it's a data frame; (2) the destination + MAC address is not all-zeros; and (3) the to-DS and from-DS are both not set. This was independent + of the sender MAC address. Such frames are generally never sent anyway, so this has no practical + impact, but it required us to tweak the `test-injection.py` script to always set the to-DS or + from-DS flags. + + In mixed mode frames using the MAC address of the AP or client as sender MAC address were only + being injected when injected _after_ authentication. Before authenticating, these frames were + dropped. In mixed client/monitor mode, the sequence counter of injected frames was being overwritten. + In mixed AP/monitor mode, we were unable to inject frames towards the client when using the MAC + address of the AP as the sender MAC address _correctly_ (without the sequence counter being + overwritten - we confirmed this with a fragmented ping against a client). + + **TODO: test mixed mode with patched drivers** + + **Note: with an ath9k_htc we cannot inject frames with spoofed MAC addresses before and after** + **authenticating in AP/monitor mode? It does inject frames (incorrectly) in client/monitor mode.** + +- On kernel **X.Y.Z** + + ## TODOs - Confirm each device can detect all vulnerabilities in the recommended modes. diff --git a/research/fragattack.py b/research/fragattack.py index 8b28b7ebd..70f463d3e 100755 --- a/research/fragattack.py +++ b/research/fragattack.py @@ -204,7 +204,7 @@ if __name__ == "__main__": 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-test', default=None, help="Use given interface to test injection through monitor interface.") - parser.add_argument('--inject-selftest', default=False, action='store_true', help="Partial injection test (checks kernel only).") + parser.add_argument('--inject-test-postauth', default=None, help="Same as --inject-test but run the test after authenticating.") 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('--peerip', help="IP of the device we will test.") @@ -242,6 +242,14 @@ if __name__ == "__main__": options.ptype = args2ptype(options) options.as_msdu = args2msdu(options) + # Make the --inject-test-postauth flags easier to check + if options.inject_test_postauth != None: + options.inject_test = options.inject_test_postauth + options.inject_test_postauth = True + + else: + options.inject_test_postauth = False + # Construct the test options.test = prepare_tests(options) if options.test == None: diff --git a/research/fraginternals.py b/research/fraginternals.py index 9906c6ac4..00fab352c 100644 --- a/research/fraginternals.py +++ b/research/fraginternals.py @@ -713,12 +713,12 @@ class Daemon(metaclass=abc.ABCMeta): # 3. Enable monitor mode set_monitor_mode(self.nic_mon) - log(STATUS, f"Using interface {self.nic_mon} to inject frames.") + log(STATUS, f"Using interface {self.nic_mon} ({get_device_driver(self.nic_mon)}) to inject frames.") if self.nic_hwsim: set_monitor_mode(self.nic_hwsim) # 4. Configure test interface if used - if self.options.inject_test: + if self.options.inject_test != None and self.options.inject_test != "self": set_monitor_mode(self.options.inject_test) def inject_mon(self, p): @@ -755,19 +755,25 @@ class Daemon(metaclass=abc.ABCMeta): log(STATUS, f"{self.nic_hwsim}: setting to channel {channel}") log(STATUS, f"{self.nic_mon}: setting to channel {channel}") - if self.options.inject_test: + if self.options.inject_test != None and self.options.inject_test != "self": set_channel(self.options.inject_test, channel) log(STATUS, f"{self.options.inject_test}: setting to channel {channel}") # When explicitly testing we can afford a longer timeout. Otherwise we should avoid it. time.sleep(0.5) - def injection_test(self, peermac): + def injection_test(self, peermac, ownmac, is_postauth): # Only perform the test when explicitly requested - if self.options.inject_test == None and not self.options.inject_selftest: + if self.options.inject_test == None: + return + + # If requested perform the test after authentication + print(self.options.inject_test_postauth, is_postauth) + if self.options.inject_test_postauth != is_postauth: return try: - test_injection(self.nic_mon, self.options.inject_test, peermac) + test_iface = None if self.options.inject_test == "self" else self.options.inject_test + test_injection(self.nic_mon, test_iface, peermac, ownmac) except IOError as ex: log(WARNING, ex.args[0]) log(ERROR, "Unexpected error. Are you using the correct kernel/driver/device?") @@ -941,8 +947,7 @@ class Authenticator(Daemon): # 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) + self.injection_test(clientmac, self.apmac, False) elif "EAPOL-TX" in msg: cmd, clientmac, payload = msg.split() @@ -958,6 +963,8 @@ class Authenticator(Daemon): return self.stations[clientmac].handle_authenticated() + self.injection_test(clientmac, self.apmac, True) + def start_daemon(self): cmd = ["../hostapd/hostapd", "-i", self.nic_iface, "hostapd.conf"] + log_level2switch(self.options) log(STATUS, "Starting hostapd using: " + " ".join(cmd)) @@ -1119,7 +1126,7 @@ class Supplicant(Daemon): # With the ath9k_htc, injection in mixed managed/monitor only works after # sending the association request. So only perform injection test now. - self.injection_test(self.station.bss) + self.injection_test(self.station.bss, self.station.mac, False) p = re.compile("Associated with (.*) successfully") bss = p.search(msg).group(1) @@ -1135,6 +1142,8 @@ class Supplicant(Daemon): # This get's the current keys self.station.handle_authenticated() + self.injection_test(self.station.bss, self.station.mac, True) + def roam(self, station): log(STATUS, "Roaming to the current AP.", color="green") wpaspy_command(self.wpaspy_ctrl, "SET reassoc_same_bss_optim 0") diff --git a/research/libwifi b/research/libwifi index 2d258c920..fa141ba0f 160000 --- a/research/libwifi +++ b/research/libwifi @@ -1 +1 @@ -Subproject commit 2d258c920b4f6b7234387e14d84cbefd8d9a5b5e +Subproject commit fa141ba0f3a0b34fe02e171bd5a299fc794e72fc diff --git a/research/test-injection.py b/research/test-injection.py index 93a972665..879354e10 100755 --- a/research/test-injection.py +++ b/research/test-injection.py @@ -10,6 +10,8 @@ def main(): peermac = "00:11:22:33:44:55" + # TODO: Add a --debug parameter similar to fragattack + subprocess.check_output(["rfkill", "unblock", "wifi"]) set_monitor_mode(options.inject)