蓝牙安全与攻击案例分析

本文是 2020 年中旬对于蓝牙技术栈安全研究的笔记,主要针对传统蓝牙和低功耗蓝牙在协议层和软件安全性上攻击面分析,并介绍了一些影响较大的蓝牙漏洞原理,比如协议层的 KNOB、BIAS 漏洞,软件实现上的 BlueBorne、SweynTooth 以及 BlueFrag 漏洞等。

前言

蓝牙(Bluetooth)是一个短距离无线传输的技术,工作在免证的ISM频段。最初名字为Wibree,在90年代由Nokia设计开发,随后转交给蓝牙特别兴趣小组(SIG)专门维护。

sig

蓝牙标准经过了数十年不愠不火的发展,核心版本从1.0迭代了到目前的5.2,其中在2010年推出的蓝牙4.0版本标准中引进了Bluetooth Smart或者Buletooth Low Energy(BLE)。由于在功耗上有了极大改善,加上智能手机和智能设备的发展,BLE的应用也进入了爆发期。

4.0之前蓝牙通常称为经典蓝牙(Classic Bluetooth),包括1.0提出的BR(Basic Rate,基础速率)以及2.0提出的EDR(Enhanced Data Rate,增强数据速率),两者往往放在一起表示与低功耗蓝牙相对的传统蓝牙。BR/EDR常用于相对短距离无线的连续连接,比如耳机的音频传输。

为了进一步提高蓝牙传输速率,在3.0中又提出了基于802.11的AMP(Alternate MAC and PHY layer extension)拓展,这是和BR/EDR不并存的一种传输模式。

核心系统

BR/EDR和BLE虽然都称为蓝牙,但它们在实现上大相径庭。前者主要侧重于点对点的通信,连接性和传输速率是考虑的重点;而BLE则侧重于低功耗的设计,在射频层和基带层上优化了多播和广播的支持。传统上Controller芯片只支持一种射频模式,但越来越多设备中也同时支持两种系统,以覆盖尽量多的使用场景。

framework

蓝牙的核心系统架构包含一个Host和一个或多个Controller,Host可以理解为主核或者主板,运行主流的富操作系统;而Controller可以看做是蓝牙芯片,运行的是裸机程序或者RTOS,主要功能是对射频信号进行编解码。Host和Controller之间通过HCI接口(Host Controller Interface)进行通信,可通过UART、USB等物理接口进行传输。核心系统中包含的组件和之间的关系如下图所示:

core
Core_v5.2 Vol 1: Architecture, Mixing, and Conventions. Part A: Architecture

其中Host部分主要是基于L2CAP抽象出的逻辑信道实现应用层的协议和功能,涉及的关键组件和协议有:

  • Channel Manager:负责创建、管理和释放L2CAP channel。
  • L2CAP Resource Manager:负责管理PDU数据的顺序、调度、分片、重组等功能,是L2CAP核心功能的一部分。
  • SMP:Security Manager Protocol,实现BLE系统中的点对点安全认证功能,包括秘钥生成和认证等;BR/EDR系统的对应功能则在Controller的Link Manager中实现。
  • ATT:Atrribute Protocol,应用层attribute client和server之间的协议。
  • GATT:Generic Attribute Profile,表示ATT server或者client的功能,profile描述了服务和属性的层级结构,主要用于LE profile服务发现中。
  • GAP:Generic Access Profile,表示所有蓝牙设备通用的基础功能,比如传输层、协议、应用所使用的模式或流程等。GAP服务包括设备和服务发现、连接模式、安全认证和关联模型等。

Controller部分中更多是逻辑链路和物理链路的管理,包括:

  • Device Manager:基带(baseband)中控制设备行为的模块,主要负责不与传输直接相关的部分,比如查询周围蓝牙设备,连接蓝牙设备,切换蓝牙设备的状态(discoverable/connectable),以及修改蓝牙名称、属性等。
  • Link Manager:负责创建、修改和释放逻辑链路(logical links)以及对应的逻辑传输(logical transports),并更新设备之间对应物理链路(physical links)的相关参数。在BR/EDR系统中,与对端的Link Manager通过LMP协议(Link Manager Protocol)进行通信;在BLE系统中则使用的是LL协议(Link Layer Protocol)。
  • Baseband Resource Manager:负责管理所有到射频媒介的访问。在链路层中,有两种类型的“连接”:
    • SCO:Synchronous Connection Orientated,实时窄带数据传输,如电话音频等,无重传
    • ACL:Asynchronous Connection-Less,异步无连接,用以其他所有数据的传输
  • Link Controller:负责对指定物理信道(逻辑链路和逻辑传输)的蓝牙数据进行编解码。

蓝牙核心系统的每个组件或协议都可以用独立的章节去介绍,整个结构的宏观理解对后面梳理蓝牙的攻击面是非常有必要的。从前面的图中我们可以看到,BR/EDR和BLE在链路层以下是相当不同的,前者为LM而后者为LL,下面分别进行介绍。

在传统蓝牙(即BR/EDR)中,2.4GHz的ISM频段分成79个频段,每个大小为1MHz,并使用特定的跳频模式(Hopping Pattern)来决定一条物理信道,从而减少不同临近终端之间的射频干扰。BR/EDR使用点对点的主从模式,其中Master为确定跳频模式的一方,Slave为与Master时钟和跳频模式同步的其他端点。

传统蓝牙建立链路层连接主要经历两个阶段:Inquiry和Paging。

Inquiry阶段,Master发送查询请求,周围(10米内)可被发现的设备(discoverable)收到请求后会发送查询响应(Inquiry Response)。在查询过程中,因为与周围设备还未连接,因此它们很可能处于不同的信道(跳频序列),实际上发送查询的设备会在不同的频率进行发送,而接收方(处于standby模式)则以更高地频率进行足够长时间的查询扫描(Inquiry Scan)以确保能被正确唤起。查询响应中包含设备ID和时钟等信息。

Paging阶段,主要解决的是链路层的连接问题。与Inquiry类似,此时各方同样没有进行时钟和频率的同步。Master与Slave的连接需要经过以下六步:

paging

连接状态的两个设备所处于的抽象网络称为piconet,这是一个星状网络,一个Master可以有最多七个Slave,但是Master本身也可以是其他piconet的Slave,这种网络拓扑称为scatternet。传统蓝牙处理链路层连接的管理器称为LM,即Link Manager,两个LM之间通过LMP协议进行通信。

这只是链路层的连接,和我们平常所说的蓝牙配对(pairing)并不是一回事。Paging只是保证了在物理层链路的连通性,进行应用层的通信往往还需要经历两步:

  • 服务发现(Service Discovery):用以确认对端所支持的服务
  • 服务连接(Service Connection):使用某个对端设备特定的服务或者配置(Profile)

但是实际上在服务发现之前,蓝牙引入了一层安全性保障,确保双方是自愿连接的,沟通连接意愿的过程就称为配对。经过配对后的设备会分别记住对方,在下一次连接时就不需要进行重新配对,而是使用之前保存的连接秘钥(Link Key)直接进行认证和连接:

LM

蓝牙Spec中定义了legacy authenticationsecure authentication情况下的认证流程和状态。当两个设备没有共同的link key时,就需要使用pairing流程来协商创建初始化秘钥Kinit。 关于配对流程的分析在后面会详细介绍。

在BLE中,2.4GHz的ISM频段分成40个频段,每个大小为2MHz,其中3个信道为广播信道(advertising channel),其余37个为通用信道(general purpose channel)。BLE也支持对建立连接后的端点在通用信道中进行跳频通信。

各个信道的频率为: f = 2402 + k * 2 MHz, k = 0, 1, ... , 39

BLE链路层的状态机包括以下状态:

  • Standby State
  • Advertising State
  • Scanning State
  • Initiating State
  • Connection State
  • Synchronization State
  • Isochronous Broadcasting State

任一时刻只能处于其中的一种状态,有限状态机的转换过程如下:

FSM

实际中的链路层的状态机不一定要实现上述完整的状态,但蓝牙标准中定义了一些相互依赖的状态组合,实现了其中一种就必须要实现另外一种。任何其他状态都可以直接进入Standby状态,而只有Advertising和Initiating状态才能进入Connection状态。Connection状态中连接的双方分别根据来源状态定义为:

  • Master Role:从Initiating状态进入
  • Slave Role:从Advertising状态进入

与传统蓝牙类似,一个Slave只能与一个Master进行连接。在BLE中,链路层数据包所包含的数据称为协议数据单元(PDU),Advertising的三个物理信道包含Advertising PDU、Scanning PDU和Initiating PDU,数据信道包含LL Data PDU和LL Control PDU等,不同的PDU包含不同类型的Payload。当然这都是发生在双方Controller端的LL之间,Host端还是主要使用HCI协议对其进行封装,根据不同的场景我们可能需要专注某一端的的实现,比如对于蓝牙芯片固件的研究更多是对LL端的数据进行分析,其他情况下对于应用层或者开发者则更多地关注Host端的HCI、L2CAP、ATT等协议。

蓝牙的服务发现和调用不考虑安全性的话可以直接在同步完物理信道后直接进行应用层交互,但为了避免窃听和中间人等攻击,甚至是为了避免错误连接到其他同名设备,蓝牙服务也是必须要有安全性保障的。初次接触蓝牙Spec的人可能会对蓝牙连接和配对的概念比较困惑,因为蓝牙标准在不同版本中定义了不同的配对模型,而BR/EDR和BLE的配对过程又发生在不同的模块中。比如BR/EDR配对过程由双方Controller端的LM(Link Manager)使用LMP协议进行协商,而BLE的配对过程则主要通过Host端的协议栈(Security Manager)进行协商。

从时间线上来看,BR/EDR分为几个阶段:

  • 2.1之前:使用Legacy Pairing,后续版本中称为BR/EDR legacy
  • 2.1:使用 Secure Simple Pairing
  • 4.2:使用 Secure Connection

BLE也经历了几个阶段的变化:

  • 4.0和4.1:使用 Secure Simple Pairing,后续版本中称为BLE legacy
  • 4.2:使用 Secure Connection

Legacy Pairing 使用双方输入或者固定的PIN CODE来进行认证,现在已经非常少见,因此可以不用关注。

Secure Simple Pairing 的配对方式主要经过以下4步(以BR/EDR为例):

  1. IO capabilities exchange:交换对方的特性,比如是否支持显示和键盘输入等,用以后续协商认证手段
  2. Public key exchange:交换椭圆曲线的公钥
  3. Authentication stage 1:身份认证
  4. Authentication stage 2:ECDH Key校验

对于身份认证,BR/EDR定义了4种认证方式:

  • Just Works:静默认证,主要用于没有显示和输入功能的设备,如耳机等
  • Numeric Comparison:双方生成随机数并计算出一个6位数字进行比对确认
  • Passkey Entry Authentication:主要用于一方有显示功能另外一方有输入功能的场景
  • OOB(Out Of Band):使用蓝牙射频以外的其他通道(如NFC)来交换认证信息

前面说了BR/EDR 2.1和BLE4.0/4.1都使用Secure Simple Pairing进行配对,为什么还特地强调是BR/EDR呢?因为虽然他们都叫做SSP,但实际上也存在不同的地方,比如BLE的SSP没有使用ECDH,因此数字的认证只能防止被动窃听(passive eavesdropping),不能防止中间人攻击,并且BLE中没有Numeric Comparison的认证方式。

不过,这也只是过去式了。在4.2以后,BLE和BR/EDR终于统一了配对流程,称为Secure Connection。其在SSP的基础上进行了安全性的增强,下面是BR/EDR的对比:

安全特性\配对类型 Legacy Secure Simple Pairing Secure Connection
加密 E0 E0 AES-CCM
认证 SAFER+ SAFER+ HMAC-SHA256
秘钥生成 SAFER+ P-192 ECDH HMAC-SHA-256 P-256 ECDH HMAC-SHA-256

而BLE也是殊途同归,最新实现的配对方式也升级成了功能相同的 Secure Connection。

常见协议

在前面的介绍中我们已经多次提到,主机系统称为Host,蓝牙射频芯片的系统称为Controller,它们之间的通信接口称为HCI(Host Controller Interface),同时这也是其传输协议的名字。HCI是Host端所能接触的最底层协议,通过内核的HCI驱动进行操作,基于HCI逐步往上封装和实现了一系列高级协议,本节就以自底向上的角度去进行介绍。

HCI协议是HCI接口最底层的协议,可根据传输层的介质分为不同类型,例如:

  • UART传输层:在btsnoop中表示为hci_h4
  • USB传输层:在btsnoop中表示为hci_h5
  • SD传输层:Secure Digital

HCI数据包分为command、event和data三种类型。command表示Host发送给Controller的命令,event为Controller发送给Host的事件,data通常是实际的蓝牙传输数据。

See: https://software-dl.ti.com/simplelink/esd/simplelink_cc13x2_sdk/1.60.00.29_new/exports/docs/ble5stack/vendor_specific_guide/BLE_Vendor_Specific_HCI_Guide/hci_interface.html

HCI command的格式为:

16bit opcode | 8bit 参数长度 | 可变参数

其中opcode又分为两部分,高6位为OGF(Opcode Group Field),低10位为OCF(Opcode Command Field)。在Linuz中我们常用的bluez框架也可以直接发送hci命令:

$ hcitool cmd --help
Usage:
        cmd <ogf> <ocf> [parameters]
Example:
        cmd 0x03 0x0013 0x41 0x42 0x43 0x44

HCI event的格式为:

8bit event code | 8bit 参数长度 | 可变参数

通常Host发送的command都会收到Controller的返回event,提示命令的执行结果。例如,HCI命令0x200c表示LE Set Scan Enable,并通过参数控制开启和关闭BLE的扫描,Controller执行完毕后返回event code 0x0e,即Command Complete,并附带status作为参数表示结果是否成功。详细的命令和事件列表可以参考Core_v5.2 Vol 4: Host Controller Interface, Part E-7 HCI commands and events

除了command和event,HCI中还包括的一大载荷就是数据,比如前面提到的同步数据包SCO、ISO(isochronous)和无连接数据包ACL等。

HCI的ACL协议主要用于在Host和Controller之间传输数据,ACL数据包的格式如下:

12bit   | 2bit    | 2bit    | 16bit             | varlen
Handle 	| PB flag | BC flag | Data Total Length | data

其中,Handle用于区分Host与Controller之间的逻辑链路,PB为Packet Boundary即包边界标志,BC(Broadcast)为广播标志。由于数据总长度只用2个字节表示,因此数据加上头部最多也只有65535字节,这意味着在发送过大的数据时需要在ACL层进行分包和重组,PB Flag就是为了这个目的而设置的,根据PB Flag的值可以表示当前数据包在完整数据中所处的位置。

ACL只提供了一个数据传输协议,类比于网络协议栈中的IP协议,在其之上使用的L2CAP协议可以类比于TCP/UDP协议,实现了更为完善的数据传输功能,包括:

  1. 协议/信道(L2CAP channel)多路复用
  2. 分段(segmentation)和重组(reassembly)
  3. 基于L2CAP channel的流量控制机制
  4. 错误控制重传机制
  5. 支持流式传输(streaming)
  6. 分片(fragmentation)和重组(recombination)
  7. QoS(Quality of Service)

L2CAP channel表示两个设备之间的一条逻辑链路,使用channel id(CID)进行区分,并以此为基本单元在Controller逻辑链路上进行多路复用。在基于连接的信道(connection-oriented channels)中,L2CAP PDU也称为B-Frame,其格式如下:

16bit length | 16bit CID | information payload

前32bit称为L2CAP header,length是除了header以外的payload长度。在不同的L2CAP模式中,information payload的内容也不尽相同,比如在Supervisor Frame(S-Frame)、Information Frame(I-Frame)。而对于无连接的L2CAP数据包,在payload之前还包含大于等于2字节的PSM(Protocol/Service Multiplexer),头部还是和B-Frame一致的。

在L2CAP之上,有着各种各样的应用层协议,比如服务发现协议SDP,蓝牙传输协议RFCOMM/OBEX,BLE的属性协议ATT,甚至是通用以太网协议BNEP以及其上的TCP/IP网络栈等。通过分层和抽象使得上层应用无需关心底层的细节,从而实现了整个蓝牙协议栈的普适性和拓展性。

协议安全

这里的协议安全不是指网络协议栈的安全性,而是蓝牙核心协议,或者说蓝牙标准本身的安全性。虽然蓝牙SIG小组在制定标准前都经过了多方讨论和研究,可依然可能存在一些没有考虑周到的临界情况。

KNOB Attack是2018年3月发现,并在同年10月报告给蓝牙SIG和CERT的一个通用协议漏洞。漏洞点主要出现在LMP协议的秘钥协商阶段,正常来说,两个蓝牙设备连接和配对的过程如下:

LMP

配对之后会先进行蓝牙秘钥协商,协商过程使用的是配对过程协商的ECDH临时秘钥以保证协商过程保密。协商过程使用LMP协议,在各自的Controller端实现:

controller

问题就出在LMP entropy(熵)协商的阶段,因为这部分的协商过程是没有经过ECDH秘钥保护的,所以就容易受到中间人攻击,恶意的攻击者可以将熵设置得尽可能小,从而可以在后面快速地爆破出Kc并实时解密蓝牙的传输数据。这也是为什么该攻击称为KNOB(Key Negotiation of Bluetooth) Attack的原因。

该漏洞的编号为CVE-2019-9506,由于是蓝牙核心协议中的设计漏洞,因此影响了大量的蓝牙设备,比如Broadcom、CYW、Apple、Snapdragon等蓝牙芯片。修复方法自然是对秘钥熵协商的过程进行加密,不过这个要等SIG更新进标准中,而标准的更新和推进又相对缓慢,因此很多蓝牙芯片厂商也各自更新了固件做简单的patch。该漏洞的直接危害就是导致蓝牙链路的中间人攻击,导致传输信息泄露或者劫持,实际攻击场景比如蓝牙键盘、蓝牙鼠标等应该是受影响比较大的。

参考资料:

BIAS全称为Bluetooth Impersonation Attacks,是2020年5月左右公开的另外一个蓝牙协议的漏洞,CERT编号为CVE-2020-10135。该漏洞实际上是一系列协议设计缺陷导致的认证错误,最终导致对未配对的设备进行连接(或者说伪造成已配对的设备)。

该漏洞主要是针对传统蓝牙(BR/EDR)的配对过程。前面已经说过,在蓝牙协议的发展中,安全配对主要分为三个阶段,即Legacy Pairing、SSP和Secure Connection。配对的作用是让从未见过的设备建立可信、安全的链路层链接,宏观来看就是我们常见的输入配对数字过程,微观上是协商了一个双方持有的长期秘钥LTK(Long Term Key,或者说链接秘钥LK(Link Key),LTK用来生成后续安全链接的会话秘钥(Session Key)。两个设备只用配对一次,但可使用保存的LTK进行多次安全连接。

在蓝牙连接的过程中,数据是不经过加密或者校验的。连接建立的主要作用是让两个设备交换它们公开的capability信息、互相校验对方的长期秘钥并计算会话秘钥。如果连接的设备支持Secure Connection,就使用安全连接方法建立链接,连接的过程使用AES-CCM经过加密和完整性保护;否则,就使用Legacy Secure Connection(简称为LSC),连接过程使用E0流加密方法进行加密,并按照对应的流程进行连接。安全连接的建立同样通过LMP协议进行。

之所以介绍这些背景,是因为漏洞的成因与背景相关性较大,在上面的基础上,BIAS漏洞可以描述为以下问题:

  1. LSC过程中master发起连接请求,slave返回自己的LTK认证响应,但master可以不进行校验,也就是说在LSC中对LTK的校验只是单向的,即master校验slave的LTK即可。因此在LSC中攻击者可以轻易伪造成master进行连接。

  2. 在LSC过程中,攻击者若想伪造成slave,则可以在收到master的连接请求后发起Role Switch角色互换请求,将自己变成master,从而在1的基础上伪造成Slave。

  3. 在Secure Connection的情况下,攻击者可以通过返回Secure Connection not Support来发起降级攻击,从而使用LSC进行后续连接,即回退到1/2的场景中进行对端伪造。

  4. 在Secure Connection的情况下,另一种攻击方法是反射攻击。即在收到Secure Connection的请求后发起Role Switch操作,并且伪造对端的认证请求,由于两端的LTK相同,因此对端可以返回合法的认证响应;之后再发起一次Role Switch,将合法的认证响应转发给对端,从而完成安全链接。

BIAS漏洞产生的根源是蓝牙协议中不严谨的定义,比如为了兼容性允许Secure Connection降级,并且Role Switch的设计完全没有考虑安全性,对其发起的时机不加判断导致被滥用。从漏洞危害来看,BIAS的直接影响是可以绕过了手动确认的配对认证与目标设备进行连接,一个典型的例子是可以伪造成目标电脑或手机曾经配对过的蓝牙耳机设备,并静默地与目标进行连接,从而实现间接控制扬声器和麦克风的效果。

参考资料:

上面介绍的只是两个比较知名的协议漏洞,类似的协议设计问题还有很多,比如《Breaking Secure Pairing of Bluetooth Low Energy Using Downgrade Attacks》中就介绍了一种针对SCO(Secure Connection Only)模式的降级攻击。实际上蓝牙核心协议的每次修订,都或多或少对以前版本的疏漏进行了修补。蓝牙协议上出现的安全问题往往影响广泛并且难以修复,因为SIG更新协议需要一定时间,从协议更新到各个厂商的实现和测试也旷日持久。通常这类问题出现后都是厂商自身根据自己的理解进行缓解性修补,这也另一方面影响了漏洞修复的质量。

实现安全

由于蓝牙协议是如此复杂,而且协议本身还随着时间的变迁而不断更新进化,这对于蓝牙的实现造成了巨大挑战。这要求蓝牙固件的开发者一方面要深入理解蓝牙协议的实现过程,另一方面也要对软件安全开发本身有一定认识。尤其是在Controller端,目前还没有一个公开的蓝牙参考实现,蓝牙芯片的内部代码都是各个厂商珍藏的intellectual property

蓝牙的协议本身都复杂到经常出现非预期的安全问题,那蓝牙的实现就更不用说了。从诺基亚时代开始,就出现过许多代码实现导致的蓝牙软件安全漏洞,比如BlueJack、BlueBugging、BlueBump、Bluesmack、SweynTooth、BlueBorne、BlueFrag等等,……下面挑选几个比较著名的漏洞进行分析。

BlueBorne是2017年左右公开的一组蓝牙漏洞,当年影响了多个平台和系统,甚至包括IoT设备如Amazon Echo和Google Home等。虽然时过境迁了,但也值得回顾一下。涉及到的漏洞如下:

  • CVE-2017-0781/CVE-2017-0782:Android中l2cap/bnep的内存破坏,可导致RCE
  • CVE-2017-0785:Android中SDP协议continuation请求偏移校验不当导致的信息泄露
  • CVE-2017-0783:Android中PANU交互不当导致的中间人攻击
  • CVE-2017-8628:Windows中蓝牙驱动实现不当导致的中间人攻击
  • CVE-2017-1000250:Linux BlueZ中SDP实现不当导致的信息泄露,与前面Android中的SDP漏洞原理类似
  • CVE-2017-1000251:Linux BlueZ中处理L2CAP配置响应不当导致的栈溢出,可进一步造成RCE
  • CVE-2017-14315:iOS中LEAP (Low Energy Audio Protocol)协议的堆溢出,可进一步造成RCE

印象中这是首次在蓝牙实现上批量公开的严重漏洞,在审计蓝牙协议实现时可以发现一些常见的错误模式,比如用户可控长度字段时导致的信息泄露和溢出,这些模式在不同平台的实现中可能都有类似的纰漏,因此所产生的安全问题在不同平台中的迁移性是比较高的。

参考资料:

SweynTooth漏洞也是一系列漏洞的集合,在2019年左右公开。虽然把它归类到实现安全中,但其中大部分漏洞的本质是各个厂商在实现蓝牙核心协议未定义行为时引发的异常。低功耗蓝牙BLE的消息交互流程如下图所示:

messages

从这个图中可以引申出许多有趣的问题,比如:”如果LL加密流程在配对的过程中发起会怎么样?“……直觉来看有可能会造成全零LTK的安装、秘钥大小溢出、公钥不合法等错误。但由于蓝牙核心协议中对这种情况没有明确说明,因此这类的错误处理就全由厂商安装自己的理解去实现了。

一个蓝牙产品在打上蓝牙Logo之前需要经过蓝牙的认证,进行一系列基线兼容性检查,但这个检查也不是面面俱到的。因此,有的即便蓝牙核心协议中有明确定义的行为,在实际测试中也会发现一些SoC厂商的实现不一致。比如,蓝牙核心协议中定义peripheral在同一个central-peripheral连接中应该只响应一次version request请求,但实际上Telink的设备会响应多次,这都是基线测试难以顾及到的地方。

作者也就是在测试这些Corner Case的情况下,发现了一系列Bug/漏洞,命名为SweynTooth,例如:

  • CVE-2019-16336, CVE-2019-17519:链路层Length字段溢出,导致DoS和潜在的RCE
  • CVE-2019-17061, CVE-2019-17060:链路层的LLID处理不当导致死锁
  • CVE-2019-17517:处理L2CAP包时对长度字段的校验错误导致内存越界拷贝
  • ….
  • CVE-2019-19194:Telink SMP的Secure Connection实现在配对过程中发起LE加密流程时会导致全零LTK的安装

加起来一共12个公开漏洞,不过利用场景都很有限,除了全零LTK漏洞外,大部分只能造成蓝牙芯片的固件崩溃重新启动或者死锁。不过,从这组漏洞中我们也能看到蓝牙固件的实现也是有不少问题的,蓝牙芯片固件的代码本身难以进行热更新,在一些特殊的HCI Event配合下,我们甚至可以从Controller中获取Host的命令执行权限。

BlueFrag是2020年2月在Android安全通告中披露的一个严重漏洞,影响蓝牙子系统可实现远程命令执行。该漏洞主要是在Android中的L2CAP层实现上,是由于L2CAP的分片和重组包长度计算出错导致的内存破坏。

漏洞修复如下:

diff --git a/hci/src/packet_fragmenter.cc b/hci/src/packet_fragmenter.cc
index 5036ed5..143fc23 100644
--- a/hci/src/packet_fragmenter.cc
+++ b/hci/src/packet_fragmenter.cc
@@ -221,7 +221,8 @@
                  "%s got packet which would exceed expected length of %d. "
                  "Truncating.",
                  __func__, partial_packet->len);
-        packet->len = partial_packet->len - partial_packet->offset;
+        packet->len =
+            (partial_packet->len - partial_packet->offset) + packet->offset;
         projected_offset = partial_packet->len;
       }

值得一提的是,这个漏洞本身会导致memcpy拷贝负数长度,正常情况下会一直拷贝直至触发非法内存空间,但在Android的libc实现上memcpy优化的实现会令拷贝前面的若干字节以及末尾的64字节退出,从而出现一个可控的内存越界读写,在此基础上可以进一步实现控制流劫持导致远程命令执行。 Android中L2CAP的实现在用户层中,称为BlueDroid,用户进程为com.android.bluetooth,因此执行命令后所获得的权限也是bluetooth权限。

参考资料:

应用安全

前面介绍的都是比较底层的协议,而在一般安全论坛和关于蓝牙安全的相关文章中介绍的通常更多是应用相关的安全,比如蓝牙智能门锁的重放、越权等问题。这部分协议的交互主要在LTK协商之后,基于会话秘钥加密的信道传输应用层信息,当然也可以是BLE中基于广播的通信。

在上层的通信中,一个重要的概念就是Profile,表示设备所支持功能的一种垂直切分。其中既包括所有设备都通用的如Generic Access Profile(GAP)Generic Attribute Profile(GATT),也包括基于特定用途的Profile如Proximity ProfileGlucose Profile等。Profile本质上定义了如何使用协议来实现某种通用或者特定的目的。

Profile的存在是蓝牙协议与众不同的一个地方,为什么会有这么多Profile,而不是像通用协议一样,定义好协议结构和字段,然后进行通用拓展呢?在《计算机网络》中有这么一段话:

真的有必要分清楚所有应用的细节,并且为每一种应用提供不同的协议栈吗?也许没有这个必要。但是,由于存在多个不同的工作组,他们分别负责设计标准的不同部分,因此,每个工作组都只关注特定的问题,从而形成了自己的Profile。你可以把这个看成是康威法则在起作用。或许蓝牙标准根本不用25个协议栈,两个就可以了,一个用于文件传输,另外一个用于流式实时通信。

可见SIG蓝牙特别兴趣小组各自为战是蓝牙Profile的形式发展至今的重要原因之一。

GATT定义了一个标准的数据模型与流程用以设备发现、读写和推送数据。一个GATT server中通常包含多个Service,而每个Service又可以包含多个Characteristic。每个Characteristic都有一个16位或者128位的UUID,并带有可选的数据描述Descriptor。Characteristic是GATT通信中最小的数据单元,封装了一个单一的数据点,其中可能包含一组相关的数据,比如加速传感器x/y/z轴的坐标数据。根据权限的不同,我们可以向Characteristic中读写数据。

举个例子,对于心率计而言,可能有一个Heart Rate Service,其中包括两个Characteristic,分别是HM(Heart Rate Measurement)和BSL(Body Sensor Location),前者还包含一个Descriptor,CCCD(Client Characteristic Configuration Descriptor),这是一个常见的descriptor,用来表示通知开关状态。

service
示例: 蓝牙的心跳服务结构

其中大部分常用的属性在蓝牙SIG文档中都定义了对应的UUID,当然也包括一部分Vendor Specific的UUID留给厂商自行去拓展和定义。

研究蓝牙应用安全的一个常用办法是在收发数据时候进行抓包,比如Android中支持在开发者模式中打开蓝牙日志,iOS支持使用XCode的拓展工具PacketLogger进行抓包。此外还可以通过对应用进行逆向或者动态追踪的方式来观察应用层的交互数据,从而挖掘背后存在的安全漏洞。由于这类问题与具体的产品和应用有关,这里就不举例说明了,感兴趣的朋友可以参考相关蓝牙应用设备的公开安全通告。

小结

从漏洞的影响面来看,协议类的蓝牙漏洞通常影响广泛且难以修复,因为需要修改协议并推进各个蓝牙厂商去进行重新实现和更新;从危害性来看,协议类的漏洞往往影响的是蓝牙信道的安全,在一般场景中危害相对有限;而实现类的漏洞通常导致内存破坏,被攻击者精心构造利用则可以造成整个系统的沦陷,一旦被利用就很可能是个严重的 RCE;应用类的漏洞通常是厂商的应用开发者所造成的疏忽,在某些情况下可导致智能设备被劫持控制,虽然修复较为容易,但这类漏洞频繁出现在不同的蓝牙应用中,因此其安全影响也是不可忽视的。