Android藍(lán)牙協(xié)議棧漏洞剖析
1.背景介紹
藍(lán)牙協(xié)議相對于其他通信協(xié)議如WIFI(802.11)、傳統(tǒng)TCP/IP議協(xié)等來說,更為復(fù)雜,目前藍(lán)牙核心規(guī)范(5.3)高達(dá)3085頁。藍(lán)牙的這種復(fù)雜性使得對藍(lán)牙的各個協(xié)議的實現(xiàn)進(jìn)行安全測試與審計變得相對困難,從而導(dǎo)致協(xié)議的實現(xiàn)和使用容易出現(xiàn)較多的安全漏洞。但是從另一方面來說,它的復(fù)雜性也會要求研究員或攻擊者進(jìn)行漏洞挖掘的技術(shù)門檻變得相對更高,需要突破的難點也會更多。
圖1 藍(lán)牙核心規(guī)范說明書封面
圖2 藍(lán)牙協(xié)議棧架構(gòu)
如圖2所示,藍(lán)牙協(xié)議棧主要分為兩個部分:Host和Controller。Host主要包含鏈路層之上的整個藍(lán)牙協(xié)議棧,包含傳輸層L2CAP以及在它之上的多種應(yīng)用層協(xié)議,是藍(lán)牙協(xié)議棧的核心部分。Controller主要與硬件驅(qū)動打交道,偏底層。本文主要關(guān)注的是Host層各協(xié)議的實現(xiàn)安全。
從Android系統(tǒng)發(fā)展歷史上來看,其藍(lán)牙協(xié)議棧也一直是安全研究的重點目標(biāo)。2017年Armis安全團(tuán)隊公布BlueBorne組合漏洞攻擊鏈可以通過藍(lán)牙對智能手機(jī)進(jìn)行遠(yuǎn)程攻擊,危害性極大。2020年Android爆出BlueFrag漏洞,攻擊者可以通過該漏洞實現(xiàn)遠(yuǎn)程零交互的遠(yuǎn)程代碼執(zhí)行。
OPPO安珀實驗室一直致力于參與維護(hù)整個Android系統(tǒng)生態(tài)安全,因此也對Android藍(lán)牙協(xié)議棧展開了深入的研究。至今我們已向Google Android安全團(tuán)隊提報了多個藍(lán)牙協(xié)議棧實現(xiàn)安全漏洞,這次將依次介紹我們團(tuán)隊發(fā)現(xiàn)的三個不同Android藍(lán)牙協(xié)議模塊漏洞:CVE-2020-27024(SMP協(xié)議)、CVE-2021-0918(GATT協(xié)議)、CVE-2021-39805(L2CAP協(xié)議)。
2.CVE-2020-27024
2.1 SMP協(xié)議簡介
SMP(Security Manage Protocol)安全管理協(xié)議定義了配對和密鑰分發(fā)的過程實現(xiàn),然后使用密鑰對鏈路通信數(shù)據(jù)進(jìn)行加密。SMP被用在LE設(shè)備或藍(lán)牙雙模設(shè)備中。如圖3所示,SMP協(xié)議工作流程大致分為幾個階段:
Step1:特征交換
配對特征交換,即交換各自都支持哪些配對特性,比如支不支持Secure Connection(安全連接),支不支持MITM,支不支持OOB(Out of Band:帶外),以及它的輸入輸出能力(IO capabilities)等。
Step2:密鑰產(chǎn)生
該階段雙方將協(xié)商生成產(chǎn)生STK/LTK:
LE Legacy pairing:產(chǎn)生Short Term Key(短期密鑰)。
LE Secure Connection:產(chǎn)生Long Term Key(長期密鑰)。
Step3:密鑰分發(fā)
該階段分發(fā)一些其他用途的Key,像Identity Resolving Key(IRK),這個Key是用于Random Address解析。當(dāng)分發(fā)這些Key時,此階段鏈路是必須要加密的,若不加密,將導(dǎo)致密鑰直接泄漏。加密使用的密鑰是用第二階段產(chǎn)生的STK或LTK,或者雙模下直接共享使用BR/EDR配對產(chǎn)生的Key。
Step4:鏈路加密
通過使用STK/LTK密鑰對整個藍(lán)牙通信鏈路進(jìn)行加密。
SMP協(xié)議整個配對流程如下圖所示,其中配對發(fā)起方角色為主設(shè)備類型(MASTER),接收方為角色為從設(shè)備類型(SLAVE)。
圖3 SMP協(xié)議工作流程
2.2 漏洞剖析
CVE-2020-27024是SMP協(xié)議中一個數(shù)組越界漏洞。SMP協(xié)議使用預(yù)定義的L2CAP_SMP_CID(0x06)、L2CAP_SMP_BR_CID(0x07)通道,位于L2CAP協(xié)議層之上。如圖4所示,SMP協(xié)議棧smp_l2cap_if_init()函數(shù)負(fù)責(zé)注冊SMP數(shù)據(jù)報文接收回調(diào)處理函數(shù),分別為處理BLE藍(lán)牙SMP報文的smp_data_received()函數(shù),以及處理BR藍(lán)牙SMP報文的smp_br_data_received()函數(shù)。
圖4 Android藍(lán)牙協(xié)議棧SMP協(xié)議的初始化代碼段
由BR藍(lán)牙通信鏈接傳入的SMP數(shù)據(jù)包將交由smp_br_data_received()函數(shù)[ 代碼位于/system/bt/stack/smp/smp_l2c.cc]處理。當(dāng)SMP協(xié)議棧接收到對端發(fā)起的配對請求SMP數(shù)據(jù)包SMP_OPCODE_PAIRING_REQ(0x01)時,報文處理流程則將到達(dá)以下圖5的代碼段。
圖5 smp_br_data_received()函數(shù)代碼段
當(dāng)smp_br_data_received()函數(shù)處理完成后,它調(diào)用smp_br_state_machine_event()函數(shù) [代碼位于/system/bt/stack/smp/smp_br_main.cc ],該函數(shù)代碼實現(xiàn)如圖6所示。
圖6 smp_br_state_machine_event()函數(shù)代碼段
首先我們可從圖7中看到全局變量smp_br_entry_table數(shù)組的SIZE其實為2。
圖7 smp_br_entry_table數(shù)組定義
從圖6中的代碼段我們可以看到由于smp_br_state_machine_event()函數(shù)在一開始執(zhí)行tSMP_BR_ENTRY_TBL entry_table = smp_br_entry_table[p_cb->role]語句時并未對p_cb->role的最大值進(jìn)行合法性判斷,反而是取值后再判斷p_cb->role的合法性。當(dāng)攻擊者惡意造成p_cb->role出現(xiàn)取值大于2的情況時,將導(dǎo)致smp_br_state_machine_event()函數(shù)entry_table賦值語句出現(xiàn)內(nèi)存OOB越界讀的異常。
3.CVE-2021-0918
3.1 GATT協(xié)議簡介
GATT是 Generic Attributes的縮寫,中文是通用屬性,它是低功耗藍(lán)牙BLE設(shè)備之間進(jìn)行通信的協(xié)議。GATT定義了一種多層的數(shù)據(jù)結(jié)構(gòu),已連接的低功耗藍(lán)牙設(shè)備用它來進(jìn)行通信,其定義的多層數(shù)據(jù)結(jié)構(gòu)簡要概括起來就是服務(wù)(service)可以包含多個特征(characteristic),每個特征包含屬性(properties)和值(value),還可以包含多個描述(descriptor)。
GATT基于ATT協(xié)議(屬性協(xié)議)來承載的,屬性協(xié)議主要用來發(fā)現(xiàn)、讀寫、通知和指示屬性。
圖8 GATT協(xié)議交互圖
在ATT層協(xié)議框架內(nèi),擁有一組屬性的設(shè)備稱為服務(wù)端(Server),讀寫該屬性值的設(shè)備稱為客戶端(Client),Server和Client通過ATT PDU進(jìn)行交互;
其中Attribute Protocol PDU報文格式如圖9所示。其中Opcode:操作碼(消息類型,1字節(jié)大?。?; Attribute Parameters:ATT參數(shù)(變長); Authentication Signature:身份驗證簽名。
圖9 Attribute Protocol PDU報文格式
ATT消息各種類型多達(dá)30多種,其中常見的消息類型包含表1中的6種類型,如下表所示。后續(xù)介紹的Android藍(lán)牙協(xié)議棧GATT漏洞也就是存于Notification消息類型處理函數(shù)代碼當(dāng)中的。
表1 Attribute Protocol PDU的類型表
PDU類型 | 發(fā)送方 | 描述信息 |
請求/Request | Client | 客戶端向服務(wù)器請求數(shù)據(jù) |
回復(fù)/Response | Server | 服務(wù)器對上面請求的回復(fù) |
命令/Command | Client | 客戶端向服務(wù)器發(fā)送命令-無回復(fù) |
通知/Notification | Server | 服務(wù)器對特征數(shù)值向客戶端發(fā)起通知-無回復(fù) |
指示/Indication | Server | 服務(wù)器對特征數(shù)值指示發(fā)送給客戶端 |
確認(rèn)/Confirmation | Client | 客戶端對指示的應(yīng)答 |
3.2 漏洞剖析
CVE-2021-0918是Android系統(tǒng)GATT藍(lán)牙協(xié)議棧處理Notification類型報文時存在的一個內(nèi)存OOB越界讀寫安全漏洞。
藍(lán)牙協(xié)議GATT報文數(shù)據(jù)核心處理函數(shù)位于gatt_data_process()函數(shù)[system\bt\stack\gatt\gatt_main.cc]。如圖10所示,該函數(shù)通過op_code值類型判斷,決定該報文是來自client端還是server端,然后分別調(diào)用不同的函數(shù)處理接口gatt_server_handle_client_req及gatt_client_handle_server_rsp函數(shù)。
圖10 gatt_data_process()代碼段
通過分析該代碼我們發(fā)現(xiàn)可以通過精心構(gòu)造opcode值(如GATT_HANDLE_VALUE_IND:0x1D、GATT_HANDLE_VALUE_NOTIF:0x1B、GATT_HANDLE_MULTI_VALUE_NOTIF:0x23)來控制函數(shù)執(zhí)行調(diào)用到gatt_client_handle_server_rsp()函數(shù)。其中GATT_HANDLE_MULTI_VALUE_NOTIF類型是后續(xù)觸發(fā)漏洞的報文類型。
圖11 gatt_client_handle_server_rsp()代碼段
最后gatt_client_handle_server_rsp()將調(diào)用到gatt_process_notification()函數(shù)。該漏洞問題代碼是就位于system/bt/stack/gatt/gatt_cl.cc文件內(nèi)的gatt_process_notification()函數(shù),該函數(shù)是負(fù)責(zé)對接收到的gatt協(xié)議notification類型通知報文進(jìn)行解析處理。
圖12 gatt_process_notification()代碼段
首先介紹下Android藍(lán)牙協(xié)議棧里常用的解析報文內(nèi)容的宏定義:STREAM_TO_INT8(u8, p)從p指向的報文中讀取1個字節(jié),保存到u8類型變量當(dāng)中,p指針加1;STREAM_TO_UINT16(u16, p)每次從p指向報文中讀取2個字節(jié),保存到u16類型變量當(dāng)中,p指針加2。STREAM_TO_ARRAY(a, p, len)負(fù)責(zé)從p指向的報文內(nèi)容讀取len字節(jié)長度的數(shù)據(jù),保存到數(shù)組變量a空間中,p指針加len長度。另外tGATT_VALUE value變量類型的結(jié)構(gòu)體構(gòu)造如圖13所示。
圖13 tGATT_VALUE結(jié)構(gòu)體
我們可以看到gatt_process_notification()函數(shù)內(nèi)當(dāng)op_code值為GATT_HANDLE_MULTI_VALUE_NOTIF類型時,value.len變量值是可以通過報文內(nèi)長度字段來控制的,此時如果value.len長度大于實際數(shù)據(jù)長度len時且小于GATT_MAX_ATTR_LEN(固定值為600),后續(xù)STREAM_TO_ARRAY(value.value, p, value.len)這行代碼將導(dǎo)致一個OOB越界讀的異常內(nèi)存拷貝操作。如圖14所示,后續(xù)gatt_process_notification函數(shù)在循環(huán)解析報文內(nèi)的多個notification消息時,由于未對解析出的value.len的長度做最大長度(不能超過GATT_MAX_ATTR_LEN)合法性校驗,將導(dǎo)致STREAM_TO_ARRAY(value.value, p, value.len)出現(xiàn)內(nèi)存OOB越界寫的風(fēng)險。
圖14 gatt_process_notification()后續(xù)代碼段
4 CVE-2021-39805
4.1 L2CAP協(xié)議簡介
L2CAP(Logical Link Control and Adaptation Protocol)稱為邏輯鏈路和適配協(xié)議,是藍(lán)牙系統(tǒng)中的核心協(xié)議。L2CAP通過協(xié)議多分復(fù)用、分段和重組,向高層提供面向連接和無連接的數(shù)據(jù)服務(wù)。
圖15 L2CAP協(xié)議交互圖
L2CAP基于信道的概念,信道的每一個端點被稱為信道標(biāo)識符(CID),同設(shè)備間CID可復(fù)用,但本地設(shè)備CID不可復(fù)用。 L2CAP是基于分組的,但也遵循信道傳輸?shù)耐ㄐ拍P?。對端設(shè)備上兩個L2CAP實體間傳遞的信號命令(Signaling Commands)這些信號命令通過Signaling Channel來傳輸,對于ACL-U邏輯鏈路應(yīng)該使用CID 0x0001, 而對于LE-U則應(yīng)該使用CID 0x0005。如L2CAP LE Signalling Channel信令通道,用于控制LE面向連接的數(shù)據(jù)信道,并可對這些LE信道的特性變化進(jìn)行協(xié)商(LE-U),后續(xù)介紹的漏洞就位于L2CAP LE Signalling Channel通道信令的處理代碼中。藍(lán)牙規(guī)范定義的CID如圖16所示。
圖16 BLE信道CID
L2CAP數(shù)據(jù)包的格式如下圖所示。
圖17 L2CAP數(shù)據(jù)包的格式
L2CAP信令報文格式如下所示。
圖18 L2CAP信令報文格式
4.2 漏洞剖析
CVE-2021-39805是L2CAP協(xié)議中一個數(shù)組越界讀漏洞。問題代碼位于l2cap藍(lán)牙協(xié)議棧system\bt\stack\l2cap\l2c_ble.cc文件中的l2cble_process_sig_cmd函數(shù)。該函數(shù)主要負(fù)責(zé)解析處理LE的信令通道控制報文。
圖19 l2cble_process_sig_cmd()代碼段
當(dāng)L2CAP層處理基于信用的增強(qiáng)型流控模式的重新配置的回復(fù)(L2CAP_CMD_CREDIT_BASED_RECONFIG_RES,0x1A)報文時,其未進(jìn)行包長度判斷,導(dǎo)致內(nèi)存信息泄露。顧名思義,這個回復(fù)就是響應(yīng)重新配置的請求(request)報文,這個(request)請求是為了重新配置該通道的MTU和MPS的,其結(jié)構(gòu)如圖18。圖19就是響應(yīng)的回復(fù)報文。
圖20基于信用的增強(qiáng)型流控模式的重新配置請求
圖21基于信用的增強(qiáng)型流控模式的重新配置回復(fù)
Android在2020年8月左右添加了對基于信用的增強(qiáng)型流控模式的支持,此漏洞代碼就從那時起一直存在,如圖22所示。這段代碼段中,STREAM_TO_UINT16從回復(fù)報文去取result字段的值,但是取之前未判斷此時回復(fù)的報文是否已經(jīng)沒有多余的數(shù)據(jù)了。因此,若精心構(gòu)造一個該回復(fù)數(shù)據(jù)包,那么就會觸發(fā)到這個地方導(dǎo)致OOB Read。且這個被賦值的result字段后續(xù)會返回給發(fā)送方,導(dǎo)致內(nèi)存信息泄露。
圖22 l2cble_process_sig_cmd()后續(xù)代碼段
5.總結(jié)與展望
Android系統(tǒng)中藍(lán)牙協(xié)議棧演進(jìn)分為幾個階段,最早android使用是Linux藍(lán)牙協(xié)議棧BlueZ。從Android 4.2開始,Google便在Android源碼中推出了它和博通公司一起開發(fā)的BlueDroid以替代BlueZ。當(dāng)前Android使用的藍(lán)牙協(xié)議棧版本名為Fluoride,而Google正在開發(fā)的下一代藍(lán)牙協(xié)議棧叫做Gabeldorsh,并使用Rust編程語言進(jìn)行開發(fā)。 目前Fluoride藍(lán)牙協(xié)議?;旧线€是使用C/C++語言來實現(xiàn)的,由于藍(lán)牙報文的協(xié)議解析處理涉及大量的內(nèi)存操作,加上藍(lán)牙協(xié)議的多樣性和復(fù)雜性,以及歷史上多家公司代碼融合等各類原因,導(dǎo)致安卓藍(lán)牙協(xié)議棧爆出過很多嚴(yán)重RCE漏洞。而Gabeldorsh可以利用Rust語言本身的特性減少內(nèi)存型漏洞的產(chǎn)生。這就導(dǎo)致今后對藍(lán)牙協(xié)議棧的漏洞挖掘更會集中于邏輯性漏洞,如協(xié)議本身的邏輯問題、條件競爭、設(shè)計缺陷等方面,這就更加要求該領(lǐng)域的漏洞挖掘研究員具有更加深厚的藍(lán)牙技術(shù)知識棧,漏洞挖掘的技術(shù)門檻也會更高、需要突破的難點也會更多。
6.參考鏈接
《Bluetooth核心規(guī)范》:https://www.bluetooth.com/specifications/specs/core-specification-5-3/
《Pixel 更新公告 - 2020 年 12 月》:https://source.android.com/security/bulletin/pixel/2020-12-01?hl=zh-cn
《Android 安全公告 - 2021 年 11 月》:https://source.android.com/security/bulletin/2021-11-01
《Android 安全公告 - 2022 年 4 月》:https://source.android.com/security/bulletin/2022-04-01