简介:Python破解WiFi密码工具是一份基于pywifi模块的轻量级实践代码,面向网络安全初学者、渗透测试爱好者或有无线安全需求的开发者,旨在帮助用户快速搭建WiFi密码检测环境并验证密钥安全性。压缩包内共有3个文件,两个Python脚本分别承担主程序与密码字典生成功能,批处理脚本则用于一键安装pywifi等依赖模块,整个压缩包仅2KB,小巧易用。这套工具发布后已被超过一万七千三百人学习,说明其具有较高的参考价值。通过研读代码,读者可以掌握pywifi模块的网卡枚举、扫描周围WiFi信号、尝试连接及抓包等核心操作,理解密码本生成与去重的实现思路,同时还能借助批处理文件减少环境配置时间,为进一步开发无线安全检测小工具打下基础。整体而言,非常适合用于Python网络编程实操练手或网络安全课堂补充案例。
1. 把“Python 破解 WiFi 密码工具”当作自家网络自检台:一次遗留密码找回场景
WiFi 密码落在交接文档的某个角落,路由器的管理密码也旧到没人记得。一位开发者在办公室翻了半天,最后用 Python 写了一段口令验证脚本,把手头所有候选口令在自有网络上跑了一遍——名字、电话、默认口令的组合,二十多分钟后其中一个被验证出来。这就是我理解的“Python破解WiFi密码工具”的实际形态:不是电影里那种两秒破网的画面,而是把 WPA2 握手中的验证信息提取出来,用本机计算力对候选密码逐条做比对。
这条链路里真正重要的是“验证”两个字。只要 AP 和客户端完成过一次握手,你就有机会在本地重建同一套密码推导过程;候选密码算出的校验值对不上,就说明源头密码不是它,对上了,答案便确定。整个过程不碰路由器的管理界面,也无需依赖系统漏洞,核心是协议计算。
这篇内容更适合两类人:一类是网络管理员,维护的无线网络密码遗失、需要重新认证设备;另一类是安全测试初学者,想理解弱密码为何在 WPA2-PSK 场景下容易被字典命中,并且把同一套流程用于加固自己的网络。
2. 密码为什么能被“破”:WiFi 认证协议与握手包里的验证痕迹
2.1 从 WEP 到 WPA3:哪些模式能被离线比对
先建立一条底线:WiFi 抓包从来拿不到“明文密码”。无论 WEP、WPA 还是 WPA2,网卡上传送的只是认证会话中的随机数、校验值和加密后的数据帧。所谓密码破解,本质是把抓到的握手信息和本地生成的候选密码做重算比对。协议设计得越严密,留给离线比对的“接口”就越少。
常见的家用与办公无线协议可以分成四档:
| 模式 | 认证方式 | 能否在本地对密码做离线验证 |
|---|---|---|
| WEP | RC4 + 24位 IV | 可以不抓握手,仅凭 IV 碰撞和密文统计分析恢复密钥,历史上已被彻底攻破 |
| WPA/WPA2-PSK | PSK → PMK 四步握手 | 能,抓一次完整握手后即可对密码字典逐条重算 |
| WPA2-Enterprise | 802.1X / RADIUS | 本地重算难度很高,通常要结合认证服务器侧漏洞,不属于个人网络破解范围 |
| WPA3-Personal | SAE / Dragonfly 密钥交换 | 使用协议握手与椭圆曲线,目前不满足常规离线字典攻击的前提 |
现实中最常落入“Python 字典比对”范畴的是第二档:WPA/WPA2-PSK。它普及率高,且把 PSK 派生的 PMK 用于每一步握手验证,验证输入正好是人为设定的 8~63 字节口令。换句话说,只要你能拿到一次完整四步握手,就可以用自己的 CPU 对候选口令做无限次离线测试,失败成本只是硬盘和电费。
2.2 四步握手:哪些字段参与验证
要理解密码如何被验证,必须回到 WPA2-PSK 的握手细节。整个过程分四步,前两步交换随机数,后两步携带校验值:
- AP 向客户端发送 ANonce(AP 侧随机数,32 字节);
- 客户端产生自己的 SNonce(32 字节),同时根据预共享密钥推导 PTK,再回送一段带 MIC 的 EAPOL 消息;
- AP 验证客户端的 MIC,确认客户端确实知道 PMK,随后也发送带自身 MIC 的消息;
- 客户端验证 AP 的 MIC,双向认证完成,开始正常数据通信。
从安全测试角度看,消息 2 和消息 3 是黄金样本:它们既有客户端随机数和 AP 随机数,又有由 PMK 参与计算出的 MIC 字段。想做密码比对时,只需要把候选密码推导成 PMK,再推导成 PTK,然后取 PTK 中的 KCK 重新计算 MIC,与抓到的字段逐字节比较即可。
整个推导链路固定如下:
- PMK = PBKDF2-HMAC-SHA1(口令, SSID, 4096 次迭代, 32 字节)
- PTK = PRF-512(PMK, AP MAC, 客户端 MAC, ANonce, SNonce)
- MIC = HMAC-SHA1(KCK, EAPOL 消息体)
这里的 SSID 不是可有可无的装饰,而是参与 PBKDF2 的加盐输入。同一个密码挂在两个不同 SSID 下,计算出的 PMK 完全不同。早期写工具的人最容易在这点上翻车:把盐写死成常量,结果自己家密码都验证不过。
2.3 计算复杂度与成功率:字典要多大才可能命中
先把结论摆出来:纯 Python 实现的同名脚本是“验证工具”,不是“暴力破解机”。WPA2 的 PMK 推导每次要进行 4096 次 HMAC-SHA1 迭代,普通 CPU 用 Python 实现时每秒只能跑几百到几千个候选口令;如果字典规模上百万,单机要挂几小时甚至几天,只能当离线作业跑。
实际工程里,我一般把候选口令按命中概率排序,而不是按字典长度排序。最优先的是从设备默认型号、场地名称、负责人姓名、手机号前缀、常见年份和吉祥数字拼接出来的几千条组合;其次是常见泄露密码库中的弱口令;最后才轮到完整键盘组合或全字符排列。对大多数家庭网络来说,前三轮组合已经能覆盖相当一部分低强度密码。
还有一条经验:WPA2-PSK 的密码是 8~63 字节,但真正容易命中且适合记忆的密码基本集中在 8~12 位。因此构建字典时要重点处理 8~12 位字串,而不是无脑拉长到 16 位以上。长密码即使结构简单,组合空间也会迅速把纯 Python 脚本拖到不可用。
3. 扫描与抓包环境准备:从无线接口到握手包落盘
3.1 准备能进 monitor 模式的无线网卡与系统环境
想要抓取 WiFi 管理帧和 EAPOL 帧,首先要让无线网卡进入 monitor 模式。这跟日常上网连接 AP 是不同工作方式:普通管理模式只接收发给自己的数据帧,而 monitor 模式会把信道内所有 802.11 帧交给上层协议栈。Python 侧用抓包库监听这个接口即可。
常见做法是先确认无线芯片驱动是否支持。Linux 环境下打开一个普通终端,执行:
iw dev如果输出里有 wlan0 之类的无线接口,再看驱动能不能直接切 monitor:
sudo ip link set wlan0 down sudo iw dev wlan0 set type monitor sudo ip link set wlan0 up iw dev wlan0 info执行完最后一句,interface type 一栏应该显示 monitor。若报错或显示 managed,说明该网卡驱动或固件不支持,最常见的是笔记本自带的某些入门级芯片和廉价免驱 USB 网卡。我自己的习惯是选一张 Linux 下能直接使用开源驱动的 USB 网卡,先在主机上验证iw dev能看到接口,再考虑在虚拟机里用 USB 直通。
虚拟机里操作时有一条常见路径:把无线网卡直通到虚拟机,然后在虚机内抓包。但直通后宿主机会失去这块网卡,抓包的报文量也受虚拟化层影响,现场抓包往往出现延迟和丢帧。做实验可以,正经审计我建议直接用物理机启动系统跑。
3.2 用 Scapy 扫描周边网络并识别加密方式
进入 monitor 模式后,先不分信道地做一轮 Beacon 帧扫描。Beacon 帧是 AP 周期性广播的“自我介绍”,里面带有 SSID、BSSID、信号强度、认证方式等字段。下面脚本会监听 20 秒,把广播出的网络信息简单罗列出来:
from scapy.all import * seen = {} def handle_beacon(pkt): if not pkt.haslayer(Dot11Beacon): return bssid = pkt.addr2 ssid_elt = pkt[Dot11Elt] if pkt.haslayer(Dot11Elt) else None ssid = "" while ssid_elt: if ssid_elt.ID == 0: # 0 号信息元素是 SSID try: ssid = ssid_elt.info.decode("utf-8", errors="ignore") except Exception: ssid = "" break ssid_elt = ssid_elt.payload cap = pkt[Dot11Beacon].cap seen[bssid] = (ssid, cap) print(f"BSSID={bssid} SSID={ssid or '<hidden>'} cap={cap}") sniff(iface="mon0", prn=handle_beacon, timeout=20) print("扫描完成,共发现", len(seen), "个AP")这段代码里,pkt[Dot11Beacon].cap是 capability 字段,能初步区分网络是否启用 WEP、是否允许密钥管理,但判断 WPA/WPA2 是否开启需要读 RSN 信息元素。真实的 WPA2 网络在 Beacon 帧中会有编号为 48 的 RSN IE,代码里没有对它做深度解析,所以只能当作第一遍扫描。生产环境我会再加一段针对 RSN IE 的解析,输出加密套件,否则容易把开 WPA2 的 AP 误判成开放网络。
另一个值得注意的点是信道。Beacon 扫描默认跟随当前接口锁定的信道,如果目标 AP 在 6 信道而你停在 1 信道,什么都扫不到。稳妥做法是在 2.4G 的 1、6、11 三个主信道和 5G 的常用信道轮换,或者在扫描脚本里用sniff的回调收到帧后立刻读取信道号并切过去。后者更贴近实测体验。
3.3 捕获一次四步握手的合法路径
只有 Beacon 信息还不够,要验证密码必须抓到 EAPOL 帧。难点不在工具,而在“如何让网络中发生一次握手”。
最稳妥且合法的做法是连接你自己拥有管理权限的网络:先正常连接上这个路由器的 SSID,然后在另一终端同时开着抓包脚本,断开再重连自己的网卡,触发新的四次握手。执行动作是对自己的设备和自己的网络,不向其他客户端发送任何干扰帧,边界非常清晰。
抓包脚本可以这样写:
from scapy.all import * eapol_pkts = [] def save_eapol(pkt): if pkt.haslayer(EAPOL): eapol_pkts.append(pkt) print(f"捕获到 EAPOL 帧,长度 {len(pkt)}") sniff(iface="mon0", prn=save_eapol, timeout=120) if eapol_pkts: wrpcap("handshake.pcap", eapol_pkts) print("共保存", len(eapol_pkts), "个 EAPOL 帧")重连动作本身用标准网络管理命令即可,例如 Linux 下关闭再启动无线接口,或者直接从桌面网络的连接面板断开再连。只要曾经的连接配置还在,重连过程就会自动完成认证。如果重连后发现 pcap 里只有一条 EAPOL 帧,往往是因为抓包启动太晚,错过了消息 1 和消息 2,需要把timeout拉长并重新触发。
整个方案里没有攻击性发包,所以即使把抓包对象换成办公室自己负责的路由器,也不会因为工具本身带来额外风险。但有一点必须立住:抓包前请确认你对这个 AP 有管理授权,不要拿同一套流程到陌生无线网络上做实验,后者的安全边界完全不同。
4. 离线验证核心:用 Python 推导 PMK 与 PTK
4.1 从 pcap 提取 EAPOL 帧与关键随机数
抓到 handshake.pcap 后,下一步是把里面的 EAPOL 帧拆出来。Scapy 读取 pcap 很方便,过滤逻辑也直观:
from scapy.all import * pkts = rdpcap("handshake.pcap") eapol_frames = [p for p in pkts if p.haslayer(EAPOL)] print("EAPOL 帧数量:", len(eapol_frames)) for i, f in enumerate(eapol_frames[:6]): print(i, f.summary()) if f.haslayer(Dot11): print(" MAC 源:", f.addr2, " MAC 目的:", f.addr1)这里每一帧的源 MAC、目的 MAC 要重点看方向:消息 2 来自客户端,源 MAC 是连接设备的 MAC;消息 3 来自 AP,源 MAC 是路由器 BSSID。后面计算 PTK 时,AP MAC 与客户端 MAC 的输入顺序是按照字节序取大小值排序的,不是简单按“AP 在前”写死。
随机数 ANonce 和 SNonce 分别藏在消息 1/2 和消息 3 的对应字段里。实际处理时我会先用bytes(f.payload)把 EAPOL 消息整体导出,再按 IEEE 802.11i 的字段偏移去切 ANonce、SNonce、MIC。相比直接依赖 Scapy 高层对象,手动切片在版本变化时更稳定,也更容易定位消息 3 的 MIC 偏移。
4.2 实现 PMK/PTK 计算与 MIC 比对的最小代码
下面这段代码是整条验证链路的数学核心。它先从口令算出 PMK,再从 PMK、双 MAC、双 Nonce 派生 PTK,最后用 KCK 对 EAPOL 消息体做 MIC 校验。为便于阅读,我把 MAC 和 Nonce 的取值先用占位常量写出来,实际使用时从抓包结果替换:
import hashlib import hmac SSID = b"YourSSID" AP_MAC = bytes.fromhex("aabbccddeeff") # 替换为 AP 的 BSSID CLI_MAC = bytes.fromhex("112233445566") # 替换为客户端 MAC ANONCE = bytes.fromhex("按消息1或消息3中AP随机数替换") SNONCE = bytes.fromhex("按消息2中客户端随机数替换") # 消息3的EAPOL原始字节,用于MIC比对 EAPOL3 = bytes.fromhex("从pcap导出的消息3完整EAPOL帧") MIC_OFFSET = 0 # 实际值为MIC字段相对EAPOL帧的偏移,需按协议解析 def derive_pmk(password: str) -> bytes: # WPA2-PSK 的 PMK 只用 SSID 做盐,4096 轮 PBKDF2 return hashlib.pbkdf2_hmac( "sha1", password.encode("utf-8"), SSID, 4096, 32 ) def derive_ptk(pmk: bytes) -> bytes: # PRF-512 实际是迭代 HMAC-SHA1,构造种子的顺序有讲究 # 双方 MAC 和 Nonce 都按字典序升序排列 a_mac = min(AP_MAC, CLI_MAC) b_mac = max(AP_MAC, CLI_MAC) a_nonce = min(ANONCE, SNONCE) b_nonce = max(ANONCE, SNONCE) seed = b"Pairwise key expansion" + a_mac + b_mac + a_nonce + b_nonce ptk = b"" prev = b"" i = 1 while len(ptk) < 64: prev = hmac.new(pmk, prev + seed + bytes([i]), hashlib.sha1).digest() ptk += prev i += 1 return ptk[:64] def verify_mic(ptk: bytes, eapol_msg: bytes, mic_offset: int) -> bool: kck = ptk[:16] # KCK 是 PTK 的前16字节 msg = bytearray(eapol_msg) # 比对前将原 MIC 字段清空,这是 WPA 标准要求 msg[mic_offset:mic_offset+16] = b"\x00" * 16 calc = hmac.new(kck, bytes(msg), hashlib.sha1).digest()[:16] original = eapol_msg[mic_offset:mic_offset+16] return hmac.compare_digest(calc, original) # 示例:对候选口令逐一验证,达到命中的即为正确密码 for candidate in open("candidate.txt", encoding="utf-8"): pwd = candidate.strip() pmk = derive_pmk(pwd) ptk = derive_ptk(pmk) if verify_mic(ptk, EAPOL3, MIC_OFFSET): print("命中:", pwd) break代码里有几个参数必须说明。第一,derive_pmk中SSID是字节串,很多用户从文本文件读取时把字符串直接传进去,结果编码不一致导致 PMK 永远不匹配。第二,derive_ptk内部对 MAC 和 Nonce 做了min/max排序,这是 WPA 规范明确要求的行为,不是程序员任性。第三,mic_offset是消息 3 中 MIC 字段相对 EAPOL 帧的偏移量,实际项目中需要用协议解析或 hex 手工定位;不同驱动封装出来的 pcap 帧头长度可能不同,不能直接用常量硬编码。
这一小段代码说明,所谓“破解工具”本质上是一台复读机:你把候选口令喂进去,它把协议算一遍,比对结果,输出命中。计算慢的部分全在 PBKDF2 上,单线程跑十万条纯 Python 大约需要数十分钟到数小时,因此第 2.3 节说的字典优先级才如此重要——顺序排得越合理,命中来得越早。
4.3 构造有效口令表:不是键盘组合越多越好
口令表构造是不亚于算法的一步。很多初学的人喜欢生成全字符组合或超长字典,但纯 Python 的验证速率摆在那里,几百万条组合会让脚本跑成“数点几小时的进度条”。真正有回报的是按使用者习惯去重建记忆候选。
我一般先收集现场线索,再程序化拼接。比如路由器的管理后台有旧密码痕迹、网络名里有固定词根、负责人常用手机号和生日等,都可以作为基础词元:
ssid_name = "home" owner_name = "zhang" year_list = ["2022", "2023", "2024"] nick_list = ["zhang", "z3", "admin", "home", "123456", "888888"] tail_list = ["", "123", "1234", "666", "888", "@", "!", "2023", "2024"] with open("candidate.txt", "w", encoding="utf-8") as f: for base in nick_list: for tail in tail_list: f.write(base + tail + "\n") f.write(owner_name + base + "\n") for y in year_list: f.write(base + y + "\n")注意别把文件生成得太大再交给脚本。正确的顺序是先让成几百条“高概率组合”,跑一跑验证流程,再决定要不要扩展到几千条。如果第一条线索方向错了,扩展几千条往往也是白跑。我会在每次扩展前先抽 20 条自己在命令行里直接验证算法无误,再全量提交,省得把“算法有 bug”误判成“字典没覆盖”。
5. 常见问题排查:抓包与比对环节最容易翻车的五个细节
5.1 monitor 模式开启成功但代码抓不到任何帧
现象:iw dev能看到接口,set type monitor也不报错,但 Python 脚本跑 30 秒,回调一次都没触发。
原因:最常见的两类。一是虚拟机没做 USB 直通,或直通后宿主抓包干扰;二是无线网卡在驱动层仍处于 managed 状态,set type monitor只是驱动做了标记,但固件没有真正切换。
解决:先在物理机上用iw dev wlan0 info确认接口类型确实为 monitor;如果确认无误但仍无数据,用tcpdump -i mon0排查 Scapy 层问题。仍无数据就换另一张网卡,优先选带常见 monitor 方案芯片的 USB 网卡。
5.2 捕获的 EAPOL 帧数量不少但无法完成验证
现象:pcap 里确实有 EAPOL 帧,但按消息 3 的偏移去做 MIC 比对时怎么也匹配不上,甚至字段里找不到完整 ANonce。
原因:抓到的往往是重复的消息 1 或仅消息 2,没有完整四步握手;或者重连太快,消息 2 携带的 MIC 对应的 PMK 来自旧的认证会话。驱动缓存、信道切换延迟都会造成这种“看似抓到实则缺帧”的情况。
解决:把抓包脚本的 timeout 拉长到 120 秒以上,重连后等网络从“连接中”变成“已连接”再等几秒;抓完后先统计帧里出现了几个方向的 EAPOL 源 MAC。严格来说,最少需要消息 2 和消息 3 的配对,才能完成一次完整比对。
5.3 已知正确密码却算出 MIC 不匹配
现象:字典里明明有这个密码,甚至拿管理后台确认过的密码去试,验证结果还是 False。
原因:九成是 MAC 排序或 Nonce 顺序错了。derive_ptk里先做min/max再做拼接,不能按消息源先后顺序写死;另外 ANonce 可能来自消息 1 或消息 3,但 PTK 计算时只需要两个随机数对应的值,不能用错。
解决:把 AP_MAC、CLI_MAC、ANonce、SNonce 分别打印成十六进制串核对:MAC 各 6 字节,Nonce 各 32 字节。确认后再回归测试整个流程。
5.4 字典文件巨大,脚本跑了一夜还没结束
现象:日志一直输出当前密码但始终未命中,进度缓慢。
原因:纯 Python 做 PBKDF2 的计算上限很低,百万级字典属于纯蛮干。这类脚本适合的是高概率组合,不是全量空间枚举。
解决:先用前面 4.3 节生成几百条高概率组合验证流程;确认算法无误后,再按命中优先级分批跑。每批控制在五千条以内,超过这个量建议考虑并行分片,或用专业并行计算方案替代纯 Python。
5.5 顺手把脚本用到了别人的网络上
现象:为了“试试工具好不好使”,拿邻居或公司公共路由器的握手包跑了同样的候选字典。
原因:技术上完全能跑,但这条行为的性质已经从“找回自己的密码”变成未经授权的验证行为。路由器的日志、审计记录可以关联异常抓包,一旦被举证,责任边界非常不利。
解决:没有解决,只有不做。我会把这套流程严格限制在拥有管理权限的 AP 上;对公共网络、雇员个人网络、陌生热点,一律视为红线。审计不是为了证明工具能破解,而是为了发现自己负责的网络哪里薄弱。
6. 把破坏性链路倒过来:用同一套流程给你的 WiFi 做安全自检
做到最后,真正值得保留的不是“破解”动作,而是那套计算链路反向暴露出来的防御信息。我每半年会对自己管理的无线网络做一次自检,步骤很简单:
先看协议版本。如果还有旧设备强制使用 WEP,直接淘汰;能用 WPA3 就切 WPA3,不能就至少保证所有连接设备支持 WPA2/AES。测试时可以拉一张表记录每个 SSID 的加密类型和是否启用 WPS PIN,WPS PIN 是另一个比密码字典更省力的入口。
再看口令强度。用前面 4.2 的验证逻辑配合 4.3 的候选生成,对当前 WPA2-PSK 密码做一次低强度字典抽测。如果抽测的前一万条里出现自己家的密码,说明密码结构太常见,立刻改成 16 位以上、包含大写、小写、数字、符号四类字符的独立密码,并避免同一密码在两个 SSID 上重用。
最后查连接记录。很多路由器后台会保存最近连接的客户端列表,把陌生 MAC 和抓包脚本里的活跃客户端做比对,看有没有异常设备持续在低信道反复重连。真正需要警惕的不是有人拿 Python 跑字典,而是有人连进网络后横向探测内网资产。密码自检只能降低第一道门风险,不能替代持续监控。
我自己留下的习惯是把这套脚本固定在指定目录里,每次换密码后主动跑一遍最弱五条候选,当作给新口令做的发烟测试。新密码如果连“admin+年份+感叹号”这类组合都扛不住,说明复杂度规划形同虚设。整个过程不依赖额外硬件,一台带 monitor 模式网卡的笔记本足够。希望帮到你。
本文还有配套的精品资源,点击获取