资讯动态

Python+pywifi实现Wi-Fi弱口令自查与无线安全巡检

发布时间:2026/10/20 7:05:19 来源:尧图企业网站定制
简介基于Python pywifi模块的WiFi密码破解工具包面向无线网络安全学习者和Python开发者用于实战理解弱密码检测、WiFi安全评估以及pywifi库的典型调用方式。资源共3个文件包含2个Python脚本和1个bat批处理Python脚本分别承担密码破解主程序与字典密码本自动生成批处理用于一键安装所需依赖模块整个压缩包仅2KB轻量便捷几乎不占用存储空间。目前已有超过1.7万人学习下载热度较高。借助该工具包使用者可直接获得可运行的破解脚本、可定制的密码本生成逻辑以及一键装好pywifi等依赖的批处理能快速完成环境搭建并上手实验。在此基础上可自行扩展字典内容、调整握手包捕获策略用于教学演示或个人安全测试是理解WiFi认证机制与Python自动化脚本编写的简明样例也适合作为网络安全入门项目的参考。1. 破解工具还是自查脚本先搞清楚「Python 破解 wifi 密码」到底能做什么网上流传的「Python 破解 wifi 密码工具」九成是拿 pywifi 库包了一层壳真正花时间的从来不是“破解”这个动作而是三件事让无线网卡在大批量重连下不崩、准备一份大概率命中的密码字典、把超时和重试调到一个不会误报、又不至于慢到天荒地老的区间。这篇文章就按从业方案把这三件事拆开讲。定位先说清楚它最合法的用途是自查——拿自己家、自己办公室的无线接入点验证默认口令和弱口令也能帮运维做内网无线基线检查。适合两类人一类是想用 Python 把无线安全测试走通的新手另一类是被「员工私自开了一个弱口令热点」折腾过的运维。需要授权的场景请先拿授权下文所有代码都默认跑在你有权测试的设备上。2. 选型与环境为什么是 pywifi以及把网卡调到能扫到信号的状态2.1 pywifi 是这个场景的默认选择它封装了什么做无线密码验证业界最常见的方案是 pywifi。它跨平台封装了系统无线网卡驱动对协议栈的调用你不需要知道 802.11 管理帧怎么构造也不需要进入监控模式。它的核心抽象是一个 Profile配置档案——一个 Profile 就是一次认证请求的完整描述包含 SSID、认证算法、密钥管理协议、加密方式和预共享密钥。pywifi 把「把这段配置塞给网卡→发起连接→轮询连接状态」整个过程做成了几个普通函数这正是批量弱口令验证最需要的。对比纯 scapy 或者裸 socket 方案scapy 要监听握手包、要网卡支持监控模式、还要手动处理 802.11 帧结构入门门槛高一大截。而且 WPA2-PSK 的认证过程并不对普通帧构造开放你很难只靠拼包完成一次真实的密钥协商。pywifi 走的是正规接入流程——网卡像普通设备一样发起连接密码对不对由 AP 返回的认证结果说了算。这不是绕过是模拟真实设备去试密码正好符合自查场景。另外 pywifi 对硬件的依赖低只要是系统能正常连接 Wi-Fi 的网卡它就能用。不像某些方案要求网卡必须支持 monitor 模式直接淘汰了一大半笔记本自带网卡。在我用过的方案里pywifi 是唯一一个「一个库管三平台」的选择Windows、Linux、macOS 都有接口只是表现差异很大这点在 2.3 里单独讲。2.2 环境搭建装库、跑通第一段扫描代码先装依赖。pywifi 的安装很简单但有个细节Linux 上部分发行版还需要装无线扩展工具包否则底层调用会被系统拒绝。# Windows / macOS pip install pywifi # Ubuntu / Debian 系除了 pip 还要装无线工具 sudo apt install wireless-tools pip install pywifi装完之后不要急着写破解循环先跑一段最基础的扫描验证确认 pywifi 真的拿到了无线网卡的控制权。这段代码我每次搭新环境都会先跑一遍能排除掉八成环境问题。import pywifi from pywifi import const # 初始化无线接口 wifi pywifi.PyWiFi() # 获取本机无线网卡接口列表 ifaces wifi.interfaces() if not ifaces: print(没有可用的无线网卡检查驱动或外部USB网卡) exit(1) # 取接口列表里的第一个作为默认测试接口 iface ifaces[0] print(f使用接口: {iface.name()}) # 触发一次主动扫描 iface.scan() time.sleep(3) # 给网卡留出扫描时间太短会扫不齐 # 读取扫描结果 scan_result iface.scan_results() print(f扫描到 {len(scan_result)} 个网络) for item in scan_result[:5]: print(fSSID: {item.ssid}, 信号强度: {item.signal}) print(f 认证: {item.auth}, AKM: {item.akm}, 加密: {item.cipher})这段代码的逻辑很简单拿到接口列表选第一个触发扫描读结果。关键是那个time.sleep(3)——pywifi 的scan()是异步的它只是发一个扫描指令给网卡就返回了真正的扫描过程在后台跑。如果紧接着就读scan_results()大概率拿到空列表这不是网卡坏了是没等它扫完。我一般会 sleep 3 到 5 秒扫得越全、后续字典匹配越有底。iface.name()在 Windows 上一般是「WLAN」或者某张无线网卡的商品名在 Linux 上一般是wlan0、wlx...这种接口名。看到接口名就说明调用打通了。扫描结果里每一项的signal是信号强度负值越接近 0 信号越好auth/akm/cipher三个字段在后面构造 Profile 时要用到照着扫描结果里的真实值去回填 Profile是减少误报的关键习惯。2.3 三个平台的差异与选卡建议不同系统跑 pywifi 的体验差很多踩过一遍之后我给新人的建议是首选 Linux其次 WindowsmacOS 基本别碰。平台扫描表现连接可靠性典型坑Linux良好好需要有 NetworkManager 或 wpa_supplicant 在跑无桌面环境要手动起服务Windows良好中等驱动频繁增删配置档案后会假死建议配合重置网卡命令macOS差差系统权限控制严格经常拿不到完整扫描列表不建议投入笔记本自带网卡在 Linux 下通常表现不错特别是常见 Intel 无线网卡驱动开箱即用。外置 USB 网卡里某国产芯片如常见的 RTL8811/8812 系列在 Linux 下兼容性更好Windows 下反而需要装官方驱动才能被 pywifi 正常控制。还有一点虚拟机里跑 pywifi 基本白费力气除非你把 USB 网卡直通给虚拟机否则它看到的还是虚拟网卡扫不到任何真实 AP。在 Windows 上跑长耗时任务时我通常会先手动执行一次netsh wlan disconnect让无线状态复位然后让 Python 脚本纯靠 pywifi 的 connect 流程走。两步分开避免系统自带无线管理器和脚本抢网卡控制权。看到「系统自动弹出 Wi-Fi 连接提示」就说明网卡被系统接管了脚本这边会开始迟迟拿不到结果。3. 从扫描到连接验证写一个能跑的弱口令检测主循环3.1 一次验证的三步走扫描 → 构造 Profile → 校验结果核心循环本身没有玄学三步把目标 AP 的 SSID 拿出来逐个密码构造 Profile发起 connect然后轮询网卡状态直到超时。关键在于第二步和第三步的细节。构造 Profile 时auth/akm/cipher这三个参数如果填错密码再对也连不上。现实中不同路由器的出厂配置五花八门——老路由器可能只开 WPAAKM_TYPE_WPAPSK新一点的路由器默认 WPA2-PSKAKM_TYPE_WPA2PSK还有 WPA/WPA2 混合模式。保守做法是优先按扫描结果里读到的真实参数回填如果扫描结果为空隐藏 SSID 的 AP 常见再用一组最常见的组合去试——OPEN 认证 WPA2PSK CCMP这套组合覆盖了绝大多数家用路由器。校验结果的逻辑要独立成一个函数不要写在主循环里。因为连接等待是一个「发起后轮询」的过程不是发完就 sleep一个独立函数方便你针对不同网卡调整轮询策略。3.2 主循环代码单密码验证函数与批量调度下面这段是我常用的验证函数骨架单独抽出来方便复用import time import pywifi from pywifi import const def try_connect(iface, ssid, password, timeout10): 尝试用指定密码连接目标SSID返回是否连接成功。 iface: pywifi 的 Interface 对象 ssid: 目标无线网络名称 password: 待验证的密码 timeout: 最长等待时间秒不是死等是轮询上限 # 构造一个连接档案Profile profile pywifi.Profile() profile.ssid ssid profile.auth const.AUTH_ALG_OPEN profile.akm.append(const.AKM_TYPE_WPA2PSK) profile.cipher const.CIPHER_TYPE_CCMP profile.key password # 移除当前所有连接档案避免干扰 iface.remove_all_network_profiles() # 把待验证的档案加入网卡 tmp_profile iface.add_network_profile(profile) # 发起连接 iface.connect(tmp_profile) # 轮询等待连接结果到超时为止 start time.time() while time.time() - start timeout: status iface.status() if status const.IFACE_CONNECTED: return True if status const.IFACE_DISCONNECTED: break # 快速失败不用等满超时 time.sleep(1) # 超时但仍未连上主动断开避免影响下一轮 iface.disconnect() return False这段代码的逻辑拆开看Profile()是连接档案的容器profile.ssid是目标名profile.key是待验证的密码。auth用 OPEN 是认证算法不是加密方式别被名字误导——在 WPA2-PSK 里认证算法就是 OPEN密钥管理协议才是决定密钥协商方式的字段。akm是一个列表所以要用append。加const.AKM_TYPE_WPA2PSK表示用 WPA2 的预共享密钥模式。cipher是数据加密算法CCMP 就是 AES现在绝大多数路由器默认都是它。老路由器如果只支持 TKIP把这里改成const.CIPHER_TYPE_TKIP即可。轮询那段是重点。iface.status()在连接过程中会返回多种状态IFACE_CONNECTING表示正在协商IFACE_CONNECTED表示已连上IFACE_DISCONNECTED表示被拒绝或断开。用 while 循环每秒查一次状态比time.sleep(timeout)死等要科学得多——密码错误时 AP 一般在 2-3 秒内就会拒绝等满 10 秒纯属浪费时间。看到IFACE_DISCONNECTED就及时 break整个批量任务的耗时能直接砍掉一半以上。3.3 批量调度怎么安排顺序不会把网卡跑崩单密码验证没问题之后批量只是加一层循环。但调度顺序有几个原则都是拿时间换出来的经验第一不要对同一个 AP 连续快速重试。家用路由器很多都带暴力破解防护连续失败几十次后会临时锁定这个客户端的 MAC。我一般每试一个密码后固定等 2-3 秒再做下一次虽然慢一点但能避免触发锁定。第二每验证 30 到 50 个密码后重置一次网卡状态。调用remove_all_network_profiles()在 Windows 上有个副作用频繁调用会把无线配置服务搞乱导致网卡在系统里处于「忙碌」状态。稳妥做法是每批密码之间只调用一次或者干脆循环里不调用只在开始前清理一次。上面那个try_connect里每次调用remove_all_network_profiles()是一种简化实际批量时我会把它挪到循环外面每 30 次调用一次。第三先跑大概率命中的集合再跑大字典。这个放到第 4 章的字典策略里一起说。调度顺序本身就是一种优化策略跟算法一视同仁。4. 字典与规则最高性价比的候选密码集怎么生成4.1 弱口令的真实分布默认口令、手机号、生日、姓名首拼真正决定这个工具跑多久的不是代码效率是候选密码集的组织方式。我自己采集过一批授权测试场景下的弱口令样本高频弱口令能分成四类第一类是路由器出厂默认口令比如家用光猫背后贴纸上的初始密码第二类是纯数字短密码8 位全数字为主流第三类是有个人信息特征的手机号后 8 位、生日八位、姓名首字母加生日第四类是拼音加数字组合比如zhangsan123这种。这里有个反直觉的结论长度较长的密码不一定比短密码更难猜中。因为大多数人在设置 8 位以上密码时用的还是「固定的单词/拼音 固定的数字尾缀」这个模式一旦你猜中了那个模式整个密码就暴露了。所以我做候选集的时候不按长度排列而是按「规则覆盖度」排列——先命中模式再扩充随机段。4.2 用规则生成局部字典不依赖现成大字典的做法网上能下到大字典但不一定适合目标场景。我推荐根据目标 SSID 或使用者信息生成局部字典命中率远高于通用字典。代码用itertools生成组合可控、不臃肿from itertools import product from typing import List def build_candidate_set( keywords: List[str], year_start: int 1990, year_end: int 2024, phone_tails: bool True, ) - set: 根据关键词和常见数字模式生成候选密码集。 keywords: 可能的姓名拼音、公司简称、路由器型号名等 year_start/year_end: 生日年份区间用于生成 8 位生日 phone_tails: 是否生成手机号后四位尾号组合 candidates set() # 1. 纯数字 8 位基础集合 for i in range(10000000, 99999999, 1234): # 稀疏采样控制体量 candidates.add(str(i)) # 2. 关键词 数字尾缀覆盖 zhangsan123 / admin2023 这类 digits [123, 1234, 12345, 666, 888, 2023, 2024] for kw in keywords: for d in digits: candidates.add(f{kw}{d}) candidates.add(f{kw.lower()}{d}) # 3. 八位生日YYYYMMDD 与 MMDDYYYY common_days [0101, 0520, 0808, 1001, 1212, 0101] for year in range(year_start, year_end 1): for day in common_days: candidates.add(f{year}{day}) candidates.add(f{day}{year}) # 4. 手机号规则前三位号段 尾号组合这里只给样例规模 if phone_tails: pref [138, 139, 150, 188, 199] tails [0000, 8888, 6666, 1234, 5678] for p, t in product(pref, tails): candidates.add(p t) return candidates if __name__ __main__: pool build_candidate_set( keywords[admin, owner, wifi, tplink], year_start1990, year_end2024, phone_tailsTrue, ) print(f生成候选密码数: {len(pool)})这段代码展示了规则生成思路不是让你原样照搬。range(10000000, 99999999, 1234)是稀疏采样步长 1234 意味着不会生成完整 9000 万个数字而是均匀抽样——这一步是为了控制时间成本。实际使用时应该先看目标是谁如果是家用路由器关键词优先用路由器型号和户主姓名拼音如果是办公网络优先公司英文名和区号电话。product用来做笛卡尔积组合生成「号段 × 尾号」的完整覆盖这段比较好理解。生成之后把结果存成一个文本文件一行一个密码后续批量验证时逐行读取。这里注意生成规则要带概率权重最可能命中的放前面。我习惯把keywords 常见数字尾缀放最前面生日放中间手机号组合放最后——因为手机号组合猜中概率相对低而形如admin123的默认弱口令命中概率最高。4.3 候选集规模与耗时的换算先跑高概率集批量验证的耗时可以精确估算单密码平均等待时间约 4-6 秒成功 2-3 秒失败更快那么 100 个密码大约 7-10 分钟1000 个密码大约 1-1.5 小时。这个速度决定了你不可能拿完整大字典跑一轮——动辄几十万条跑几天不现实。我一般把候选集切成三档第一档只放 50 个以内交给「默认弱口令 短数字」第二档放 500 个加进个人信息规则第三档才放大字典抽稀后的子集。跑的顺序永远是第一档先跑完命中就停止不浪费时间。工具是给人用的不是用来证明网卡能连续工作多长时间的。候选集规模预计耗时典型命中率50 条默认口令 常见弱口令4-6 分钟覆盖率最高500 条加个人规则40-60 分钟一般场景够用5000 条扩充字典抽稀6-8 小时适合无人值守夜跑这张表是经验值具体看你网卡响应速度和目标 AP 的拒绝策略。如果遇到那种失败 5 次就锁 10 分钟的路由器任何表都没意义——先解决锁定策略再谈字典规模。5. 避坑连续弱口令验证最容易挂的 5 个场景5.1 现象扫描结果始终为空pywifi 列表读不到任何网络原因有几个最离谱也最常见的网卡有多个接口pywifi 默认选的interfaces()[0]根本就是蓝牙虚拟接口或不可用的虚拟 Wi-Fi 接口。这类接口能初始化、能调用扫描但返回结果永远是空。解决打印所有接口名称手动确认哪个是真无线网卡。在 Linux 下用iw dev查看物理接口名Windows 下看网络适配器列表。另外确认网卡没被系统设置成「飞行模式」Ubuntu 上rfkill list可以查看软硬开关状态。我一般先把这段诊断代码跑一遍再进入正式任务import pywifi wifi pywifi.PyWiFi() for i, iface in enumerate(wifi.interfaces()): print(f[{i}] {iface.name()}) iface wifi.interfaces()[0] iface.scan() time.sleep(5) print(扫描结果:, len(iface.scan_results()))5.2 现象验证到中间步骤网卡掉线脚本直接挂死这个在 Windows 上极其常见。跑着跑着Windows 的无线服务WLAN AutoConfig重新扫描了一圈把你刚建立的连接档案弄丢了或者主动断开了。脚本侧表现为status()长时间返回IFACE_DISCONNECTED即便密码正确也一样。解决两层处理。程序层在每轮连接前先检查iface.status()如果处于异常状态就调用一次iface.disconnect()强制让网卡回到空闲状态睡 1 秒再继续。系统层Windows 里在「服务」中把 WLAN AutoConfig 设置为手动启动或者修改它导致的干扰行为Linux 下则把 NetworkManager 的「自动连接已知网络」关掉避免脚本刚连上就又被系统切走。更深一层如果网卡频繁掉线且伴随系统事件日志里大量重置那是驱动问题。换驱动版本或者换一张 USB 网卡比在代码里做一百次重试都有效。5.3 现象有命中但实际连不上误报率很高这个坑最容易让人误判工具价值脚本返回IFACE_CONNECTED你以为密码找到了结果手机根本连不上这个 Wi-Fi密码是错的。原因在于pywifi 的IFACE_CONNECTED状态代表的是「网卡已经与 AP 完成关联」但关联成功和密钥验证通过不是同一个时刻。有些老网卡驱动会在四次握手尚未完成时就把状态置为 connected造成假阳性。解决在try_connect里连上后再做一个「能力校验」——尝试用这个连接访问网关或者再查一次iface.status()确认持续 3 秒以上都是 connected 才判定命中。我一般加一个二次确认连上后 sleep 2 秒如果状态还是 connected且能拿到网关 IPiface.status()后尝试 ping 网关才算真命中。这会把单密码耗时从 4 秒拉到 6 秒但能过滤掉大半误报。5.4 现象Windows 上速率上不去每个密码卡到超时Windows 的无线驱动对「断连后立刻重连」极其敏感。脚本里每验证一个密码就disconnectconnect驱动内部的状态机还没复位下一轮连接请求就进来了大量请求被驱动直接丢弃结果就是每次连接都等满 timeout速率断崖下跌。解决放弃每条密码都 disconnect 的做法改成「连接失败时顺手断开成功时立即断开但保持档案还在」。其实更重要的是控制节奏——每轮连接之间固定等 3 秒让驱动完成复位。Linux NetworkManager 下这个问题较轻可以放宽到 1 秒。不要让循环体看起来紧凑就拼命压缩间隔我在这上面吃过亏压到 1 秒内100 个密码跑了 20 分钟没出一个结果放开到 3 秒反而 15 分钟出了结果因为丢请求少了。5.5 现象同一接口反复增删配置文件导致驱动状态错乱在 Windows 上remove_all_network_profiles()和add_network_profile()高频轮换很容易把驱动里保存的配置列表搞坏。现象是跑着跑着网卡扫描不到任何信号了但设备管理器里一切正常。解决这也是我把remove_all_network_profiles()移出单次循环的原因。正确的姿势是程序启动时调一次清理把旧档案全部删掉然后全程不删档案只通过connect/connect来回切换。每个密码对应一个临时 Profileadd_network_profile返回的是这个 profile 在驱动里的句柄直接用句柄发起连接就行不需要每次都清空列表。如果还是出错退到最后手段——用subprocess调系统命令重启无线网卡Windows 下是netsh interface set interface WLAN disabled再enabled虽然粗暴但比在 Python 里做状态恢复要可靠得多。6. 进阶验证把它做成每周跑一次的路由器弱口令巡检6.1 验货流程先确认工具本身没毛病任何工具投入正式使用前都要先验货。我的做法是准备一台旧路由器故意把密码设成一个简单弱口令比如12345678然后把脚本的目标指向它跑一遍。如果工具能准确命中、确认连通性无误报才算通过验收。这一步比任何代码审查都有效——你亲眼看过它命中才知道批量跑出来的结果可信度有多高。也正是这一步能帮你提前还原出 5.3 里说的误报问题命中后手动用手机连一次验证结果不然后面的巡检报告全建在沙子上。6.2 巡检循环与结果落盘验货通过后可以把它改造成无人值守的巡检脚本把待验证的 SSID 列表放在一个targets.txt里每条一行跑完把结果写入带时间戳的 CSV 文件方便对比历史变化。以下是巡检循环的骨架import csv import datetime import pywifi wifi pywifi.PyWiFi() iface wifi.interfaces()[0] targets [ {ssid: Home_5G, candidates: [12345678, 88888888, admin123]}, {ssid: Office_Guest, candidates: [password, 12345678]}, ] report_file fwifi_check_{datetime.date.today().isoformat()}.csv with open(report_file, w, newline, encodingutf-8) as f: writer csv.writer(f) writer.writerow([时间, SSID, 命中密码, 耗时]) for target in targets: ssid target[ssid] for pwd in target[candidates]: t0 datetime.datetime.now() ok try_connect(iface, ssid, pwd) cost (datetime.datetime.now() - t0).total_seconds() if ok: writer.writerow([t0.isoformat(), ssid, pwd, f{cost:.1f}s]) print(f命中: {ssid} - {pwd}) # 命中之后立即跳出当前目标换下一个 break print(f巡检完成报告已写入 {report_file})巡检的要义是「建立基线」第一次跑出来的弱口令是存量风险后面每周跑一次比的是有没有新增——某个 SSID 消失了、密码变了、多了一个 nobody 开的热点。如果你能坚持把历史 CSV 留一年年底复盘时会发现它比任何网络扫描软件都更能反映公司无线网络的实际使用变化。最后说一个我自己的习惯每次拿到一个新环境的无线密码测试任务我第一件事不是写代码是把目标网络的特征记下来——路由器型号、默认密码规则、SSID 命名习惯。这些东西决定了字典怎么组织也决定了这个任务是不是值得用脚本跑。很多看起来该自动化的事情人工 5 分钟就能做完脚本反而要跑两小时。判断「值不值得跑」本身就是经验的一部分。希望这些踩坑记录能帮到你少走我走过的弯路。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑