本环境是蛇矛实验室基于"火天网演攻防演训靶场"进行搭建,通过火天网演中的环境构建模块,可以灵活的对目标网络进行设计和配置,结合虚实结合技术能够快速将wifi、蓝牙等进行接入并保证正常运行逻辑,从而可以快速进行场景搭建和复现验证工作。
背景
蓝牙技术始于爱立信公司的1994年方案,它是研究在移动电话和其他配件间进行低功耗、低成本无线通信连接的方法。发明者希望为设备间的通讯创造一组统一规则(标准化协议),以解决用户间互不兼容的移动电子设备。1997年前爱立信公司此概念接触了移动设备制造商,讨论其项目合作发展,结果获得支持。1998年项目正式启动。1998年5月,爱立信、诺基亚、东芝、IBM和英特尔公司等五家著名厂商, 在联合开展短程无线通信技术的标准化活动时提出了蓝牙技术,其宗旨是提供一种短距离、低成本的无线传输应用技术。这五家厂商还成立了蓝牙特别兴趣组,以使蓝牙技术能够成为未来的无线通信标准。芯片霸主Intel公司负责半导体芯片和传输软件的开发,爱立信负责无线射频和移动电话软件的开发,IBM和东芝负责笔记本电脑接口规格的开发。1999年下半年,著名的业界巨头微软、摩托罗拉、三康、朗讯与蓝牙特别小组的五家公司共同发起成立了蓝牙技术推广组织,从而在全球范围内掀起了一股“蓝牙”热潮。全球业界即将开发一大批蓝牙技术的应用产品,使蓝牙技术呈现出极其广阔的市场前景,并预示着21世纪初将迎来波澜壮阔的全球无线通信浪潮。
如对蓝牙基础有过了解,可以直接看第三章。
1.蓝牙基础
蓝牙出现的原因,是为了解决从有线数据传输到无线传输数据过程的问题。目前蓝牙的版本:1.1、1.2、2.0、2.1、3.0、4.0、4.1、4.2、5.0、5.1、5.2、5.3。蓝牙版本一直在更新,"<4.0" 的被称为经典蓝牙(Classic Bluetooth),">=4.0" 开始有了低功耗蓝牙(Bluetooth Low Energy,一般简写为BLE)。其实我们常说的蓝牙4.0并不等同于BLE,BLE只是蓝牙4.0的子集;蓝牙4.0是一个综合性协议规范。蓝牙4.0版本以后技术模式上分为低功耗蓝牙(BLE)和经典蓝牙(BR/EDR)两种、市场蓝牙产品大多数为仅支持BLE的,也有两者都支持的。蓝牙 4.0 的芯片模式分为 Single mode 与 Dual mode。Single mode 只能与蓝牙 4.0 互相传输无法向下与 3.0/2.1/2.0 版本兼容;Dual mode 可以向下兼容 3.0/2.1/2.0 版本。前者应用于使用纽扣电池的传感器设备,例如对功耗要求较高的心率检测器和温度计;后者应用于传统蓝牙设备,同时兼顾低功耗的需求。
-
Bluetooth :经典蓝牙 ,特点是耗电量大,传输距离近,速度一般,适合数据量大的传输。(相关设备:蓝牙耳机、蓝牙音响)
-
Bluetooth Smart :Single mode蓝牙只支持低功耗蓝牙,特点是耗电量小,传输距离远速度快,适合数据量小的传输。(相关设备:蓝牙锁、蓝牙灯泡、蓝牙手环)
-
Bluetooth Smart Ready:Dual mode蓝牙同时支持经典蓝牙和低功耗蓝牙。(相关设备:手机)
蓝牙5.0是由蓝牙技术联盟在2016年提出的蓝牙技术标准,蓝牙5.0针对低功耗设备速度有相应提升和优化,有着更广的覆盖范围和相较四倍的速度提升,同时还提供了基于AoA/AoD 等定位的功能,并且针对物联网进行了很多底层优化,让使用蓝牙做为标准的物联网应用更加强大。
BLE协议架构
要实现一个BLE应用,需要一个支持BLE射频的芯片,然后基于一个与芯片配套的协议栈,开发蓝牙应用。协议栈的作用就是软件和硬件之间的桥梁,对应用数据进行封包然后生成可以通过射频发送的空中数据包及其逆向过程。蓝牙协议将蓝牙整体分成了两层架构,底层是核心协议,描述了蓝牙核心技术的基础和规范,包括了Host和Controller。应用层协议则基于具体需求,使用核心协议提供的机制,实现不同的功能策略。这两部分在不同的蓝牙协议版本中略有区别,但大致上是,Controller完成硬件侧的规范制订,包括信号调制解调,会抽象出用于通信的逻辑链路,可能存在一个或多个,如LE Controller、BR/EDR Controller;Host则在逻辑链路的基础上完成更友好的封装,屏蔽掉技术细节,方便应用层对数据的使用。
BLE协议架构由下面几部分组成:
1.物理层(PHY):PHY层用来指定BLE所用的无线频段,调制解调方式和方法等。
2.链路层(LL):LL层是整个BLE协议栈的核心,要做的事情非常多,比如具体选择哪个射频通道进行通信,怎么识别空中数据包,具体在哪个时间点把数据包发送出去,怎么保证数据的完整性,ACK如何接收,如何进行重传,以及如何对链路进行管理和控制等等。LL层只负责把数据发出去或者收回来,对数据进行怎样的解析则交给上面的GAP或者GATT。
3.主机控制接口(HCI):HCI主要用于2颗芯片实现BLE协议栈的场合,用来规范两者之间的通信协议和通信命令等。这一层可以是软件或者硬件接口,如UART、SPI、USB等。
4.通用访问配置文件(GAP):GAP是对LL层payload(有效数据包)如何进行解析的两种方式中的一种,而且是最简单的那一种。GAP简单的对LL payload进行一些规范和定义,因此GAP能实现的功能极其有限。GAP目前主要用来进行广播,扫描和发起连接等。
5.逻辑链路控制级自适应协议(L2CAP):L2CAP对LL进行了一次简单封装,LL只关心传输的数据本身,L2CAP就要区分是加密通道还是普通通道,同时还要对连接间隔进行管理。
6.安全管理(SMP):SMP用来管理BLE连接的加密和安全的,如何保证连接的安全性,同时不影响用户的体验,这些都是SMP要考虑的工作。
7.属性协议(ATT):简单来说,ATT层用来定义用户命令及命令操作的数据,比如读取某个数据或者写某个数据。BLE协议栈中,开发者接触最多的就是ATT。BLE引入了attribute概念,用来描述一条一条的数据。Attribute除了定义数据,同时定义该数据可以使用的ATT命令,因此这一层被称为ATT层。
8.通用属性配置文件(GATT):GATT 是在 ATT 上面的一层结构,定义了使用 ATT的服务框架,GATT用来规范attribute中的数据内容,并运用group(分组)的概念对attribute进行分类管理,GATT规定配置文件(profile)的结构。没有GATT,BLE协议栈也能跑,但互联互通就会出问题,也正是因为有了GATT和各种各样的应用profile,BLE摆脱了ZigBee等无线协议的兼容性困境,成了出货量最大的2.4G无线通信产品。GATT定义了使用ATT的服务框架。在BLE中,所有被profile或者服务用到的数据块称为“特性”,两个建立连接的设备之间的所有数据通信都是通过GATT子程序处理。GATT层用于已连接的蓝牙设备之间的数据通信,应用程序和profile直接使用GATT层。当两个设备建立连接之后,它们就处于下面两种角色之一:GATT服务器:为GATT客户端提供数据服务的设备。GATT客户端:从GATT服务器读写应用数据的设备。
2.低功耗蓝牙工作流程
在BLE中存在两个角色,一个是中心角色(Central),一个是外围角色(Peripheral),蓝牙设备或手机都可以单独作为Central或Peripheral角色。外设角色的作用是为中心角色提供各种数据,中心角色可以扫描并接收多个外设角色数据( 外围角色中的设备进行广播,中心角色的设备扫描寻找广播),数据以服务(Service)和特性(Characteristic)的形式呈现。
蓝牙工作流程:蓝牙广播->扫描设备->设备配对->数据传输。
这里以智能手环为例,我们简单理解蓝牙的工作流程为:智能手环(外围设备)开启蓝牙后会进行广播,这时智能手环会在3个广播信道(37,38,39)上发送相同的广播报文,此时手机(中心设备)打开蓝牙后,手机中蓝牙适配器自带扫描器开始工作(扫描也在三个特定的广播信道进行),扫描器接收广播信道的报文后,发出扫描请求报文,智能手环发送扫描响应报文,这时手机就知道了发现了周边有一个智能手环设备。手机在点击连接智能手环时,发起连接请求报文,智能手环收到并处理后返回连接回应报文,此时俩者一旦连接建立之后,则开始使用数据报文(这里不理解也没关系,后面会讲解)。连接成功后,俩者开始通信,通信过程中手机发现蓝牙耳机存在某种服务,服务中存在一些特性如获取人体心率,这些特性允许手机通过特定的信道发出读、写等请求进行数据传输,上面过程中所有的数据传输均以无线的形式在空中传播。
如何通过无线发送蓝牙数据包
再理解蓝牙工作流程的细节前,我们先来看蓝牙无线通信是如何进行的。下面部分内容来自于该文章(https://www.cnblogs.com/schips/p/12293062.html),原理讲解比较通透,所以我拷贝了一部分。假设有设备A和设备B,设备A要把自己目前的电量状态83%(十六进制表示为0x53)发给设备B,该怎么做呢?作为一个开发者,他希望越简单越好,对他而言,他希望调用一个简单的API就能完成这件事,比如send(0x53),实际上我们的BLE协议栈就是这样设计的,开发者只需调用send(0x53)就可以把数据发送出去了,其余的事情BLE协议栈帮你搞定。很多人会想,BLE协议栈是不是直接在物理层就把0x53发出去,就如下图所示:
这种方式初看起来挺美的,但由于很多细节没有考虑到,实际是不可行的。首先,它没有考虑用哪一个射频信道来进行传输,在不更改API的情况下,我们只能对协议栈进行分层,为此引入LL层,开发者还是调用send(0x53),send(0x53)再调用send_LL(0x53,2402M)(注:2402M为信道频率)。这里还有一个问题,设备B怎么知道这个数据包是发给自己的还是其他人的,为此BLE引入access address概念,用来指明接收者身份,其中,0x8E89BED6这个access address比较特殊,它表示要发给周边所有设备,即广播。如果你要一对一的进行通信(BLE协议将其称为连接),即设备A的数据包只能设备B接收,同样设备B的数据包只能设备A接收,那么就必须生成一个独特的随机access address以标识设备A和设备B两者之间的连接。
广播方式
我们先来看一下简单的广播情况,这种情况下,我们把设备A叫advertiser(广播者),设备B叫scanner或者observer(扫描者)。广播状态下设备A的LL层API将变成send_LL(0x53,2402M, 0x8E89BED6)。由于设备B可以同时接收到很多设备的广播,因此数据包还必须包含设备A的device address(0xE1022AAB753B)以确认该广播包来自设备A,为此send_LL参数需要变成(0x53,2402M, 0x8E89BED6, 0xE1022AAB753B)。LL层还要检查数据的完整性,即数据在传输过程中有没有发生窜改,为此引入CRC24对数据包进行检验 (假设为0xB2C78E) 。同时为了调制解调电路工作更高效,每一个数据包的最前面会加上1个字节的preamble(前导帧),preamble一般为0x55或者0xAA。这样,整个空中包就变成(注:空中包用小端模式表示!):
上面这个数据包还有如下问题:
-
没有对数据包进行分类组织,设备B无法找到自己想要的数据0x53。为此我们需要在access address之后加入两个字段:LL header和长度字节。LL header用来表示数据包的LL类型,长度字节用来指明payload的长度
-
设备B什么时候开启射频窗口以接收空中数据包?如上图case1所示,当设备A的数据包在空中传输的时候,设备B把接收窗口关闭,此时通信将失败;同样对case2来说,当设备A没有在空中发送数据包时,设备B把接收窗口打开,此时通信也将失败。只有case3的情况,通信才能成功,即设备A的数据包在空中传输时,设备B正好打开射频接收窗口,此时通信才能成功,换句话说,LL层还必须定义通信时序。
-
当设备B拿到数据0x53后,该如何解析这个数据呢?它到底表示湿度还是电量,还是别的意思?这个就是GAP层要做的工作,GAP层引入了LTV(Length-Type-Value)结构来定义数据,比如020105,02-长度,01-类型(强制字段,表示广播flag,广播包必须包含该字段),05-值。由于广播包最大只能为31个字节,它能定义的数据类型极其有限,像这里说的电量,GAP就没有定义,因此要通过广播方式把电量数据发出去,只能使用供应商自定义数据类型0xFF,即04FF590053,其中04表示长度,FF表示数据类型(自定义数据),0x0059是供应商ID(自定义数据中的强制字段),0x53就是我们的数据(设备双方约定0x53就是表示电量,而不是其他意思)。
最终空中传输的数据包将变成:“AA D6BE898E 60 0E 3B75AB2A02E1 02010504FF5900 53 8EC7B2”
-
AA – 前导帧(preamble)
-
D6BE898E – 访问地址(access address)
-
60 – LL帧头字段(LL header)
-
0E – 有效数据包长度(payload length)
-
3B75AB2A02E1 – 广播者设备地址(advertiser address)
-
02010504FF590053 – 广播数据
-
8EC7B2 – CRC24值
有了PHY,LL和GAP,就可以发送广播包了,但广播包携带的信息极其有限,而且还有如下几大限制:
-
无法进行一对一双向通信 (广播是一对多通信,而且是单方向的通信)
-
由于不支持组包和拆包,因此无法传输大数据
-
通信不可靠及效率低下。广播信道不能太多,否则将导致扫描端效率低下。为此,BLE只使用37(2402MHz) /38(2426MHz) /39(2480MHz)三个信道进行广播和扫描,因此广播不支持跳频。由于广播是一对多的,所以广播也无法支持ACK。这些都使广播通信变得不可靠。
-
扫描端功耗高。由于扫描端不知道设备端何时广播,也不知道设备端选用哪个频道进行广播,扫描端只能拉长扫描窗口时间,并同时对37/38/39三个通道进行扫描,这样功耗就会比较高。
而连接则可以很好解决上述问题,下面我们就来看看连接是如何将0x53发送出去的。
连接方式
到底什么叫连接(connection)?像有线UART,很容易理解,就是用线(Rx和Tx等)把设备A和设备B相连,即为连接。用“线”把两个设备相连,实际是让2个设备有共同的通信媒介,并让两者时钟同步起来。蓝牙连接有何尝不是这个道理,所谓设备A和设备B建立蓝牙连接,就是指设备A和设备B两者一对一“同步”成功,其具体包含以下几方面:
-
设备A和设备B对接下来要使用的物理信道达成一致
-
设备A和设备B双方建立一个共同的时间锚点,也就是说,把双方的时间原点变成同一个点
-
设备A和设备B两者时钟同步成功,即双方都知道对方什么时候发送数据包什么时候接收数据包
-
连接成功后,设备A和设备B通信流程如下所示:
如上图所示,一旦设备A和设备B连接成功(此种情况下,我们把设备A称为Master或者Central,把设备B称为Slave或者Peripheral),设备A将周期性以CI(connection interval)为间隔向设备B发送数据包,而设备B也周期性地以CI为间隔打开射频接收窗口以接收设备A的数据包。同时按照蓝牙spec要求,设备B收到设备A数据包150us后,设备B切换到发送状态,把自己的数据发给设备A;设备A则切换到接收状态,接收设备B发过来的数据。由此可见,连接状态下,设备A和设备B的射频发送和接收窗口都是周期性地有计划地开和关,而且开的时间非常短,从而大大降低系统功耗并大大提高系统效率。
现在我们看看连接状态下是如何把数据0x53发送出去的,从中大家可以体会到蓝牙协议栈分层的妙处。
-
对开发者来说,很简单,他只需要调用send(0x53)
-
GATT层定义数据的类型和分组,方便起见,我们用0x0013表示电量这种数据类型,这样GATT层把数据打包成130053(小端模式!)
-
ATT层用来选择具体的通信命令,比如读/写/notify/indicate等,这里选择notify命令0x1B,这样数据包变成了:1B130053
-
L2CAP用来指定connection interval(连接间隔),比如每10ms同步一次(CI不体现在数据包中),同时指定逻辑通道编号0004(表示ATT命令),最后把ATT数据长度0x0004加在包头,这样数据就变为:040004001B130053
-
LL层要做的工作很多,首先LL层需要指定用哪个物理信道进行传输(物理信道不体现在数据包中),然后再给此连接分配一个Access address(0x50655DAB)以标识此连接只为设备A和设备B直连服务,然后加上LL header和payload length字段,LL header标识此packet为数据packet,而不是control packet等,payload length为整个L2CAP字段的长度,最后加上CRC24字段,以保证整个packet的数据完整性,所以数据包最后变成:
-
AA – 前导帧(preamble)
-
0x50655DAB – 访问地址(access address)
-
1E – LL帧头字段(LL header)
-
08 – 有效数据包长度(payload length)
-
04000400 – ATT数据长度,以及L2CAP通道编号
-
1B – notify command
-
0x0013 – 电量数据handle
-
0x53 – 真正要发送的电量数据
-
0xF650D5 – CRC24值
-
虽然开发者只调用了 send(0x53),但由于低功耗蓝牙协议栈层层打包,最后空中实际传输的数据将变成下图所示的模样,这就既满足了低功耗蓝牙通信的需求,又让用户API变得简单,可谓一箭双雕!
-
AAAB5D65501E08040004001B130053D550F6
-
在理解了上面的知识后,我们可以进行下面的内容了。
蓝牙广播
低功耗蓝牙一共有40个信道,频段范围从2402兆赫兹到2480兆赫兹,每两兆赫兹一个信道,其中37、38、39是广播信道,剩余的是数据信道。
蓝牙广播就是在这37,38,39三个信道上广播数据,一个广播数据包最长37个字节,其中有六个字节用作蓝牙设备的mac地址,剩余的31个字节又被分为若干个广播数据结构体,蓝牙规范里面称为ad structure。每一个广播数据结构体有三部分组成,分别是结构体长度类型和内容。其中长度占用1字节,类型1字节,和若干个字节内容。这里面长度等于一加N(内容字节数)。
下图中共有两个广播数据结构体,第一个广播数据结构体的长度为0x4,表示后面有四个字节属于这个结构体。紧接着是第二个广播数据结构体,长度为0x03,表示后面有三个字节属于这个结构体。上面提到了一个广播数据结构体最大可用的字节数为31个,如果没有用完的话,系统会在后面自动补零,凑够31个字节。
注意:蓝牙广播最多只能广播31个字节的数据,如果要广播的数据超过了31个字节,可以把一部分数据放到扫描响应里面。
上面提到了广播数据结构体组成方式,如果我们要想知道这些广播数据的具体含义,就必须知道每一个广播数据结构体的广播类型,广播类型蓝牙官网已经制定了详细的标准,我们可以在官网下载完整的AD type 进行查看。下图是几个比较常用的类型,比如009表示蓝牙设备的名称,0xa表示蓝牙设备的发射功率,0xff为厂商自定义类型。我们知道了广播数据结构体的类型,后面的数据内容是我们比较关注的,这些内容采用的是utf-8编码,所以可以传输中文。下图中的数据内容0x31 0x32 0x33 0x34 表示的字符串是"1234"。那么第一个广播结构体所表示的含义就是指定了蓝牙设备名称为1234,第二个广播数据结构体发射功率为8dbm。第三个广告数据结构体是厂商自定义数据,其数据内容的含义由厂商决定。
扫描与响应
蓝牙广播大致可以分为如下四类:
可连接非定向可连接
定向不可连接
非定向可扫描
非定向可连接
-
非定向是大部分普通的蓝牙设备采用的广播方式
-
可连接定向呢主要用于已配对设备中的快速连接
-
不可连接非定向是蓝牙信标或蓝牙传感器常用的广播方式
-
可扫描非对象是在不可连接非对象的基础上加入了扫描响应的功能,能够通过扫描响应来承载更多的数据
这个表格总结出了这几种广播类型的功能。蓝牙广播是蓝牙设备主动发射的一些数据,而扫描响应的是蓝牙从机收到蓝牙主机的扫描请求之后,回复给蓝牙主机的数据,扫描响应的数据格式和蓝牙广播的数据格式完全一样,不同的是广播数据是主动发射的,而扫描响应的数据呢是在收到其他设备的扫描请求之后才会触发的。
扫描响应数据和广播数据格式是一样的,扫描响应数据是非必需的,扫描响应数据可以作为广播数据的补充,扫描响应需要一定的触发条件。
服务与特性
以蓝牙鼠标为例,我们来看一下它的服务和特性是如何实现的,在手机上打开名叫谷雨蓝牙的微信小程序,搜索蓝牙鼠标后点击连接。连接成功后,展示的就是该设备的服务列表,一共有五个服务,每个服务上面的英文单词是服务的名称。
下面还有一行uuid,随便点开一个服务,展开是该服务里面的特性,每一个特性由特性名称,特性uuid和特性的访问权限组成。一个蓝牙设备里面可以包含若干个服务,一个服务里面包含若干个特性,每个特性里面又可以有读写通知等权限,每一个服务和特性都要有一个uuid。
uuid是蓝牙组织定义的用于区分各个服务和特性的标识符,用户可以自定义16 bit uuid,也可使用官方定义好的16bit uuid。uuid总长度是128bit,比如下面就是两个标准的uuid。但是蓝牙设计者考虑到128bit的uuid太长,使用起来不太方便。为了方便使用,蓝牙组织定义了一些16位的uuid的基地址,可以与16位uuid进行拼接,形成128bit的uid。
数据传输
上面我们学习了蓝牙服务和特性,我们知道了服务与特性。那么数据之间是怎么传输的呢,这里我们学习一下数据的传输,低功耗蓝牙通信是基于一个个特性实现的,每一个特性可以被看作一个数据点,数据的收发都要依托于这些数据点。对数据点的操作方法有如下常用的五种类型:
-
read
-
write
-
write with no response,
-
notify
-
indicate
这几种通信方式的区别,设备作为从机,手机作为主机
-
read操作,就是手机读取设备中某个特性的值。
-
write操作就是手机修改设备中某个特性的值。
-
write with no response,与write操作类似,只不过写完之后不需要设备回应,write操作则需要设备回应。
-
notify,操作是设备里面的数据发生变化之后,通知手机来取数据,需要在手机端订阅相应的通知才有效。
-
indicate与notify操作类似,不同之处在于,indicate需要手机回应,notify则不需要。
上面部分内容来自于课程(https://www.bilibili.com/video/BV1ad4y1d7AM/),如果大家感兴趣,可以前去学习。
3.蓝牙抓包分析
电脑抓包
这里以windows为例,我们作为初学者,一般使用CC2540/nrf52840 usb dongle来抓取蓝牙数据包,买板子后并且按照手册安装好环境后,更新驱动。利用平台USB设备接入模块接入蓝牙模块,并可连接对实物蓝牙手环进行测试
打开wireshark就可以看到nrf sniffer的接口后,我们直接双击就可以抓包了。
开启抓包后,使外围设备开启广播模式。等待外围设备广播包稳定后,点击wireshark 中 Device列表外围设备的mac地址,开启中心设备进行扫描和连接,就可以抓取俩个设备之间的通信包。
注意:下图中devcies下拉列表中没有鼠标的mac地址,说明并不能抓取设备连接后通信过程,但是这里还是可以分析一下广播和连接的过程。
广播包中PDU的类型如下:
0000 ADV_IND:可连接通用连接广播
0001 ADV_DIRECT_IND:可连接定向连接(指定设备)广播
0010 ADV_NONCONN_IND:不可连接通用广播
0011 SCAN_REQ:扫描请求
0100 SCAN_RSP:扫描响应
0101 CONNECT_REQ:连接请求
0110 ADV_SCAN_IND:可扫描通用广播
0111-1111 Reserved
位[4:5]:保留
位[6]:RxAdd
位[7]:TxAdd
位[8:13]:广播数据长度 (最大为37 字节)
位[14:15]:保留
BLE 连接过程中有三个重要的数据包:SCAN_REQ, SCAN_RSP 和 CONNECT_REQ(CONN_REQ又称为CONNECT_IND)。SCAN_REQ:扫描请求,由主设备向从设备发出,目的是为了获得从设备的响应以得到更多的从设备广播数据信息(包括设备名字,或者服务UUID,及其它如厂家特定格式的信息(如硬件版本,软件版本号,设备系列号等等)。
SCAN_RSP: 从设备对就主设备发起的SCAN_REQ的响应,作为广播包的补充,从设备可以给主设备更多的广播数据,比如说,有些设备在广播包里面没有设备名字,这个时候就可以把设备名字放在这个包里面发给主设备。
CONNECT_REQ(CONN_REQ又称为CONNECT_IND):主设备向从设备发出连接请求。至此连接建立完成(从设备不会响应这个请求),如果从设备没有连接上面的问题的话,以后主从双方会开始相互交换有效数据(基于GAP,GATT及SMP协议)或者交换空包。
BLE抽象出一个协议:Attribute protocol,该协议将这些“信息”以“Attribute(属性)”的形式抽象出来,并提供一些方法,供远端设备(remote device)读取、修改这些属性的值(Attribute value)。一般情况下,ATT 层用来定义用户命令及命令操作的数据,当我们想要给设备发送恶意报文,这些操作需要在ATT协议层完成,这里我们需要重点关注一下ATT报文。
下图中,实线包含的部分为ATT层。ATT报文由Attribute Opcode和Attribute Parameters组成。
ATT层是固定的CID,当L2CAP层的CID为0x4时,为ATT层。
ATT报文中的Opcode决定了后面的Parameters,例如后文中0x1b为Notify,那么后面的Parameters就为Attribute Handle和Attribute Value组成,我们在分析时需要重点关注Attribute Value的值。
上面在数据传输小节中已经讲解了Notify,Notify是当中心设备订阅从设备相应服务时,从设备里面的数据发生变化后,从设备通知中心设备来取数据。下图为opcode为Notification的ATT报文。
除了上述方法外,我们还可以使用蓝牙适配器(电脑自带也行)与蓝牙调试工具进行抓包分析,使用方法位正常连接蓝牙设备后,蓝牙启动调试工具就可以看到服务与特性,并且可以看到通信日志以及发送报文到设备。蓝牙调试工具比较多,这里不进行推荐,百度搜索下载就行。
Linux系统抓包与上面相同,大多采用适配器与调试工具组合进行抓包分析,bluetoothd、hcitool和gatttool都是比较好用的工具。
手机抓包
当我们想要抓取手机app与蓝牙设备的通信时,有时ble sniffer板子无法抓到通信包,那么就我们需要安装adb环境进行蓝牙调试,整个过程比较方便。
下面我以某智能手环为例,进行蓝牙抓包分析。windows安装好adb并配置环境后,下载adb驱动安装包,打开ADB Driver Installer程序,通过数据线将手机与电脑连接。手机开发者选项中打开usb调试,此时出现密钥并保存后,ADB Driver installer点击refresh就会出现手机设备。
打开android killer,点击android,在已找到的设备中选择手机设备后,点击日志即可查看Android设备日志信息。
点击开始进行日志记录,此时手机app绑定智能手环进行操作时,就会抓取到手机app的日志信息。
日志信息中,会包含蓝牙通信等信息,有助于帮助我们分析蓝牙通信流程。若此时出现有利于我们分析蓝牙流程的日志信息,我们可以通过有限的信息对app进行逆向分析,找出蓝牙实现的功能实现。
当Android killer日志信息不能获取到有效信息时,我们可以手机开发者选项中打开启用蓝牙HCI信息收集日志开关,设置完之后电脑adb连接手机,然后打开蓝牙设备和手机上和连接设备的APP,这个过程蓝牙设备和app间发送的数据包都会被记录下来。
收集完毕后,我们可以使用"adb pull /data/log/bt"将已收集的蓝牙日志文件保存到adb环境中的bt文件夹下。
使用wireshark分析日志文件,当使用手机app查看今日数据时,手环会发送总步数、心率、睡眠时间等信息给手机app。
当使用手机收到短信时,手环会进行提醒,此过程中app蓝牙数据包传入手环。
一个简单例子
上面我们讲解了低功耗蓝牙的基础知识和抓包技巧。这里做一个简单的攻击示例,目的是向手环发送信息使其显示。
首先是抓包分析,这里尝试使用nrf52840对其进行抓包,只能抓到广播通道报文,抓包无果。
然后尝试使用Android killer日志信息
根据其调试信息,尝试对手机app进行逆向分析,并没有找到发送信息相关的有效代码,分析无果。
最后,使用hci调试日志进行抓包,抓取其通信包裹。
获取log文件后,使用wireshark进行分析。发现当我们连接手环后的读取信息的操作与写入操作均在handle 0x11进行操作,返回handle位0x0e,并且wirte指令操作在uuid为0xff00的特性中,那么我们就明确了攻击的服务特性和handle。
重新使用hci调试日志进行抓包,这次抓包过程做了发送俩次信息的操作,手环并且成功显示。
第一次发送信息人为:pwn,信息为:111
第二次发送信息人为:pwn,信息为:222
分析时,我们重点关注write command,并且handle为0x11,找到了发送信息人前面的报文为0x0a020000020e
这里为发送提示信息人的报文
这里为发送信息内容的报文
这里为发送信息内容的报文的后一条报文
紧接着就是第二次发送信息人之间的一条报文
后面与第一次发送报文相同
那么我们就知道了,发送第一次信息和第二次信息都发送了4个报文,分别为信息推送报文,信息人报文,信息内容报文,结束推送报文。那么我们就可以在0xff02特性中进行write with no response操作,重放这些报文进行验证。
注意:中心设备与手环发送消息需要发送报文进行绑定,这里为了方便操作,这里我直接使用手机蓝牙调试工具进行发送。
验证成功后,后续当我们分析出每一条操控蓝牙设备的指令,就可以将想要发送的消息按照指定格式进行发送与BLE设备通讯,从而实现对蓝牙设备的攻击。
总结
这一小节,我们学习蓝牙无线通信的基础知识,以及对蓝牙智能手环的简单抓包分析和攻击,初步理解了低功耗蓝牙的内容。
蛇矛实验室成立于2020年,致力于安全研究、攻防解决方案、靶场对标场景仿真复现及技战法设计与输出等相关方向。团队核心成员均由从事安全行业10余年经验的安全专家组成,团队目前成员涉及红蓝对抗、渗透测试、逆向破解、病毒分析、工控安全以及免杀等相关领域。