IEEE 802.11是現今無線局域網通用的標准,而當今我們熟悉的Wi-Fi,正是基於IEEE 802.11系列標准的產品。通過Wi-Fi,我們可以盡情享受無線上網的樂趣,而不必拖着長長的網線。那么,它是如何工作的呢?帶着這樣的疑問,我查找了相關資料,並通過抓包的方式進行驗證。由於沒有通信相關的專業背景,因此學習的主要是數據鏈路層的部分。
定義
Access Point(AP)
接入點,多指無線訪問接入點,即通常所說的路由器。
Station(STA)
站點,泛指無線接入設備,如筆記本電腦、平板電腦、手機等。
Basic Service Set(BSS)
所有無線設備(STA)關聯到一個訪問點(AP)上,它們構成一個基礎服務集合。在集合中,訪問點控制和主導整個BSS中的全部數據的傳輸過程。
Extended Service Set(ESS)
多個BSS通過各種手段互聯形成的擴展網絡,無線設備關聯到一個或多個訪問點上,它們構成一個擴展服務集合。在同一個ESS中的不同BSS之間切換的過程稱為漫游。
Service Set Identification(SSID)
BSS和ESS使用的標識符,路由器等AP一般都允許用戶自由設置。
802.11 Frame
802.11標准將所有的幀(Frame,數據鏈路層的基本傳輸單元)分為3種:
-
Management Frame
管理幀(wlan.fc.type == 0x00)
用於STA與AP之間協商、關系的控制。
-
Beacon Frame
信標幀(wlan.fc.type_subtype == 0x08)
一個提供服務的AP會定時發送Beacon Frame以告知BSS的存在,並提供了BSS的一些基本信息,如BSSID、SSID、Channel等。
-
Probe Request / Probe Response
探測請求(wlan.fc.type_subtype == 0x04)和探測響應(wlan.fc.type_subtype == 0x05)
Probe request由STA發出,用於探測周圍的BSS。如果指定了SSID,則只有SSID與之一致的BSS(准確來說是BSS內的AP)會通過Probe Response進行響應;如果未指定,則所有BSS都會進行響應。和Beacon Frame一樣,Probe Response提供了BSS的基本信息。
-
Authentication
認證(wlan.fc.type_subtype == 0x0B)
Authentication中,包含認證類型(Authentication Algorithm),認證進度(Authentication SEQ),認證狀態(Status Code)。AP可以根據相關信息決定接受還是拒絕某個STA的加入,並同樣通過Authentication進行回復。
-
Deauthentication
解除認證(wlan.fc.type_subtype == 0x0C)
用來終結認證關系。
-
Association Request / Association Response
關聯請求(wlan.fc.type_subtype == 0x00) / 關聯響應(wlan.fc.type_subtype == 0x01)
一旦STA找到網絡並通過認證,就會發送Association Request,請求 AP 進行關聯。AP以Association Response進行回應。如果AP接受該請求,將為該STA分配資源。
-
Reassociation Request / Reassociation Response
重關聯請求(wlan.fc.type_subtype == 0x02) / 重關聯響應(wlan.fc.type_subtype == 0x03)
當STA遠離原AP,並發現相同的ESS里有另一個信號更強的AP時,STA將發送Reassociation Request。AP以Reassociation Response進行回應。一旦AP接受該請求,將為該STA分配資源,由此AP提供服務。
-
Disassociation
解除關聯(wlan.fc.type_subtype == 0x0A)
用來終結關聯關系。收到Disassociation后,AP將釋放先前為該STA分配的資源。
-
-
Control Frame
控制幀(wlan.fc.type == 0x01)
用於競爭期間的握手通信和正向確認等,為數據幀的發送提供輔助功能。
-
Power Save - Poll
省電-輪詢(wlan.fc.type_subtype == 0x0A)。休眠的AP定期發送。
-
Request To Send
請求發送(wlan.fc.type_subtype == 0x0B)
表明A要向B發送若干數據,申請預約。目的是為了避免同時有多人向B發送幀,導致沖突。
-
Clear To Send
清除發送(wlan.fc.type_subtype == 0x0C)
收到Request To Send后,如果B同意該預約,則通過Clear To Send宣告其他人在一定時間內暫停向自己發送數據,避免沖突。
-
ACK
確認收到的數據幀(wlan.fc.type_subtype == 0x0D)
如果收到的數據幀校驗出錯,則不發送ACK,等待重傳。
-
CF-End
無競爭周期結束(wlan.fc.type_subtype == 0x0E)
讓STA脫離PCF模式,開始以DCF(基於競爭)模式。
-
CF-End + CF-ACK
無競爭周期結束+確認(wlan.fc.type_subtype == 0x0F)
-
-
Data Frame
數據幀(wlan.fc.type == 0x02)
用於在競爭期(Contention Period)和非競爭期(Contention-free Period)傳輸數據。
-
Data
基本數據幀(wlan.fc.type_subtype == 0x00)
包含了通信的實際數據。
-
Null
沒有數據的空幀(wlan.fc.type_subtype == 0x04)
但可以有其它的標記信息。
-
CF-ACK
無競爭周期的確認(wlan.fc.type_subtype == 0x05)
用於確認之前所收到的幀。
-
CF-Poll
無競爭周期的輪詢(wlan.fc.type_subtype == 0x06)
用於通知已經沒有數據要傳輸。
-
Qos Data
Data幀的 Qos 版本(wlan.fc.type_subtype == 0x08)
-
Qos Null
Null幀的 Qos 版本(wlan.fc.type_subtype == 0x0C)
此外還有各種幀的組合,如Data + CF-ACK,Data + CF-Poll、Qos Data + CF-ACK等,不再細述。
-
工作流程
為了真正了解802.11協議的工作流程,這里對一個STA加入到一個BSS的過程進行裝包分析。打開Wireshark后,進入Capture-Input,選擇要監聽的WIFI網卡,將Link-Layer Header改為Per-Packet Information,將Monitor Mode改為enabled(雙擊修改)后開始監聽。
-
STA通過偵聽AP定期發送的Beacon Frame來發現BSS。
如圖,可以發現空間中充斥着各個AP發送的Beacon Frame:
在這種方式下,STA幾乎無需付出掃描代價,因此稱為被動掃描。還有一種稱為主動掃描的BSS發現方法,STA通過在信道上發出Probe Request幀,通過AP發回的Probe Response來發現BSS。如圖,設備HTC在廣播Probe Request后,收到了SSID為STAR的AP發來的Probe Response:
從圖上可以發現在STA在發現STAR后雙方又進行了多輪Probe。
-
當STA獲取到該BSS的相關信息並確定想加入該BSS時,向相應AP發送Authentication Request
如圖,雙方通過發送Authentication幀進行認證:
我們發現這里的認證協議是Open System,即AP只對接入設備的MAC地址進行驗證,只要MAC地址不被BAN,STA就可以通過認證。這樣豈不是很不安全?非也非也,請接着往下看。
-
認證通過后,STA向該AP發送Association Request,AP收到后回復Association Response
-
至此,STA接入完畢,可以開始向AP傳送數據幀
-
注意:在上圖中,AP對STA發起了EAPOL認證
這是因為AP選擇了WPA2(RSN)-PSK的認證方式。在這種認證方式下,AP和STA把預共享密鑰(PSK)當作成對主密鑰(PMK),並通過EAPOL協議進行四次握手,生成了成對臨時密鑰(PTK),用於加密后續通訊內容。
After EAPOL 1 and 2 both sides know the temporal key that will be used to decrypt the traffic.
The third message is proof that both sides know the temporal key and indicates that the Authenticator (the base station) is ready to start using the temporal key.
The fourth message triggers the switch from the PMK set up before the EAPOL to the temporal key derived in the EAPOL
-
雙方通過Qos data幀交換數據
此時幀中的數據已被PTK加密:
應用
在學習了相關概念和流程后,可以折騰一些有趣的東西。
應用一 利用Wireshark進行無線網絡抓包
Wireshark可以通過PSK算出PTK來解密數據。在Preferences-Protocols-IEEE 802.11中勾選Enable decryption:
點擊Decryption Keys旁邊的Edit按鈕,新增類型的wpa-pwd的記錄,Key為接入AP的PSK:SSID:
保存后發現先前被加密的數據被解密了!從鏈路層到應用層的報文一覽無余:
這意味着我們可以方便地進行跨設備網絡嗅探。曾經抓移動設備的包是一件十分蛋疼的事情,為此我嘗試了各種姿勢:
-
在移動設備上直接抓包
抓出來的包在移動設備上無論是查看還是操作都十分不方便,往往需要導出到電腦上來分析。
-
電腦做AP供移動設備連接,然后在電腦上抓包
由於RMBP只有無線網卡,一旦做了AP就連不了網,無法滿足99%的應用場景。
-
路由器上抓包
最終我搞了一台極路由,刷了OpenWRT,然后直接在上面tcpdump,當然dump出來的文件依然要拷到電腦上分析才方便。這個方法唯一的不足是能夠讓你愉快地進行tcpdump的路由畢竟極少,日常生活中99%的路由都是只能192.168.1.1的弱雞路由,比如上文所用的TPLink。
通過網絡嗅探的方式,我們能夠得到移動設備傳輸的包,再通過PTK解密得到包內容,不失為一種另類的抓包方法。
應用二 WIFI探針
通常來說,移動設備會經常發送Probe request來發現周圍的BSS,而在Probe request中有設備的MAC地址。只要我們監控周圍的Probe request幀,就可以知道是否有某個設備進入了BSS的范圍。於是,我搞到了BOSS手機的MAC地址,寫了一段代碼,BOSS一旦進入到WIFI覆蓋范圍就彈出提示。
由於RMBP只有一張無線網卡,在進入monitor mode后會導致無法上網,為了避免該影響,考慮插入多一張網卡。一番尋找后,掏出了吃灰多年的360wifi2代(9塊9包郵哦親)。由於懶得折騰Mac上的驅動,因此轉移到自帶驅動的Ubuntu 16.04的虛擬機上進行。在插入網卡后,設備已經被識別:
$ lsusb
...
Bus 001 Device 004: ID 148f:760b Ralink Technology, Corp. MT7601U Wireless Adapter
$ ifconfig
...
wlx24050f2db588 Link encap:Ethernet HWaddr 24:05:0f:2d:b5:88
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
進入monitor mode,設置監聽信道:
$ sudo ip link set wlx24050f2db588 down
$ sudo iw dev wlx24050f2db588 set type monitor
$ sudo ip link set wlx24050f2db588 up
$ sudo iw dev wlx24050f2db588 set channel 1
此時看iwconfig,會發現wlx24050f2db588網卡的Mode為Monitor,Frequency為2.412 GHz。
以下是監聽代碼,依賴於scapy 2.3.2和manuf(https://github.com/coolbho3k/manuf.py):
from __future__ import print_function
from scapy.all import *
import manuf
def monitorDevice(pkt):
addr, target = None, None
if pkt.haslayer(Dot11ProbeReq):
addr = pkt.getlayer(Dot11).addr2
target = pkt.getlayer(Dot11ProbeReq).info or ''
if pkt.haslayer(Dot11ProbeResp):
addr = pkt.getlayer(Dot11).addr1
target = pkt.getlayer(Dot11ProbeResp).info or ''
if addr:
manuf = parser.get_manuf(addr) or 'Unknown'
print('Detected Devices: MAC[%s] Manuf[%s] Target[%s]' % (addr, manuf, target))
if MAC_DICT.get(addr) == 'BOSS':
print('[*] Warning!!! BOSS is coming!!!')
MAC_DICT = {'50:2e:5c:e5:e6:14': 'BOSS'}
interface = 'wlx24050f2db588'
parser = manuf.MacParser()
sniff(iface=interface, prn=monitorDevice)
這份代碼除了監聽Probe Request,還監聽了Probe Response。當監聽到BOSS手機的MAC,輸出提示。於是我跑着這份代碼,開始了愉悅的摸魚生活~
第一天,我利用WIFI探針,成功躲過BOSS的襲擊。
第二天,我被BOSS干死了,因為今天BOSS的手機沒開WIFI。
第三天,我又被BOSS干死了,因為今天BOSS出門沒帶手機。
第四天,我又被BOSS干死了,因為今天BOSS竟然換IPhone了。
......
總結
我們必須承認,Wi-Fi的普及是人類史上的一次飛躍。擁有Wi-Fi,我們不再需要拖着長長的網線,不必擔心路由器上的LAN口不夠用,為移動設備的發展提供了良好條件。但同時也必須指出,我們在獲取Wi-Fi便利的同時,也付出了相應的代價:當你在大街上行走時,路邊不起眼的垃圾桶正監聽移動設備發出Probe Request幀,為“大數據”增磚添瓦;當你進入餐館,詢問店家密碼后愉快地連上WIFI刷朋友圈刷微博時,你的隱私可能正在店家甚至是其他人收集;當你在家里偷偷摸摸地下載小黃油時,隔壁老王發出嘆息:“這部早看過了”。只有不斷提高自己的姿勢水平,才能保證自己的菊部安全。總之,出門在外,還是走Proxy全局加密吧~