Android藍牙子系統“BlueFrag”漏洞分析(CVE-2020-0022)
發布時間 2020-02-13一、漏洞背景
2020年2月,Android安全公告中披露并修復了一個嚴重漏洞,漏洞編號為CVE-2020-0022,又稱BlueFrag,可影響Android藍牙子系統。該漏洞是一個遠程代碼執行漏洞,出現在Bluedroid藍牙協議棧的HCI層,當無線模塊處于活動狀態時,攻擊者可以利用藍牙守護程序提升權限進而在設備上執行代碼。該漏洞影響Android Oreo(8.0和8.1)、Pie(9),但無法在Android 10上進行利用,僅能觸發DoS攻擊。
二、協議簡介
2.1 HCI
HCI 層位于藍牙協議棧高層協議和低層協議之間,提供了對基帶控制器和鏈路管理器的命令以及訪問藍牙硬件的統一接口方法,其接口適用于BR/EDR控制器、BR/EDR/LE控制器、LE控制器、AMP控制器,與底層的結構關系如下圖:
主機系統上的HCI驅動程序和控制器中的HCI層之間會存在中間層, 這些中間層即是主機控制器傳輸層,這些傳輸層是透明的,只需完成傳輸數據的任務,不必清楚數據的具體格式。兩個藍牙設備點對點HCI層的交互過程如下圖所示:
2.1.1 HCI包格式
HCI通過包的方式來傳送數據、命令和事件的,所有在主機和主機控制器之間的通信都以包的形式進行。包括每個命令的返回參數都通過特定的事件包來傳輸。HCI有數據、命令和事件三種類型的包。命令包COMMAND(0x01)只能從主機發往主機控制器,其中數據包是雙向的,分為兩類:ACL(0x02)、SCO(0x03),而事件包EVENT(0x04)始終是主機控制器發向主機的。主機發出的大多數命令包都會觸發主機控制器產生相應的事件包作為響應,在傳輸過程中會有一個句柄,用于識別主機之間的邏輯通道和控制器,共有三種類型的句柄:連接句柄、邏輯鏈路句柄和物理鏈路句柄。
根據需要,這里只介紹ACL數據包格式,ACL 數據用于主機和控制器之間的非同步數據交換,如播放音樂數據的數據包,格式如下圖:
每個字段的說明如下所示:
字段 |
說明 |
Handle |
Connection_Handle用于在主控制器上傳輸數據包或段。 |
PB Flag |
包邊界和適應范圍。 |
BC Flag |
廣播標志。 |
Data Total Length |
以八位位組為單位的數據長度,包含高層協議data。 |
其中,PB Flag的描述如下:
設置為 00'b 的時候,代表 Host -> Contoller 的 L2CAP 的首包。設置為 01’b 的時候,代表 Host -> Contoller 或者 Contoller -> Host 的 L2CAP 的續包(中間的)。設置為 10'b 的時候,代表 Contoller -> Host 的 L2CAP 的首包。
2.1.2 分段(Fragmentation)和重組(Reassembly )
分段是將PDU分解成較小的部分,以便從L2CAP傳遞到較低層。重組是根據從下層傳遞來的片段重組PDU的過程。分段和重組可以應用于任何L2CAP PDU。
2.2 L2CAP數據包格式
L2CAP是基于分組的,但也遵循信道傳輸的通信模型。L2CAP支持的信道有兩種:面向連接的信道和面向無連接的信道。在面向連接的信道中,L2CAP數據包的格式如下圖所示。
數據包中每個字段的說明如下所示:
字段 |
說明 |
Length |
2字節,表示信息有效負載的大小,不包括長度L2CAP頭。 |
Channel ID(CID) |
2字節,用于標識目的信道的終端。通道ID的范圍與正在發送數據包的設備相關。 |
Information(Payload) |
信息負載。長度為0到65535字節。 |
三、漏洞原理分析
CVE-2020-0022漏洞位于HCI層,漏洞補丁代碼位于hci/src/packet_fragmenter.cc(以8.1.0_r33為例)中的reassemble_and_dispatch()函數中,該函數是用于數據包分片的重組。對于過長的ACL數據包需要進行包的重組,主要是根據ACL包中的PB Flag標志位進行重組,如果當前是起始部分并且是不完整的,則生成一個部分包(partial_packet)放到map里,等下次收到它的后續部分進行拼裝,拼裝完畢后就分發出去。詳細分析reassemble_and_dispatch()函數如下:
首先,處理第一個packet,代碼127行到129行,分別讀取handle、acl_length和l2cap_length。handle為本次鏈路的Connection_Handle。根據前文數據包格式的介紹,acl_length為Data Total Length,該data數據域中存放著L2CAP數據包分片(也可能是一個完整的L2CAP數據包)。然后,直接讀取data中L2CAP Length,該l2cap_length是一個完整的L2CAP數據包中payload的長度。行131,校驗packet包長度是否正常。行133,通過handle獲取boundary_flag,即是PB Flag。
行136,判斷boundary_flag是否為2,二進制表示為10’b,即判斷當前packet是否為 Contoller -> Host 的 L2CAP 的首包,如果是,進入if語句。行137到行147,判斷當前packet是否已經被處理,保證本次處理的packet都是最新的。行149到行154,判斷L2CAP數據包長度是否正常,不正常直接報錯返回。
接下來,行156到行157,計算full_length,其中包括一個完整的L2CAP數據包中的payload的長度,一個L2CAP頭部長度和一個HCI頭部長度。行161到行168,判斷full_length是否超過BT_DEFAULT_BUFFER_SIZE,如果超過直接報錯返回。行170到行178,判斷當前頭包packet是否還有續包,如果沒有續包直接調用callbacks->reassembled處理當前packet并返回。
如果當前頭包packet后面還有續包,那就開始重新分配一塊新的內存用于packet中數據包重組。行180到184,分配并設置partial_packet,將partial_packet->len設置為full_length,將partial_packet->offset設置為packet->len即當前頭包packet->data的長度。行186,調用memcpy,將頭包packet中HCI數據包整體拷貝到partial_packet中。行189到行191,先找到HCI數據包頭部,并跳過handle,更新acl_length為一個完整的L2CAP數據包長度。行193,將partial_packet存放到容器中。行196,釋放當前頭包packet,表示已經處理完第一個packet,不再需要它了。行197,else語句開始處理后續packet,即boundary_flag不等于2的packet。
行198到行205,首先通過handle判斷當前后續packet是否屬于本次鏈路的,如果不屬于,直接返回。行206,獲取前一輪生成的partial_packet。行208,將當前后續packet->offset賦值為HCI_ACL_PREAMBLE_SIZE即4字節,此時packet->offset指向HCI包中的data域,里面存放著L2CAP數據包分片。行209和行210,計算projected_offset,projected_offset為partial_packet->offset與本次L2CAP數據包分片的長度之和。
行211和行219,判斷projected_offset是否大于partial_packet->len,即判斷projected_offset是否大于full_length。如果大于,則修改packet->len為partial_packet->len減去partial_packet->offset,即packet->len為partial_packet剩余空間的長度。然后,將projected_offset設置為partial_packet->len。具體數據包重組如下圖所示:
修正好實際要拷貝的長度后,行221,調用memcpy進行拷貝,漏洞點到了,第一個參數為partial_packet->data + partial_packet->offset,目的地址是正確的,第二個參數為packet->data + packet->offset,源地址也是正確的,第三個參數是要拷貝的長度len為packet->len - packet->offset,這個值是有問題的,分兩種情況。第一種情況是projected_offset小于partial_packet->len,packet->len - packet->offset為L2CAP數據包片段總長度,并且是個正數。第二種是行211的情況,packet->len已經被修正過,不需要再一次packet->len - packet->offset的操作,如果partial_packet剩余空間長度小于4字節,那packet->len - packet->offset 是小于零的,是一個負數。由于memcpy()函數第三個參數類型是一個無符號整型類型,因此整數溢出導致堆溢出。漏洞補丁如下:
可以看到,補丁代碼中將packet->len加上了一個packet->offset,用于后面抵消減packet->offset的操作。
四、影響版本
Android Oreo(8.0和8.1)
Android Pie(9)
Android 10
五、安全建議
盡快更新最新的Android安全補丁
僅在絕對必要時啟用藍牙
保持藍牙設備不可發現
參考信息:
1.https://insinuator.net/2020/02/critical-bluetooth-vulnerability-in-android-cve-2020-0022/
2.https://akhozo.blogspot.com/2020/02/critical-android-bluetooth-flaw-cve.html?spref=tw
3.https://android.googlesource.com/platform/system/bt/+/3cb7149d8fed2d7d77ceaa95bf845224c4db3baf%5E%21/#F0
4.https://source.android.com/security/bulletin/2020-02-01.html
5.http://androidxref.com/8.1.0_r33/xref/system/bt/hci/src/packet_fragmenter.cc
6.Bluetooth_Core_v4.2藍牙官方文檔