1.背景介绍蓝牙协议比WIFI(802.11)、传统TCP/IP协议等其他通信协议更为复杂,目前的蓝牙核心规范(5.3)高达3085页。蓝牙的复杂性使得对各种蓝牙协议的实现进行安全测试和审计相对困难,导致协议的实现和使用存在更多的安全漏洞。但另一方面,其复杂性也会要求研究人员或攻击者对漏洞挖掘具有相对较高的技术门槛,突破难度也会更大。图1蓝牙核心规范手册封面图2蓝牙协议栈的架构如图2所示,蓝牙协议栈主要分为两部分:Host和Controller。Host主要包括链路层以上的整个蓝牙协议栈,包括传输层L2CAP和其上方的各种应用层协议,是蓝牙协议栈的核心部分。Controller主要处理硬件驱动,处于最底层。本文主要关注Host层各协议的实现安全性。从Android系统的发展历史来看,其蓝牙协议栈一直是安全研究的重点对象。2017年,Armis安全团队宣布BlueBorne组合漏洞攻击链可以通过蓝牙对智能手机进行远程攻击,危害极大。2020年Android爆发BlueFrag漏洞,攻击者可通过该漏洞实现零交互的远程代码执行。OPPO琥珀实验室一直致力于参与维护整个安卓系统的生态安全,因此也对安卓蓝牙协议栈进行了深入的研究。到目前为止,我们已经向谷歌安卓安全团队报告了多个蓝牙协议栈实现安全漏洞。本次介绍我们团队发现的三个不同的Android蓝牙协议模块漏洞:CVE-2020-27024(SMP协议)、CVE-2021-0918(GATT协议)、CVE-2021-39805(L2CAP协议)。2.CVE-2020-270242.1SMP协议简介SMP(SecurityManageProtocol)安全管理协议定义了配对和密钥分发的过程,然后使用密钥对链路通信数据进行加密。SMP用于LE设备或蓝牙双模设备。如图3所示,SMP协议的工作流程大致分为几个阶段:Step1:featureexchangepairingfeatureexchange,即每个exchange支持哪些pairingfeatures,比如是否支持SecureConnection(安全连接),是否支持MITM,是否支持OOB(OutofBand:带外),以及它的输入输出能力(IO能力)等。Step2:密钥生成在这个阶段,双方会协商生成STK/LTK:LELegacypairing:生成ShortTermKey(短期密钥)。LESecureConnection:GenerateLongTermKey(长期密钥)。Step3:Keydistribution这个阶段会分发一些其他用途的key,比如IdentityResolvingKey(IRK),用于RandomAddress分析。在分发这些密钥时,这个阶段的链接必须被加密。如果不加密,密钥会直接泄露。用于加密的密钥是第二阶段生成的STK或LTK,或者双模直接共享BR/EDR配对生成的Key。Step4:链路加密使用STK/LTK密钥对整个蓝牙通信链路进行加密。SMP协议的整个配对过程如下图所示,其中配对发起方的角色是主设备类型(MASTER),接收方的角色是从设备类型(SLAVE)。图3SMP协议工作流程2.2漏洞分析CVE-2020-27024是SMP协议中的一个数组越界漏洞。SMP协议使用预定义的L2CAP_SMP_CID(0x06)、L2CAP_SMP_BR_CID(0x07)通道,位于L2CAP协议层之上。如图4所示,SMP协议栈smp_l2cap_if_init()函数负责注册SMP数据报文接收回调处理函数,分别是处理BLE蓝牙SMP报文的smp_data_received()函数和处理BR蓝牙的smp_br_data_received()函数SMP消息。图4Android蓝牙协议栈SMP协议初始化代码段BR蓝牙通信链路导入的SMP数据包会经过smp_br_data_received()函数处理【代码位于/system/bt/stack/smp/smp_l2c抄送]。当SMP协议栈收到对端发起的配对请求SMP数据包SMP_OPCODE_PAIRING_REQ(0x01)时,报文处理流程会到达下图5的代码段。图5smp_br_data_received()函数代码段smp_br_data_received()函数在处理时,调用了smp_br_state_machine_event()函数【代码位于/system/bt/stack/smp/smp_br_main.cc】。函数代码实现如图6所示。图6smp_br_state_machine_event()函数代码段首先,我们从图7中可以看出,全局变量smp_br_entry_table数组的SIZE其实是2。图7smp_br_entry_table数组定义来自图7中的代码段6、我们可以看到smp_br_state_machine_event()函数在第一次执行tSMP_BR_ENTRY_TBLentry_table=smp_br_entry_table[p_cb->role]语句时并没有对p_cb->role的最大值进行判断,而是判断p_cb->role的合法性取值后。当攻击者恶意导致p_cb->role的值大于2时,会在smp_br_state_machine_event()函数的entry_table赋值语句中导致内存OOB越界读异常。3、CVE-2021-09183.1GATT协议简介GATT是GenericAttributes的缩写,中文是通用属性,是蓝牙低功耗BLE设备之间通信的协议。GATT定义了一个多层数据结构,连接的低功耗蓝牙设备使用它进行通信。其定义的多层数据结构简单概括为服务(service)可以包含多个特征(characteristic),每个特征包含属性(properties)和值(value),还可以包含多个描述(descriptor)。GATT基于ATT协议(属性协议),主要用于发现、读写、通知和指示属性。图8GATT协议交互图在ATT层协议框架内,具有一组属性的设备称为服务器(Server),读写属性值的设备称为客户端(Client)。服务器和客户端通过ATTPDU进行交互;其中AttributeProtocolPDU报文格式如图4所示。9.其中,Opcode:操作码(消息类型,1字节大小);属性参数:ATT参数(可变长度);AuthenticationSignature:认证签名。图9属性协议PDU消息格式ATT消息有30多种,常见的消息类型包括表1中的6种,如下表所示。后面介绍的Android蓝牙协议栈GATT漏洞也存储在Notification消息类型处理函数代码中。表1属性协议PDU类型表PDU类型发送者描述信息Request/RequestClient客户端向服务器请求数据回复/ResponseServer服务器对上述请求的回复命令/CommandClient客户端向服务器发送命令-无回复通知/NotificationServer服务器对特征数值发起anotificationtotheclient-noreplyindication/IndicationServer服务端发送特征值指示给客户端确认/ConfirmationClient客户端响应指示存在内存OOB越界读写安全漏洞。蓝牙协议GATT报文数据核心处理函数位于gatt_data_process()函数[system\bt\stack\gatt\gatt_main.cc]。如图10所示,该函数通过op_code值类型判断来判断消息是来自客户端还是服务端,然后分别调用不同的函数处理接口gatt_server_handle_client_req和gatt_client_handle_server_rsp函数。图10gatt_data_process()代码段通过分析代码,我们发现可以通过精心构造操作码值(如GATT_HANDLE_VALUE_IND:0x1D、GATT_HANDLE_VALUE_NOTIF:0x1B、GATT_HANDLE_MULTI_VALUE_NOTIF:0x23)来控制对gatt_client_handle_server_rsp()函数的函数执行调用。其中,GATT_HANDLE_MULTI_VALUE_NOTIF的类型为后续触发漏洞的消息类型。图11gatt_client_handle_server_rsp()代码段最后gatt_client_handle_server_rsp()会调用gatt_process_notification()函数。漏洞代码为位于system/bt/stack/gatt/gatt_cl.cc文件中的gatt_process_notification()函数,负责解析处理接收到的gatt协议通知类型的通知消息。图12gatt_process_notification()代码段首先介绍Android蓝牙协议栈中常用的解析消息内容的宏定义:STREAM_TO_INT8(u8,p)从p指向的消息中读取1个字节,保存到一个u8类型的变量中其中,p指针加1;STREAM_TO_UINT16(u16,p)每次从p指向的消息中读取2个字节,保存在u16类型变量中,p指针加2。STREAM_TO_ARRAY(a,p,len)负责从p指向的消息内容中读取长度为len字节的数据,保存在数组变量a的空间中,并将len的长度加到p中指针。另外,tGATT_VALUE值变量类型的structure结构如图13所示。图13tGATT_VALUE结构我们可以看到,在gatt_process_notification()函数中,当op_code值为GATT_HANDLE_MULTI_VALUE_NOTIF时,可以通过消息中的length字段来控制value.len变量值。此时如果value.len长度大于实际数据长度len小于GATT_MAX_ATTR_LEN(固定值为600),下面这行代码STREAM_TO_ARRAY(value.value,p,value.len)会导致异常OOB越界读取的内存复制操作。如图14所示,当后续的gatt_process_notification函数循环解析消息中的多个通知消息时,会导致STREAM_TO_ARRAY(value.value,p,value.len)存在内存越界写的风险。图14gatt_process_notification()后续代码段4CVE-2021-398054.1L2CAP协议简介L2CAP(LogicalLinkControlandAdaptationProtocol)全称逻辑链路控制和适配协议,是蓝牙系统中的核心协议。L2CAP通过协议复用、分段和重组,向上层提供面向连接和无连接的数据服务。图15L2CAP协议交互图L2CAP是基于通道的概念。通道的每个端点称为通道标识符(CID)。CID在相同设备之间可以复用,但本地设备的CID不能复用。L2CAP基于分组,但也遵循信道传输的通信模型。对端设备上两个L2CAP实体之间传输的信令命令(SignalingCommands)是通过SignalingChannel传输的。对于ACL-U逻辑链路,应使用CID0x0001,对于LE-U,应使用CID0x0005。例如,L2CAPLESignalingChannel用于控制面向LE连接的数据通道,可以协商这些LE通道(LE-U)的特性变化。后面介绍的漏洞位于L2CAPLESignalingChannel信道信令中。处理代码。蓝牙规范定义的CID如图16所示。图16BLE通道CIDL2CAP包格式如下图所示。图17L2CAP包格式L2CAP信令包格式如下。图18L2CAP信令包格式4.2漏洞分析CVE-2021-39805是L2CAP协议中的数组越界读取漏洞。问题代码位于l2cap蓝牙协议栈system\bt\stack\l2cap\l2c_ble.cc文件中的l2cble_process_sig_cmd函数中。该函数主要负责解析处理LE的信令通道控制消息。图19l2cble_process_sig_cmd()代码段L2CAP层在处理基于信用的增强流控模式重配置回复(L2CAP_CMD_CREDIT_BASED_RECONFIG_RES,0x1A)消息时,没有判断包长,导致内存信息泄露。顾名思义,这个回复是响应重配置请求(request)消息,这个(request)请求是重新配置通道的MTU和MPS,其结构如图18所示。图19是回复响应消息。图20基于信用的增强流控模式的重配置请求图21基于信用的增强流控模式的重配置响应Android在2020年8月左右增加了对基于信用的增强流控模式的支持,漏洞代码从那时起就一直存在,如图在图22中。在这段代码段中,STREAM_TO_UINT16从回复报文中取出result字段的值,但是在取之前,此时并没有判断回复报文中是否没有冗余数据。所以如果一个responsepacket构造的很仔细,就会触发这个地方,导致OOBRead。并且分配的结果域后面会返回给发送者,造成内存信息的泄露。图22l2cble_process_sig_cmd()后续代码段5.总结与展望Android系统蓝牙协议栈的演进分为几个阶段。android最早使用的是Linux蓝牙协议栈BlueZ。从Android4.2开始,谷歌在Android源码中推出了与Broadcom共同开发的BlueDroid来替代BlueZ。目前Android使用的蓝牙协议栈版本叫做Fluoride,谷歌正在开发的下一代蓝牙协议栈叫做Gabeldorsh,使用Rust编程语言开发。目前,Fluoride蓝牙协议栈基本都是使用C/C++语言实现的。由于蓝牙报文的协议解析和处理涉及大量的内存操作,加之蓝牙协议的多样性和复杂性,以及历史上多家公司的代码融合等种种原因,已经暴露出很多严重的RCE漏洞安卓蓝牙协议栈。而Gabeldorsh可以利用Rust语言本身的特性来减少内存类漏洞的发生。因此,未来蓝牙协议栈的漏洞挖掘将重点关注逻辑漏洞,例如协议本身的逻辑问题、条件竞争、设计缺陷等,这就需要该领域的漏洞挖掘研究人员拥有更深层次的蓝牙技术。知识栈,漏洞挖掘的技术门槛会更高,需要攻克的困难也会更多。6.参考链接《Bluetooth核心规范》: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/公告/2022-04-01
