文章目錄
- 1 原理分析
- 1.1 WPS連接過程
- 1.1.1 初始階段
- 1.1.2 注冊階段
- 1.2 WPS攻擊原理
- 1.2.1 在線攻擊
- 1.2.2 離線攻擊
- 1.2.2.1 Ralink模式
- 1.2.2.2 eCos模式
- 2 實驗過程
- 3 參考資料
在2011年 Stefan Viehb?ck 演示過WPS的在線暴力攻擊,由于PIN碼猜測最多只需11000種組合,平均6小時就能攻破一臺路由器。而在2014年 Dominique Bongard 又演示了一種離線暴力坡解的攻擊,這種可怕的攻擊可在不到一秒時間內破譯WPA密鑰,Bongard先生還在其幻燈片結尾發出警告:“立即禁用WPS!”
【教程合集】
【無線抓包實驗1】抓包獲取隱藏WiFi名稱
【無線抓包實驗2】5G WiFi抓包跑包全流程
【無線抓包實驗3】批量抓包與無客戶端抓包
【無線安全實驗4】WPS離線破譯原理與實驗
1 原理分析
WPS(Wi-Fi Protected Setup)是一項旨在簡化無線網絡安全配置的標準,它通過PIN碼(Personal Identification Number)或PBC(Push Button Configuration)等方式,使家庭用戶能夠輕松地將新設備安全地接入Wi-Fi網絡。在PIN碼模式下,WPS使用EAP-WSC(Extensible Authentication Protocol for Wi-Fi Simple Configuration)協議完成認證與密鑰交換過程,該過程包含八個階段(M1-M8)的消息交換。本文將深入探討這八個階段的詳細流程,并重點分析其中涉及的關鍵參數(如E-Hash1、E-Hash2、PKE、PKR、AuthKey、E-Nonce等)的作用與相互計算關系。通過對這些參數和流程的理解,我們能夠更深入地認識WPS的安全機制及其潛在脆弱性。
1.1 WPS連接過程
在WPS中有兩個角色概念Enrollee和Registrar,Enrollee是入網設備(即手機物聯網家居等各種終端),Registrar為認證服務器,一般也由AP(即路由器等設備)充當。
1.1.1 初始階段
【發現過程】
AP端的WSC開始工作后,它會廣播帶有WSC IE字段的beacon包,以聲明AP支持WSC
如果Enrollee收到來自AP的端的beacon包,那么它會解析beacon包中的 WSC IE,并向AP發送單播Probe Request包;如果Enrollee沒有收到帶有WSC IE的beacon包,那么它就會去搜索周圍支持WSC的AP,所以會向周圍發送Probe Request廣播包。
如果Enrollee發現周圍有兩個或者兩個以上的AP在跑WPS,則Enrollee會在發現階段停止繼續執行;同理,如果AP發現有兩個或兩個以上的Enrollee在嘗試建立WPS連接,AP也會停止運行WPS。如果哪一天按下你router的WPS按鈕,發現wps燈快閃了幾下就不閃了,可能就是當時同時有兩個Enrollee在嘗試WPS連接。
AP收到帶有 WSC IE的Probe Request請求包以后,就會回復Probe Response包,這個包里面帶有WSC IE,會告訴Enrollee一些信息,這些信息很多,Enrollee會根據這些信息來決定下一步的動作
【關聯過程】
- 對于PIN WPS需要在這個步驟輸入PIN,對于PUSH BUTTON則不需要輸入,當然PIN有分AP PIN和client PIN,這個決定了需要在AP端還是在Enrollee端輸入PIN, 這種輸入都是in-band的方式,當然也可以使用out-band的方式輸入信息,如NFC
- 當Enrollee獲取到AP端的信息,并且通過判斷符合接入條件的時候,Enrollee會嘗試去和AP進行認證,向AP發送Auth包
- AP端回復Auth 成功包,認證成功
- 然后Enrollee發送Association Request 關聯請求包,并附帶WSC IE 信息,這個信息很重要,目的是告訴AP我這邊使用的協議(如802.1x WPS 1.0 協議),我們接下來的M1-M8過程也將會遵守這個協議進行交互,如果不能接受這種協議的話,請及時告訴我。
- 這時,AP端表示這種協議是支持的,發送一個Association Response包給Enrollee,完成關聯。
【準備過程】
- 發送EAPOL-Start
- 在STA和AP雙方開展EAP-WSC流程前,AP需要確定STA的Identity以及使用的身份驗證算法。該過程涉及三次EAP包交換。這三次包交換的內容,首先,AP發送EAP-Request/Identity以確定STA的ID
- 對于打算使用WSC認證方法的STA來說,它需要在回復的EAP-Response/Identity包中設置Identity為"WFA-SimpleConfig-Enrollee-1-0"。
- AP確定STA的Identity為"WFA-SimpleConfig-Enrollee-1-0"后,將發送EAP-Request/WSC_Start包以啟動EAP-WSC認證流程。而后進入WPS認證與配置的M1~M8階段。
1.1.2 注冊階段
WPS使用EAP-WSC(EAP for Wi-Fi Simple Configuration)協議來完成配置過程,這部分是WPS的核心部分。該協議基于EAP(Extensible Authentication Protocol)框架,但專門用于WPS的設備注冊流程。整個認證過程包含8個消息交換階段(M1至M8),這些消息通過EAPoL-Data幀在Enrollee(設備)和Registrar(AP)之間傳輸,安全地交換配置信息(如 SSID、網絡密鑰等)。
消息 | 方向 | 說明 | 主要作用與內容 |
---|---|---|---|
M1 | 設備 → AP | 發起注冊 | Enrollee 發送能力信息和公鑰PKE 和隨機數N1 ,啟動注冊流程。 |
M2 | AP → 設備 | 派生密鑰 | Registrar 發送能力信息和公鑰PKR 和隨機數N1 ,并開始密鑰派生。 |
M3 | 設備 → AP | 生成證明 | Enrollee 發送設備PIN碼的哈希證明E-Hash1 和E-Hash2 。 |
M4 | AP → 設備 | 生成證明 | Registrar 回應設備PIN碼的哈希證明R-Hash1 和R-Hash2 ,并提交第一個秘密隨機數R-S1 。 |
M5 | 設備 → AP | 驗證證明 | Enrollee 提交第一個秘密隨機數 E-S1 。 |
M6 | AP → 設備 | 驗證證明 | Registrar 提交第二個秘密隨機數 R-S2 。 |
M7 | 設備 → AP | 驗證證明 | Enrollee 提交第二個秘密隨機數 E-S2 。 |
M8 | AP → 設備 | 配置網絡 | Registrar 發送最終的加密配置信息(如 SSID、網絡密鑰等)。 |
【建立加密】
-
【M1】:初始化注冊請求,提供Enrollee設備信息和安全能力。Enrollee選擇隨機數
A
為私鑰,計算公鑰PKE = g^A mod p
(使用指定的 1536-bit MODP 群)。發送UUID-E, MAC-E, PKE, N1(Enrollee隨機數), Device Password ID, 能力屬性等。
-
【M2】:響應注冊請求,提供Registrar信息并啟動密鑰交換。Registrar選擇隨機數
B
為私鑰,計算公鑰PKR = g^B mod p
。發送UUID-R, PKR, N2(Registrar隨機數), N1(回顯), Auth_M2, 能力屬性等。
根據交互的公鑰與隨機數,雙方相互獨立計算出共享密鑰DHShared和密鑰派生密鑰KDK:
DHShared=PKEBmodp=PKRAmodp=g(A?B)modpDHKey=SHA-256(zeropad(DHShared,192))KDK=HMAC?SHA256(DHKey,N1∣∣MAC?E∣∣N2)DHShared = PKE^B \mod p = PKR^A \mod p = g^{(A \cdot B)} \mod p\\ DHKey = \text{SHA-256}(\text{zeropad}(DHShared, 192))\\ KDK = HMAC-SHA256(DHKey, N1 || MAC-E || N2) DHShared=PKEBmodp=PKRAmodp=g(A?B)modpDHKey=SHA-256(zeropad(DHShared,192))KDK=HMAC?SHA256(DHKey,N1∣∣MAC?E∣∣N2)
最終派生出兩個關鍵的會話密鑰AuthKey和KeyWrapKey:
AuthKey∣∣KeyWrapKey∣∣EMSK=kdf(KDK,"Wi?FiEasyandSecureKeyDerivation",640)AuthKey || KeyWrapKey || EMSK = kdf(KDK, "Wi-Fi Easy and Secure Key Derivation", 640) AuthKey∣∣KeyWrapKey∣∣EMSK=kdf(KDK,"Wi?FiEasyandSecureKeyDerivation",640)
PS:
kdf
是使用 HMAC-SHA256 的迭代函數,輸出 640 位,分割為:
AuthKey
(256 bits): 用于消息認證 (HMAC)。KeyWrapKey
(128 bits): 用于加密敏感數據 (AES)。EMSK
(256 bits): 擴展主會話密鑰,可用于派生其他應用密鑰。M2中的
Auth_M2 = HMAC-SHA256(AuthKey, M2_Data)
。M2_Data
是 M2 消息中在 Authenticator 屬性之前的所有屬性。后續M3-M8的Auth_MX計算同理。
至此,雙方通過Diffie-Hellman密鑰交換算法已共享 KDK
, AuthKey
, KeyWrapKey
,為后續加密和認證打下基礎。
【驗證PIN碼】
-
【M3】:Enrollee其證明持有PIN碼。Enrollee將PIN碼分割為兩部分(如8位PIN碼12345670左右均分為1234和5670),再派生出
PSK1
和PSK2
:
PSK1=First?128?bits?of(HMAC?SHA256(AuthKey,First?Half?Password))PSK2=First?128?bits?of(HMAC?SHA256(AuthKey,Second?Half?Password))PSK1 = First-128-bits-of( HMAC-SHA256(AuthKey, First-Half-Password) )\\ PSK2 = First-128-bits-of( HMAC-SHA256(AuthKey, Second-Half-Password) ) PSK1=First?128?bits?of(HMAC?SHA256(AuthKey,First?Half?Password))PSK2=First?128?bits?of(HMAC?SHA256(AuthKey,Second?Half?Password))
然后生成秘密隨機數E-S1
,E-S2
(各 128 bits),計算證明哈希E-Hash1
和E-Hash2
:
E?Hash1=HMAC?SHA256(AuthKey,E?S1∣∣PSK1∣∣PKE∣∣PKR)E?Hash2=HMAC?SHA256(AuthKey,E?S1∣∣PSK2∣∣PKE∣∣PKR)E-Hash1 = HMAC-SHA256(AuthKey, E-S1 || PSK1 || PKE || PKR)\\ E-Hash2 = HMAC-SHA256(AuthKey, E-S1 || PSK2 || PKE || PKR) E?Hash1=HMAC?SHA256(AuthKey,E?S1∣∣PSK1∣∣PKE∣∣PKR)E?Hash2=HMAC?SHA256(AuthKey,E?S1∣∣PSK2∣∣PKE∣∣PKR)
發送 N2(回顯), E-Hash1, E-Hash2, Auth_M3。 -
【M4】:Registrar其證明持有PIN碼,提供秘密隨機數讓Enrollee驗證PIN碼第一部分。Registrar按同樣方法分割PIN碼并派生PSK1和PSK2,再生成秘密隨機數
R-S1
,R-S2
,計算證明哈希R-Hash1
和R-Hash2
:
R?Hash1=HMAC?SHA256(AuthKey,R?S1∣∣PSK1∣∣PKE∣∣PKR)R?Hash2=HMAC?SHA256(AuthKey,R?S1∣∣PSK2∣∣PKE∣∣PKR)R-Hash1 = HMAC-SHA256(AuthKey, R-S1 || PSK1 || PKE || PKR)\\ R-Hash2 = HMAC-SHA256(AuthKey, R-S1 || PSK2 || PKE || PKR) R?Hash1=HMAC?SHA256(AuthKey,R?S1∣∣PSK1∣∣PKE∣∣PKR)R?Hash2=HMAC?SHA256(AuthKey,R?S1∣∣PSK2∣∣PKE∣∣PKR)
而后生成隨機數IV(128bit),結合KeyWrapKey將第一個秘密隨機數R-S1
加密到EncryptedSettings
,并使用AuthKey生成KWA以保護R-S1的完整性:
KWA=First?64?bits?of(HMAC?SHA256(AuthKey,R?S1))DataToEncrypt=R?S1∣∣KWAEncryptedSettings=AES?Encrypt?CBC(KeyWrapKey,IV,DataToEncrypt)KWA = First-64-bits-of( HMAC-SHA256(AuthKey, R-S1) )\\ DataToEncrypt = R-S1 || KWA\\ EncryptedSettings = AES-Encrypt-CBC(KeyWrapKey, IV, DataToEncrypt) KWA=First?64?bits?of(HMAC?SHA256(AuthKey,R?S1))DataToEncrypt=R?S1∣∣KWAEncryptedSettings=AES?Encrypt?CBC(KeyWrapKey,IV,DataToEncrypt)
發送 N1(回顯), R-Hash1, R-Hash2, EncryptedSettings (R-S1), IV, Auth_M4。 -
【M5】:Enrollee提供秘密隨機數讓Registrar驗證PIN碼第一部分。Enrollee解密R-S1并驗證其完整性:
Data∣∣KWA′=AES?Decrypt?CBC(KeyWrapKey,IV,EncryptedSettings)KWA′==First?64?bits?of(HMAC?SHA256(AuthKey,R?S1))Data || KWA' = AES-Decrypt-CBC(KeyWrapKey, IV, EncryptedSettings)\\ KWA' == First-64-bits-of( HMAC-SHA256(AuthKey, R-S1) ) Data∣∣KWA′=AES?Decrypt?CBC(KeyWrapKey,IV,EncryptedSettings)KWA′==First?64?bits?of(HMAC?SHA256(AuthKey,R?S1))
使用解密得到的R-S1
和自己已知的PSK1
,PKE
,PKR
重新計算R-Hash1
,與 M4 中的值比較。若計算不一致,觸發WSC_NACK
終止會話(后續同)。然后使用同樣方法將自己的第一個秘密隨機數E-S1
加密到EncryptedSettings
。發送 N2(回顯), EncryptedSettings (E-S1), IV, Auth_M5。
-
【M6】:**Registrar提供秘密隨機數讓Enrollee驗證PIN碼第二部分。**Registrar解密
E-S1
并計算E-Hash1
,將自己的第二個秘密隨機數R-S2
加密到EncryptedSettings
發送 N1(回顯), EncryptedSettings (R-S2), IV, Auth_M6。
-
【M7】:**Enrollee提供秘密隨機數讓Registrar驗證PIN碼第二部分。**Enrollee解密
R-S2
并計算R-Hash2
,將自己的第二個秘密隨機數E-S2
加密到EncryptedSettings
發送 N2(回顯), EncryptedSettings (E-S2 + Config-if-AP), IV, Auth_M7。
【配置網絡】
-
【M8】:**完成驗證并配置網絡。**Registrar解密
E-S2
并計算E-Hash2
,雙向認證全部完成。組裝ConfigData網絡配置信息:
ConfigData=Credential(SSID,NetworkKey,AuthType,EncType,...)ConfigData = Credential (SSID, Network Key, AuthType, EncType, ...) ConfigData=Credential(SSID,NetworkKey,AuthType,EncType,...)
同樣使用 KeyWrapKey 加密 ConfigData (過程同前,附加 KWA)。發送 N1(回顯), EncryptedSettings (ConfigData), IV, Auth_M8。最終Enrollee 解密并應用 ConfigData,協議完成。
【通俗解釋】
- Enrollee (手機):“你好路由器,我想加入網絡,這是我的信息(M1)。”
- Registrar (路由器):“好的手機,請證明你知道PIN碼。驗證通過后,我就把Wi-Fi密碼給你(M2)。“
- 雙方都生成兩個上鎖的箱子(E-Hash1/E-Hash2, R-Hash1/R-Hash2),里面是能證明自己身份的秘密。箱子的鑰匙(E-S1/E-S2, R-S1/R-S2)在自己手里。Enrollee 先把自己的兩個鎖上的箱子(M3)交給 Registrar,說:“給,這是我的證明。”
- Registrar 說:“好吧,但我看不到里面。為了表示誠意,這是我能打開你第一個箱子的鑰匙(加密的R-S1),同時我也把我的兩個鎖上的箱子(R-Hash1/R-Hash2)給你。”(M4)
- Enrollee 用只有自己才有的密鑰(KDK)解密拿到鑰匙(R-S1), 打開Registrar的第一個箱子(驗證R-Hash1)。一旦驗證成功,Enrollee 就確信 Registrar 知道真正的 PIN。于是,Enrollee 放心地把打開自己第一個箱子所需的鑰匙(E-S1)交給 Registrar(M5)。
- Registrar 用 E-S1 驗證 Enrollee 的第一個箱子(E-Hash1),也確認了 Enrollee 的身份。后續的 M6、M7 重復這個過程,用第二對箱子和鑰匙(E-Hash2/E-S2, R-Hash2/R-S2)進行二次確認。
1.2 WPS攻擊原理
1.2.1 在線攻擊
PIN碼為8位純數字,而第8位為前面1-7位的校驗和,所以總共只有10的7次方種組合。而由于PIN碼的驗證過程是分段式的,即先驗證前4位,再驗證后4位,則攻擊者只需先猜測前4位組合(104),再猜測后四位組合(103),即最多11000種組合即可猜出正確PIN碼。而WPS協議最初默認沒有對PIN的驗證次數進行限制,這就使在線PIN坡解成為了可能。傳統的在線攻擊方案可以借助 reaver 或 bully 簡便地實現,信號良好情況下大約 3s/pin(WPS1.0,無鎖 PIN 現象),平均幾小時即可攻破一臺路由器。
注意在WPS在線攻擊中,攻擊者電腦扮演的是Registrar,而受攻擊路由器則充當Enrollee(與前面分析的邏輯相反)。攻擊工具(如reaver
或bully
)運行在攻擊者的電腦上(Supplicant/Client)。它宣稱自己是一個“外部注冊器(External Registrar)”,使受攻擊目標接受管理并傳輸網絡配置信息。
攻擊者通過遍歷所有PIN碼組合,發送M4幀后根據是否收到AP回復的WSC_NACK來確定前半段PIN碼是否正確,若不正確則遞增下一個組合。直到猜中前半段PIN碼,再發送M6幀并根據是否收到AP回復的WSC_NACK來確定后半段PIN碼是否正確,最終完全確認整個PIN碼。
1.2.2 離線攻擊
現在多數路由器都是 WPS2.0(WSC),會出現鎖 PIN 現象,一定程度提高了安全性。可就算是幾次 PIN 嘗試的機會,也留給了攻擊者可乘之機。2014年Dominique Bongard演示了一種離線WPS的方法,對某些存在安全漏洞的路由器可在不到一秒內破譯。該攻擊利用了某些路由廠商芯片只能生成低熵的偽隨機數,進而坡解加密過程。攻擊稱為“pixie-dust attack”,翻譯為“小精靈塵埃攻擊”或“仙塵”攻擊(外國人起名靈感感覺大都跟游戲影視作品有關)。
入網設備和AP之間沒有傳輸PIN碼,是通過計算PIN碼的Hash值來驗證的。如果PIN碼驗證失敗,流程會止于M4階段。根據之前在線PIN坡解過程分析,攻擊者可以獲取到PIN碼最終計算產物E-Hash1和E-Hash2(AP發送的M3幀),以及中間計算值AuthKey、PKE、PKE,而初始參數PIN碼與兩個中間計算使用的隨機數E-S1和E-S2是不知道的。但是如果攻擊者能猜測到AP生成的隨機數E-S1和E-S2,就可以通過代入所有PIN碼組合去猜測驗證,最終獲取到PIN碼。
其實這里筆者有點疑惑,為什么攻擊者不按常規流程充當Enrollee角色,去獲取AP發送的M4幀,這樣還可以多獲取到一個隨機數信息。可能是因為代碼是基于reaver改編的分支,而reaver就是使用Registrar角色去進行攻擊吧。
那么怎么能猜到AP生成的隨機數呢?Dominique Bongard發現某些路由器的芯片生成的是不安全的偽隨機數(Pseudo-Random Number Generator,PRNG),導致其可以通過上一個隨機數進行逆向預測。例如,Broadcom基本上使用C中的Rand()函數,在Ralink中隨機數始終不會生成(因此為0),而RTL819x生成的隨機數存在復用(N1、E-S1、E-S2均相同)。
易受攻擊的路由器收錄:https://docs.google.com/spreadsheets/d/1tSlbqVQ59kGn8hgmwcPTHUECQ3o9YhXR91A_p7Nnj5Y/edit#gid=2048815923
在攻擊過程中,M1階段受攻擊路由器會生成隨機數N1(E-Nonce),到M3階段又會生成的隨機數E-S1和E-S2,這兩個隨機數是緊接著N1生成的。而N1可以直接捕獲到,如果路由器生成的是偽隨機數,就可以進行逆向分析。下面分析pixiewps源碼中的兩種逆推偽隨機數的模式:Ralink模式(直接計算)和eCos模式(暴力枚舉)。
1.2.2.1 Ralink模式
- Ralink基于線性反饋移位寄存器(LFSR)算法生成偽隨機數,使用的是 32 位 Galois LFSR(掩碼 0x80000057),生成代碼如下。
//Ranlink隨機數生成
static unsigned char ralink_randbyte(struct ralink_randstate *state)
{unsigned char r = 0;for (int i = 0; i < 8; i++) {unsigned char result;if (state->sreg & 0x00000001) { // 檢查LSBstate->sreg = ((state->sreg ^ 0x80000057) >> 1) | 0x80000000;result = 1;}else {state->sreg = state->sreg >> 1; // 簡單右移result = 0;}r = (r << 1) | result; // MSB優先累積}return r;
}
偽隨機數生成流程:
- 選定一個初始的數S0,在LFSR中通常稱為狀態(可以理解為種子,如:1010…1011 ,共32位),先取最低位(Least Significant Bit,LBS)作為輸出隨機數的第一位(最左邊的一位)。
- 如果最低位為1則S0與多項式(0x80000057)進行異或操作,如果最低位為0則不變,得到S0‘。
- 對S0‘右移一位,如果進行了異或操作則高位補1,如果沒有操作則高位補0,得到S1。
- 接著重復這個過程,再次對S1取值、操作、右移,一步步得到隨機數的第二、三、…、八位,循環做8次就可以得到1字節(8bit)的隨機數。而N1為16字節,則需做8x16次運算。
static void ralink_randstate_restore(struct ralink_randstate *state, uint8_t r)
{for (int i = 0; i < 8; i++) {const unsigned char result = r & 1; // 取LSB(從后向前處理)r = r >> 1;if (result) { // 如果輸出位是1state->sreg = (((state->sreg) << 1) ^ 0x80000057) | 0x00000001;}else { // 如果輸出位是0state->sreg = state->sreg << 1; // 簡單左移}}
}
通過隨機數逆向種子:
由隨機數的最后一位,可以知道上一次的操作數Sn的最后一位(如果隨機數最后一位是0,則Sn’的最后一位為0;如果隨機數最后一位是1,則Sn’的最后一位為1)。同理,由隨機數倒數第二位,可以知道上上次的操作數Sn-1的最后一位,以此類推。由于知道每次操作數的最后一位,從最后一次操作數Sn開始進行補值、操作、左移(逆運算)。
- 如假如隨機數最后一位為1,則設最后一次操作數Sn為0000…0001(最后一位為0則設0000…0000,最后一位前面的值隨便設,因為后續會不斷左移去掉)。
- 然后觀察隨機數倒數第二位,倒數第二位為1,則說明Sn-1’到Sn做了異或操作,那么需要再與多項式(0x80000057)做一次異或操作使其變為Sn-1’;如果隨機數倒數第二位為0,則無需操作Sn即Sn-1’。
- 將Sn-1‘左移,然后末尾補隨機數的倒數第二位,變為Sn-1。
- 重復這個過程,直至將最開始Sn的最后一位左移到第一位。一共32位,所以做31次即可逆向出某個時刻的操作數(種子)。
static unsigned char ralink_randbyte_backwards(struct ralink_randstate *state)
{unsigned char r = 0;for (int i = 0; i < 8; i++) {unsigned char result;if (state->sreg & 0x80000000) { // 檢查MSBstate->sreg = ((state->sreg << 1) ^ 0x80000057) | 0x00000001;result = 1;}else {state->sreg = state->sreg << 1; // 簡單左移result = 0;}r |= result << i; // LSB優先累積}return r;
}
通過種子逆向生成隨機數:
前面是通過種子往后生成隨機數,這個代碼是通過種子往前生成隨機數,過程類似。
- 選定一個初始的數Sn,先取最高位(Most Significant Bit,MSB)作為輸出隨機數的最后一位(最右邊的一位,這里是第八位)。
- 如果最高位為1則S0與多項式(0x80000057)進行異或操作,如果最高位為0則不變,得到Sn‘。
- 對Sn‘右移一位,如果進行了異或操作則低位補1,如果沒有操作則低位補0,得到Sn-1。
- 接著重復這個過程,再次對Sn-1取值、操作、左移,一步步得到隨機數的第七、六、…、一位,循環做8次就可以得到1字節(8bit)的隨機數。
LFSR算法生成的隨機數是完全可逆的,在源碼中是先通過隨機數N1(E-Nonce)反推種子,然后回退 16 字節得到 E?S2,再接著回退 16 字節得到 E?S1。這里筆者是挺疑惑的,按照WSC規范,生成順序應該是N1 -> E-S1 -> E-S2。不清楚代碼為什么不是從N1繼續正向生成隨機數E-S1和E-S2,而是逆向生成E-S2和E-S1,也許這個隨機數的生成邏輯就是逆向生成吧。
1.2.2.2 eCos模式
- eCos simple 模式基于線性同余生成器(LCG,Linear Congruential Generator)算法生成偽隨機數,源自 C 語言標準庫的
rand()
函數,生成代碼如下。
static uint32_t ecos_rand_simple(uint32_t *seed)
{uint32_t s = *seed;uint32_t uret;// 第一步:線性同余生成s = (s * 1103515245) + 12345; // 生成s1uret = s & 0xffe00000; // 取高11位 (bits 31-21)// 第二步:繼續生成 s = (s * 1103515245) + 12345; // 生成s2uret += (s & 0xfffc0000) >> 11; // 取高14位右移11位 (bits 31-18 → bits 20-7)// 第三步:再次生成s = (s * 1103515245) + 12345; // 生成s3uret += (s & 0xfe000000) >> (11 + 14); // 取高7位右移25位 (bits 31-25 → bits 6-0)*seed = s;return uret; // 返回32位值,但實際只使用低8位
}//使用時只取低8位
output_byte = ecos_rand_simple(&seed) & 0xFF;
偽隨機數生成流程:
- 選定一個初始的數S0(32位)作為種子。對這個數乘以一個乘數(1103515245),再進行增量(12345),得到S1,取高11位作為隨機數的高11位。
- 對S1再乘以乘數并進行增量,得到S2,取高14位作為隨機數中間14位。
- 對S2再乘以乘數并進行增量,得到S3,取高7位作為隨機數低7位。總共得到11+14+7=32位隨機數,但使用時只取低8位。
整體操作為對操作數做3次LCG固定計算s = (s * a + c) % m,每次取部分高位拼接成隨機數。末尾取模在代碼中沒有顯式編寫,實際上因為使用了無符號整數(232),計算后溢出的高位會被丟棄,相當于取2^32的模。
uint32_t known = wps->e_nonce[0] << 25; /* 將熵從32位減少到25位 */
uint32_t seed, counter = 0;
while (counter < 0x02000000) { // 2^25 = 33,554,432次嘗試int i;seed = known | counter; // 構建候選種子// 驗證后續15個字節for (i = 1; i < WPS_NONCE_LEN; i++) {if (wps->e_nonce[i] != (uint8_t)(ecos_rand_simple(&seed) & 0xff))break;}// 如果所有字節都匹配if (i == WPS_NONCE_LEN) {// 找到正確種子,繼續生成E-S1和E-S2wps->s1_seed = seed;for (i = 0; i < WPS_SECRET_NONCE_LEN; i++)wps->e_s1[i] = (uint8_t)(ecos_rand_simple(&seed) & 0xff);wps->s2_seed = seed;for (i = 0; i < WPS_SECRET_NONCE_LEN; i++)wps->e_s2[i] = (uint8_t)(ecos_rand_simple(&seed) & 0xff);break;}counter++;
}
通過隨機數逆向種子:
首先一字節的隨機數(8位)的后7位就是取自最后一次操作數的S3的前7位,那么對于S3還有剩下的25位未知。而LCG算法與前面LFSR算法不同,生成隨機數會溢出部分數據導致計算不可逆。但偽隨機數的特點就是計算過程是固定的,通過分析連續生成的隨機數,知道結果就可以直接套初始值去猜測,最終逆推出種子。
對于WPS中生成的N1(E-Nonce)總共16字節,我們取第1個字節,其前7位做種子的前7位,對于未知的后25位進行枚舉猜測,同樣使用LCG算法去計算后面生成的隨機數,與N1的后15字節結果進行比對。如果計算結果比對實際隨機數完全一致,那就說明猜測成功。這種方式即暴力坡解,最多猜測2^25次(33,554,432),計算機可在幾秒內完成。
猜出種子后,再往后計算就可以得到E-S1和E-S2。
2 實驗過程
本次實驗以無線安全審計目的,意在對路由器安全強度進行測試,僅做學習研究之用。請注意遵循相關法律法規。
其實現在大多數路由器已經沒有WPS漏洞了,越新的路由器會采用更新的無線安全標準(如WPA3),同時禁用WPS功能。無線安全水平是在不斷提升的,但也不排除還有少部分老舊路由器沒有被淘汰更新。
本次實驗使用的軟件為WiFiGrab。
百度云盤下載:https://pan.baidu.com/s/1Q9oWrHF_nKgwOtKyVcb7IQ?pwd=xxwd
123云盤下載:https://www.123684.com/s/q496Td-Ru95H
-
接入USB抓包網卡后啟動軟件。
-
在設置中可同時啟用2.4G和5G掃描,并將掃描時間改長一些,確認。
-
點擊掃描WiFi,對附近無線網絡進行掃描。
掃描完成,可以觀察邊框顏色,黑色邊框說明AP啟用了WPS,灰色邊框說明AP未啟用WPS(軟件通過AP信標幀中的wifi_protected_setup_state字段確定)。
僅對已啟用WPS的AP進行測試(需注意隱藏WiFi即使啟用了WPS,也無法直接進行WPS攻擊,因為不知道WiFi名稱無法接入。但其實WiFi名稱是可以通過抓包獲取的,不過本軟件不涉及該內容)。
-
以筆者自己的路由器(榮耀CD16)進行測試,選擇目標后,點擊PIN。
-
運行后WPS離線攻擊沒有成功,說明該路由器沒有偽隨機數漏洞。
觀察日志可以看到,軟件如前面分析的,對AP發起WPS的流程。通過M1到M3交互獲取到E-Nonce、PKR、PKE、AuthKey等信息,然后嘗試猜測E-S1和E-S2,但未猜測成功,該AP可能基于物理過程生成的是真隨機數,或是使用其他算法生成的隨機數。
-
筆者對周圍的路由器也進行了安全測試,發現大多數路由器也不存在此漏洞,是較新的路由設備。但也有極個別路由器(可能是采用老式芯片的光貓或路由器)是有該漏洞存在的。
前文有易受攻擊的路由器收錄的信息,而WPS的廣播信息中有兩個字段Model Name和Model Number標識了AP設備的型號與編號,由此能得知AP是否易受攻擊。易受攻擊的路由器在軟件中會顯示為藍色邊框,同時在MAC地址后側括號中會顯示該設備信息(如Ralink Wireless Access Point RT2860)。
筆者找到了個別顯示藍色邊框的路由器進行測試,發現其PIN碼信息可以被計算出來,且只需要不到十幾秒時間。
3 參考資料
https://ifconfig.dk/pixiedust/
https://github.com/2EXP/2exp.github.io/issues/3
https://mlg556.github.io/posts/bruteforce-wps-with-reaver-and-pixiewps/bruteforce-wps-with-reaver-and-pixiewps.html
https://blog.csdn.net/moonlinux20704/article/details/109102318
http://archive.hack.lu/2014/Hacklu2014_offline_bruteforce_attack_on_wps.pdf