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=2 enables both PWE derivation methods per WPA3 specification revision, closing side-channel timing attacks against sae_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=2 will reject connections from clients with broken PMF implementations (certain Android 9 vendor skins, older Intel 7260 firmware). Expected output: hostapd -dd shows RSN: PMF required in association responses; rejected clients log STA 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 = no forces 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 with openssl 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 with ieee80211w=2, inventory failures, and maintain a hostapd.accept_mac allowlist 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 -dd shows WPA: PMF required for all association attempts
  • [ ] eapol_test to RADIUS server fails with untrusted server certificate
  • [ ] wash output empty for all production SSIDs after 5-minute monitor
  • [ ] iw dev wlan0 station dump reports MFP for every associated station
  • [ ] VPN tunnel established within 3 seconds of wireless association; traceroute 198.51.100.1 exits via tunnel interface
  • [ ] Guest client cannot ping6 ff02::1%wlan0 to discover other segment hosts

Further reading