3. 解析WPA3 Beacon帧

解析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。

Beacon帧RSNE解析结构 Beacon帧结构: MAC Header 24 bytes Fixed 12 bytes Tagged Parameters 可变长度 偏移: 0 24 36 Tag=48 (RSNE) RSNE内部结构: 版本 2B 组密钥套件 4B 成对计数 2B 成对列表 N×4B AKM计数 2B AKM套件列表 M×4B AKM套件格式 (4字节): OUI 3B (00-0F-AC) 类型 1B WPA3相关AKM类型: 类型 8 = SAE (WPA3-Personal) 类型 12 = SAE-H2E (WPA3增强) 解析流程: 遍历Tag → 找到Tag=48 → 读取AKM计数 → 逐个检查OUI和类型