3. 解析WPA3 Beacon帧
任务说明
本案例要求编写一个Beacon帧解析器,从802.11管理帧中提取RSN信息元素(RSNE),并识别其中是否包含WPA3所需的AKM套件(00-0F-AC:8为SAE,00-0F-AC:12为SAE-H2E)。输入为原始Beacon帧字节流,输出为解析后的AKM套件列表及WPA3能力判定。
Beacon帧结构与解析逻辑
Beacon帧属于管理帧(类型0,子类型8),帧体由固定字段和Tagged Parameters组成。解析流程为:跳过MAC头部(24字节)和固定字段(时间戳8字节+Beacon间隔2字节+能力信息2字节),从偏移36字节处开始遍历Tagged Parameters。每个Tag由Tag Number(1字节)、Length(1字节)和Value组成。当Tag Number为48(0x30)时即为RSNE,进一步解析其内部结构:版本(2字节)、组密钥套件(4字节)、成对密钥套件计数(2字节)及列表、AKM套件计数(2字节)及列表。AKM套件格式为OUI(3字节)+类型(1字节),WPA3相关类型为8(SAE)和12(SAE-H2E)。
代码实现
def parse_beacon_rsne(beacon_frame: bytes) -> dict:
"""
解析Beacon帧,提取RSNE中的AKM套件
参数:
beacon_frame: 完整Beacon帧字节流(含MAC头部)
返回:
dict: 包含akm_suites列表和wpa3_support布尔值的字典
"""
# 检查帧最小长度(MAC头24 + 固定字段12 + Tag头2)
if len(beacon_frame) < 38:
return {"error": "帧长度不足", "akm_suites": [], "wpa3_support": False}
# 跳过MAC头部(24字节)和固定字段(12字节)
offset = 36
akm_suites = []
wpa3_support = False
# 遍历Tagged Parameters
while offset + 2 <= len(beacon_frame):
tag_num = beacon_frame[offset]
tag_len = beacon_frame[offset + 1]
tag_start = offset + 2
# 检查Tag长度是否越界
if tag_start + tag_len > len(beacon_frame):
break
# 处理RSNE (Tag Number = 48)
if tag_num == 48 and tag_len >= 8:
rsn_data = beacon_frame[tag_start:tag_start + tag_len]
# RSNE结构: 版本(2) + 组密钥套件(4) + 成对密钥计数(2) + 成对密钥列表 + AKM计数(2) + AKM列表
if len(rsn_data) >= 8:
# 跳过版本(2) + 组密钥套件(4)
pos = 6
# 成对密钥套件计数
pairwise_count = int.from_bytes(rsn_data[pos:pos+2], 'little')
pos += 2
# 跳过成对密钥套件列表
pos += pairwise_count * 4
# AKM套件计数
if pos + 2 <= len(rsn_data):
akm_count = int.from_bytes(rsn_data[pos:pos+2], 'little')
pos += 2
# 解析AKM套件列表
for i in range(akm_count):
if pos + 4 <= len(rsn_data):
oui = rsn_data[pos:pos+3]
akm_type = rsn_data[pos+3]
# 标准WPA3 OUI为00-0F-AC
if oui == bytes([0x00, 0x0F, 0xAC]):
akm_suites.append(akm_type)
# AKM类型8=SAE, 12=SAE-H2E
if akm_type in (8, 12):
wpa3_support = True
pos += 4
else:
break
break # RSNE通常只有一个,解析完即可退出
# 移动到下一个Tag
offset = tag_start + tag_len
return {
"akm_suites": akm_suites,
"wpa3_support": wpa3_support
}
# 示例Beacon帧(构造包含WPA3 RSNE的最小帧)
def create_sample_beacon():
"""构造一个包含WPA3 RSNE的Beacon帧用于测试"""
# MAC头部(24字节)- 使用零填充简化
mac_header = bytes(24)
# 固定字段(12字节)
fixed_fields = bytes(12)
# RSNE Tag (Tag=48)
# 版本: 1
version = (1).to_bytes(2, 'little')
# 组密钥套件: CCMP (00-0F-AC:4)
group_cipher = bytes([0x00, 0x0F, 0xAC, 0x04])
# 成对密钥套件计数: 1, 套件: CCMP
pairwise_count = (1).to_bytes(2, 'little')
pairwise_cipher = bytes([0x00, 0x0F, 0xAC, 0x04])
# AKM计数: 1, 套件: SAE (00-0F-AC:8)
akm_count = (1).to_bytes(2, 'little')
akm_sae = bytes([0x00, 0x0F, 0xAC, 0x08])
rsn_body = version + group_cipher + pairwise_count + pairwise_cipher + akm_count + akm_sae
rsn_tag = bytes([48, len(rsn_body)]) + rsn_body
# 添加一个SSID Tag使帧更完整(可选)
ssid = b"WPA3_Test"
ssid_tag = bytes([0, len(ssid)]) + ssid
return mac_header + fixed_fields + rsn_tag + ssid_tag
# 执行解析
if __name__ == "__main__":
beacon = create_sample_beacon()
result = parse_beacon_rsne(beacon)
print("AKM套件类型:", result["akm_suites"])
print("WPA3支持:", result["wpa3_support"])
# 预期输出(由代码逻辑直接推出):
# AKM套件类型: [8]
# WPA3支持: True
验证方法
运行上述代码,观察输出结果。若输出AKM套件类型: [8]且WPA3支持: True,说明解析器正确识别了RSNE中的SAE AKM套件。如需验证其他AKM类型,可修改create_sample_beacon函数中akm_sae的最后一个字节为12(SAE-H2E)或1(802.1X)进行测试。判定标准为:解析出的AKM套件类型与构造输入完全一致,且当包含类型8或12时wpa3_support为True。