Beacon帧解析:从空中嗅探到网络身份
Beacon帧,说白了就是Wi-Fi网络的「广播名片」。AP每隔100ms左右就会在空中喊一嗓子:「我在这里,我叫这个名,我支持这些速率,加密方式是这样的...」
我刚开始做Wi-Fi抓包时,觉得Beacon帧无非就是看看SSID。后来有一次客户投诉说办公区有干扰源,我抓了上千个Beacon帧,才发现厂商信息、信道宽度、HT Capabilities这些字段才是定位问题的关键。嗯,从那以后我再也不敢小看这个「广播包」了。
核心认知:Beacon帧是802.11管理帧的一种,Type=00,Subtype=1000。它不携带用户数据,但携带了网络的全部「元信息」。
Beacon帧结构:逐层拆解
一个完整的Beacon帧,从物理层到MAC层,再到帧体,层层嵌套。我习惯把它分成三块来看:
- MAC头部(24字节):Frame Control、Duration、DA(目的地址,通常是广播FF:FF:FF:FF:FF:FF)、SA(源地址,即AP的MAC)、BSSID(基本服务集标识,通常等于AP的MAC)、Sequence Control。
- 帧体(可变长度):Timestamp、Beacon Interval、Capability Information,后面跟着一串Tagged Parameters(也叫IE,信息元素)。
- FCS(4字节):帧校验序列,用于检测传输错误。
你想想看,一个Beacon帧最少也就50字节左右,但里面塞了十几甚至二十几个IE。每个IE都有Type、Length、Value三段结构,这就是TLV格式。
| 字段 | 长度(字节) | 说明 |
|---|---|---|
| Timestamp | 8 | AP的64位时间戳,用于同步 |
| Beacon Interval | 2 | 发送间隔,单位TU(1TU=1024μs),默认100 |
| Capability Information | 2 | 能力位图:ESS、IBSS、Privacy、Short Preamble等 |
| SSID (IE 0) | 2+可变 | Type=0,Length=SSID长度,Value=SSID字符串 |
| Supported Rates (IE 1) | 2+可变 | 支持的速率集,每个速率用7位编码 |
| DS Parameter Set (IE 3) | 3 | 当前信道编号 |
| Vendor Specific (IE 221) | 3+可变 | 厂商自定义信息,OUI+数据 |
抓包小技巧:在Wireshark中,直接展开"Tagged Parameters"就能看到所有IE。我习惯用过滤表达式 wlan.fc.type_subtype == 8 只显示Beacon帧,然后按BSSID分组统计,一眼就能看出环境中有多少AP。
SSID与BSSID提取:从字节到字符串
SSID就是Wi-Fi的名字,BSSID是AP的MAC地址。提取它们,说白了就是解析IE的过程。
SSID提取:
- 找到Tag Number = 0的IE。
- 读取Length字段,得到SSID的字节长度(0~32)。
- 读取Value字段,就是SSID的ASCII字符串。
- 如果Length=0,说明是隐藏SSID(后面会讲)。
BSSID提取:
- 直接取MAC头部的Address 3字段(因为Beacon帧中,Address 3就是BSSID)。
- 注意:有些AP会使用不同的BSSID和SA(源MAC),但绝大多数情况下BSSID = SA。
// 伪代码示例:从Beacon帧中提取SSID和BSSID
function parseBeacon(packet):
// 提取BSSID (Address 3, 偏移24字节处)
bssid = packet[24:30].toMacString()
// 遍历Tagged Parameters
offset = 36 // MAC头(24) + 固定字段(12) = 36
while offset < packet.length - 4: // 减去FCS
tagType = packet[offset]
tagLen = packet[offset + 1]
if tagType == 0: // SSID
ssid = packet[offset+2 : offset+2+tagLen].toString()
if tagLen == 0:
ssid = "[Hidden SSID]"
break
offset += 2 + tagLen
return {bssid, ssid}
注意:SSID长度最大32字节,但有些厂商会发送超过32字节的SSID(非标行为)。我在一次兼容性测试中遇到过,某品牌AP发送了33字节的SSID,导致部分老旧网卡直接不显示这个网络。抓包一看,IE的Length字段写的是33,但标准规定最大32。这种「野路子」AP,遇到了就得留个心眼。
隐藏SSID探测:它真的「隐藏」了吗?
很多人觉得隐藏SSID就是「我把SSID广播关掉,别人就找不到我了」。其实这是个误解。隐藏SSID的AP仍然在发送Beacon帧,只是把SSID IE的Length设为0,或者填充一个空字符串。
我做过一个实验:在办公室把AP设为隐藏SSID,然后用抓包工具监听。结果呢?Beacon帧照样每秒10个左右在发,只是SSID字段是空的。但注意——
- Probe Response帧会泄露SSID:当客户端主动发送Probe Request(探测请求)时,AP会回复Probe Response,里面就包含了完整的SSID。
- 某些AP在Beacon帧的其他IE中也会泄露SSID:比如Vendor Specific IE、或者某些厂商自定义的IE里,可能藏着SSID字符串。
为什么会这样?因为AP需要让已经连接过的客户端知道「我还在」,所以它必须保留SSID信息,只是不在标准位置暴露而已。
| 隐藏方式 | Beacon帧SSID IE | Probe Response | 能否被扫描到 |
|---|---|---|---|
| 标准隐藏 | Length=0 | 包含完整SSID | 能(但SSID为空) |
| 非标隐藏 | 填充空字符或随机数据 | 包含完整SSID | 能(但SSID乱码) |
| 完全静默 | 不发送Beacon | 不响应Probe Request | 不能(但客户端也无法连接) |
探测隐藏SSID的方法:在Wireshark中,用过滤表达式 wlan.tag.number == 0 && wlan.tag.length == 0 找到隐藏SSID的Beacon帧。然后监听后续的Probe Response,或者用主动扫描工具发送针对该BSSID的Probe Request,AP就会乖乖吐出SSID。
厂商信息识别:从OUI到设备指纹
每个网卡厂商都有自己分配的OUI(Organizationally Unique Identifier),即MAC地址的前3个字节。比如00:1A:2B是Cisco,00:0C:43是TP-Link。但Beacon帧里的厂商信息远不止OUI这么简单。
我习惯从三个维度识别厂商:
- BSSID的OUI:最直接,查OUI数据库就能知道AP的制造商。
- Vendor Specific IE (IE 221):很多厂商会在Beacon帧里塞自己的私有IE,比如Cisco的CCX、Aruba的VSIE、小米的MiWiFi等。这些IE的Type=221,前3个字节是厂商的OUI,后面是自定义数据。
- HT/VHT Capabilities中的厂商特征:比如某些厂商对MCS(调制编码方案)的支持范围、对信道带宽的偏好,都有细微差异。
// 解析Vendor Specific IE的示例
function parseVendorIE(packet, offset):
tagType = packet[offset] // 应为221 (0xDD)
tagLen = packet[offset + 1]
oui = packet[offset+2 : offset+5].toHexString()
vendorData = packet[offset+5 : offset+2+tagLen]
switch(oui):
case "00:00:0C": // Cisco
// 解析Cisco私有IE
break
case "00:0C:43": // TP-Link
// 解析TP-Link私有IE
break
case "00:1A:2B": // 其他厂商
break
return {oui, vendorData}
实战经验:有一次客户说网络中有「不明AP」干扰,我抓了Beacon帧一看,BSSID的OUI显示是某知名品牌,但Vendor Specific IE里却出现了另一个厂商的OUI。后来确认是有人刷了第三方固件(比如OpenWrt),导致MAC地址没改,但私有IE暴露了真实身份。嗯,这种「伪装AP」在抓包分析中并不少见。
Beacon帧分析知识体系
下面这张图是我自己梳理的Beacon帧分析框架,从帧结构到实际应用,一条线串下来:
这张图把Beacon帧从物理结构到分析目标再到实际应用串了起来。我个人习惯在抓包前先画这么一张图,脑子里有了框架,抓包时就不会迷失在几百个字段里。
实战:用Wireshark快速提取关键信息
说了这么多理论,来点实操。打开Wireshark,抓一个Beacon帧,你会看到类似这样的结构:
Frame 1: 242 bytes on wire (1936 bits)
Radiotap Header v0.0
802.11 Beacon frame, Flags: ....
Type/Subtype: Beacon (8)
Frame Control: 0x8008
.000 0000 0000 0000 = Duration: 0
DA: Broadcast (ff:ff:ff:ff:ff:ff)
SA: 00:1a:2b:3c:4d:5e
BSSID: 00:1a:2b:3c:4d:5e
...
Tagged Parameters (174 bytes)
Tag: SSID (0)
Tag Number: 0
Tag Length: 8
SSID: MyWiFi
Tag: Supported Rates (1)
Tag Number: 1
Tag Length: 8
Supported Rates: 1(B), 2(B), 5.5(B), 11(B), 6, 9, 12, 18
Tag: Vendor Specific (221)
Tag Number: 221
Tag Length: 7
OUI: 00-00-0C (Cisco)
Vendor Specific Data: ...
快速过滤技巧:
- 只看Beacon帧:
wlan.fc.type_subtype == 8 - 只看某个BSSID:
wlan.bssid == 00:1a:2b:3c:4d:5e - 只看隐藏SSID:
wlan.tag.number == 0 && wlan.tag.length == 0 - 只看某厂商:
wlan.tag.oui == 00:00:0c
嗯,Beacon帧解析这块,说白了就是「读TLV」。你只要掌握了TLV的套路,再复杂的IE也能拆开。下次抓包时,别只看SSID,多看看Vendor IE、HT Capabilities、甚至DS Parameter Set里的信道号,这些信息往往能帮你快速定位问题。