Defensive Architecture and Hardening Configuration
WPA3 Deployment and Downgrade Prevention
WPA3-Personal in transition mode exposes a critical vulnerability: it advertises both SAE and WPA2-PSK simultaneously, allowing clients to connect via the weaker handshake. The configuration must enforce PMF and restrict the downgrade window.
# hostapd.conf — WPA3-Personal transition mode with downgrade controls
interface=wlan0
ssid=CorpSecure
wpa=2
wpa_key_mgmt=SAE WPA-PSK
wpa_passphrase=legacy_for_transitional_clients_only
sae_password=high_entropy_sae_pmkid_resistant
ieee80211w=2 # 1=optional, 2=required — required blocks WPA2-only clients
sae_require_mfp=1
sae_pwe=2 # hunting-and-pecking + hash-to-element, mitigates timing leaks
ieee80211w value |
Effect | Downgrade risk |
|---|---|---|
| 0 | Disabled | PMF-capable clients may omit protection; trivial deauth possible |
| 1 | Optional | Client negotiates per-association; attacker forces "no PMF" |
| 2 | Required | Refuses non-PMF associations; breaks older clients intentionally |
What it does:
sae_pwe=2enables both PWE derivation methods per WPA3 specification revision, closing side-channel timing attacks againstsae_pwe=0(hunting-and-pecking only). When to use it: All new WPA3 deployments; transition mode only while legacy clients are being inventoried and replaced. Risks:ieee80211w=2will reject connections from clients with broken PMF implementations (certain Android 9 vendor skins, older Intel 7260 firmware). Expected output:hostapd -ddshowsRSN: PMF requiredin association responses; rejected clients logSTA refused due to PMF policy.
Verification that PMF is actually enforced, not merely configured:
# Lab: Capture association response to confirm PMF capability field
tshark -i wlan0mon -Y "wlan.fc.type_subtype==0x01" -T fields \
-e wlan.rsn.capabilities.pmf -e wlan.tag.rsn.akm.suites
# Production: Passive audit of current associations
iw dev wlan0 station dump | grep -E "station|capability"
Realistic output interpretation:
aa:bb:cc:dd:ee:ff
station capab: 0x3 # 0x2 bit = PMF capable, 0x1 bit = PMF required
f0:de:f1:2a:3b:4c
station capab: 0x1 # Claims capable but not requiring — audit this client
The 0x1 value for the second client warrants investigation: it will accept associations without PMF if the AP advertises optional mode. Transition mode with ieee80211w=1 is exactly what an evil twin AP uses to harvest WPA2 handshakes.
Enterprise EAP Method Selection
The RADIUS EAP module loading order determines which methods are offered to supplicants. Weak methods must be explicitly removed, not merely deprioritized.
# /etc/freeradius/3.0/mods-enabled/eap — disable everything except TLS-based
eap {
default_eap_type = tls
tls-config tls-common {
private_key_file = /etc/freeradius/3.0/certs/server.key
certificate_file = /etc/freeradius/3.0/certs/server.pem
ca_file = /etc/freeradius/3.0/certs/ca.pem
dh_file = ${certdir}/dh
verify {
skip_if_ocsp = no
}
}
# Explicitly disable: peap, ttls, md5, leap, pwd, gtc
# Do not comment out — remove or set to 'disable = yes'
}
| Method | Mutual auth | Channel binding | Downgrade risk | Verdict |
|---|---|---|---|---|
| EAP-TLS | Yes (cert+privkey) | Native via TLS | None | Baseline for high-assurance networks |
| PEAP-EAP-TLS | Yes | Nested TLS + inner TLS | PEAP phase allows MSCHAPv2 fallback if misconfigured | Only if supplicant locks inner method |
| EAP-TTLS | Server cert only | Optional inner | PAP/CHAP/MSCHAPv2 inner methods are credential-harvesting bait | Avoid — complexity without security gain |
| PEAP-MSCHAPv2 | Server cert only | No | Credential relay trivial with Responder or Hostapd-WPE | Deprecated; equivalent to clear-text for motivated attacker |
What it does:
skip_if_ocsp = noforces OCSP stapling or direct OCSP verification; a missing response fails authentication rather than silently continuing. When to use it: Certificate-lifecycle automation is operational (OCSP responder reachable, CRL distribution points valid). Risks: OCSP responders become single points of failure; monitor withopenssl ocsp -url $responder -issuer ca.pem -cert client.pem.
Production variant for certificate validation without OCSP dependency:
# Safer: CRL checking with local caching
crl_file = /etc/freeradius/3.0/certs/crl.pem
check_crl = yes
check_all_crl = yes
Supplicant-side pinning prevents evil twin RADIUS proxies:
# wpa_supplicant.conf — network block with CA pinning and server name check
network={
ssid="CorpSecure-EAP"
key_mgmt=WPA-EAP
eap=TLS
identity="[email protected]"
ca_cert="/etc/certs/corp-ca.pem"
subject_match="/CN=radius01.corp.example"
# Block any server presenting different CN or untrusted CA chain
altsubject_match="DNS:radius01.corp.example;DNS:radius02.corp.example"
}
802.11w (PMF/MFP) Enablement and Client Reality
Vendor documentation claims PMF support; actual behavior diverges. The Windows 10/Surface Pro case—netsh wlan show profiles reports PMF support, yet association fails when PMF is required—indicates driver-level negotiation failure despite OS capability advertisement.
| Client platform | Advertised PMF | Required PMF functional | Notes |
|---|---|---|---|
| Windows 10/11 (Intel AX200+) | Yes | Yes | Driver-dependent; 22.x PROSet required |
| Windows 10 (Surface Pro 2017, Marvell) | Yes | No | OS claims support, driver rejects required mode |
| macOS 12+ | Yes | Yes | No known required-mode failures |
| iOS 14+ | Yes | Yes | |
| Android 10+ (AOSP) | Yes | Yes | Vendor skins may disable in firmware |
| Android 9 (Samsung Exynos) | Partial | No | wpa_supplicant compiled without PMF required |
| Embedded/IoT (various) | Uncommon | Rare | Industrial WiFi modules often omit 802.11w |
Hard-won insight: A client associating successfully with
ieee80211w=1(optional) proves nothing about its PMF implementation. Test withieee80211w=2, inventory failures, and maintain ahostapd.accept_macallowlist for exceptions—tracked as technical debt with remediation dates.
Cisco IOS XE configuration (9800 series, 17.16.x track):
! Verify PMF operational state, not merely configured
wireless profile policy CorpSecure-Policy
security wpa wpa2 wpa3
security 802.11w
security 802.11w pmf mandatory ! Not optional, not default
no security wps ! Explicit disable, not implicit absence
! Audit actual client capability advertisement
show wireless client summary detail | include PMF
show wireless client mac-address aa:bb:cc:dd:ee:ff detail | sec Capabilities
Network Segmentation Architecture
Wireless segmentation fails when VLAN hopping or AP management plane compromise bridges isolation. The architecture must assume AP breach.
[Internet] → [Firewall] → [Core L3 Switch]
|
+-------------------+-------------------+
| | |
[WLC/Native] [Wireless DMZ VLAN] [Guest VLAN]
(management) (corporate SSID) (captive portal)
| |
[RADIUS DMZ] [Data VLAN 10]
(auth backend) (wired equivalent)
# hostapd with VLAN tagging per SSID, enforced at AP
vlan_file=/etc/hostapd.vlan
dynamic_vlan=2 # RADIUS-Assigned VLAN mandatory
# /etc/hostapd.vlan
* wlan0.#
10 wlan0.10
20 wlan0.20
| Segmentation layer | Control | Failure mode |
|---|---|---|
| SSID/VLAN mapping | AP config | Same-SSID VLAN override via RADIUS spoofing |
| RADIUS VLAN assignment | Auth backend | Compromised RADIUS → arbitrary VLAN placement |
| ACL between VLANs | L3 switch/firewall | Misconfigured native VLAN trunking |
| Guest isolation | AP client isolation + L2 ACL | IPv6 ND/RA bypasses IPv4-only ACLs |
Guest isolation must block not merely unicast but multicast/broadcast discovery:
# Bridge-level isolation with multicast suppression
ebtables -A FORWARD -i wlan0-guest -o wlan0-guest -j DROP
ebtables -A FORWARD -p IPv6 --ip6-protocol ipv6-icmp -j DROP
WPS Disable Verification and Entropy Analysis
WPS PIN mode uses a static 8-digit code with checksum, yielding 10^7 effective combinations and online bruteforce feasible in hours. The "HACK ME" characterization is accurate: WPS was designed for pairing convenience with no threat model for physical proximity attackers.
# Verify WPS is absent from beacon and probe response, not merely disabled in UI
wash -i wlan0mon -C # Monitor mode WPS detection
# Expected: target SSID absent from wash output
# Failure: SSID appears with "Locked" status — WPS present, temporarily throttled
PIN generation entropy audit for unavoidable WPS deployments (legacy IoT):
# Extract PIN from nvram/firmware for analysis
strings /dev/mtd0 | grep -E '^[0-9]{8}$' | while read pin; do
checksum=$(( (10 - (3*$(echo $pin | cut -c1) + 1*$(echo $pin | cut -c2) + \
3*$(echo $pin | cut -c3) + 1*$(echo $pin | cut -c4) + \
3*$(echo $pin | cut -c5) + 1*$(echo $pin | cut -c6) + \
3*$(echo $pin | cut -c7)) % 10) % 10 ))
[ "$checksum" -eq "$(echo $pin | cut -c8)" ] && echo "VALID WPS PIN: $pin"
done
| Finding | Risk | Action |
|---|---|---|
| PIN derived from MAC address (algorithmic) | Trivial prediction | Replace firmware or retire device |
| PIN static across device model | Batch compromise | Vendor disclosure, network isolation |
| PIN "random" but low entropy (LCG seed) | Recoverable from serial | Custom RNG reimplementation if possible |
| WPS push-button only, no PIN | Reduced attack surface | Acceptable for physically secured locations |
Client Configuration Hardening
Proactive scanning creates probe request fingerprints and exposes preferred network lists. Suppress this behavior and restrict automatic connections.
# wpa_supplicant.conf — probing suppression and network profile lockdown
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
ap_scan=1
fast_reauth=0 # Disable EAP fast reauth; prevents session resumption abuse
network={
ssid="CorpSecure"
scan_ssid=0 # Do not actively probe for hidden SSID
key_mgmt=WPA-EAP
# Lock to specific BSSID prevents roaming to evil twin with same SSID
bssid=00:11:22:33:44:55
# Disable automatic connection; require explicit user action
disabled=1
}
# systemd service override for VPN auto-connect on wireless association
# /etc/systemd/system/wpa_supplicant.service.d/vpn-up.conf
[Service]
ExecStartPost=/usr/local/bin/wireguard-up-on-assoc.sh
VPN auto-connect script with association validation:
#!/bin/bash
# wireguard-up-on-assoc.sh — only bring tunnel up on authorized BSSID
AUTHORIZED_BSSIDS="00:11:22:33:44:55 00:11:22:33:44:66"
CURRENT_BSSID=$(wpa_cli status | grep bssid | cut -d= -f2)
if echo "$AUTHORIZED_BSSIDS" | grep -qw "$CURRENT_BSSID"; then
wg-quick up corp-tunnel
# Apply strict routing: tunnel is default, wireless is stub only
ip route add 192.0.2.0/24 dev wlan0 scope link table 42
ip rule add from 192.168.1.0/24 lookup 42
else
logger -p auth.warning "VPN suppressed: unauthorized BSSID $CURRENT_BSSID"
# Option: deauthenticate immediately
# wpa_cli disconnect
fi
Common mistakes:
| Mistake | Why it bites you |
|---|---|
ieee80211w=1 on AP, optional on supplicant |
Attacker advertises ieee80211w=0, both sides silently downgrade |
| Certificate CN match only, no SAN check | Evil twin uses legitimate CA + different SAN; CN validation passes |
RADIUS check_cert_cn without check_cert_exp |
Revoked but unexpired attacker certificate accepted |
| Guest VLAN with IPv6 unfiltered | IPv6 RA hijacking bypasses entire IPv4 ACL architecture |
| WPS "disabled" in web UI, not in firmware | Wash still detects WPS IE; PIN mode active at 802.11 level |
ap_scan=2 with autoscan periodic |
Continuous background probing exposes travel patterns and home network SSIDs |
Configuration verification checklist:
- [ ]
hostapd -ddshowsWPA: PMF requiredfor all association attempts - [ ]
eapol_testto RADIUS server fails with untrusted server certificate - [ ]
washoutput empty for all production SSIDs after 5-minute monitor - [ ]
iw dev wlan0 station dumpreportsMFPfor every associated station - [ ] VPN tunnel established within 3 seconds of wireless association;
traceroute 198.51.100.1exits via tunnel interface - [ ] Guest client cannot
ping6 ff02::1%wlan0to discover other segment hosts