7.4 服务的枚举

“服务发现协议”是一个由“蓝牙技术联盟”定义的一个蓝牙协议。该协议用于识别或公布某个蓝牙设备上所有可用的服务。“服务发现协议”的创建,主要是满足蓝牙网络中的一些独特需求,比如枚举出远程蓝牙设备上的服务的“功能”(function)、“类型”(class),或者其他属性,例如一些操作功能,还有一些“私人的配置”(profile)。当一个蓝牙服务的开发者在设备上实现蓝牙栈(Bluetooth stack)的时候,他必须挑选出哪些服务可以告诉远端蓝牙设备,并能够通过“服务发现协议”识别出这些服务。而从攻击者角度来说,“服务发现协议”可以允许你识别并确认远端“蓝牙主机”上可能的服务,还可以看到不同的蓝牙“私人配置”文件。而这些配置文件的内容,正是需要连接到服务上所需要的详细信息。

使用sdptool工具枚举蓝牙上的所有服务

前面我们已经介绍了几个“主动式发现”的工具。这些工具都可以枚举和显示最基本的“服务发现协议”记录信息。这些工具使用起来很方便,但是在以下几个方面都存在局限性。

·这些工具只能用来攻击“可发现的”模式的“蓝牙主机”,对于通过其他方式识别出的“非可发现的”模式下的“蓝牙主机”,则不能显示“服务发现协议”信息。

·这些工具对“服务发现协议”记录数据,通常是汇总成主要的“私人配置”格式,在内容显示上,没有连接到该“蓝牙主机”所需的必要细节。

·这些工具在枚举服务时可能会忽略那些可以使用但未在目标设备上进行声明的服务。

而Linux上的sdptool命令则可以让你列举出目标蓝牙设备上的所有服务。这个工具没有图形化界面,并且该工具显示的结果看上去很生硬,看着吃力,但是它却是在蓝牙“服务发现”方面,可用的工具中综合指数最好的一款。在本例中,我们使用sdptool来识别一台名为“MacBook Air”的笔记本电脑,这台电脑运行在OS X 10.9.1“冲浪湾”版上,看看它的“传统蓝牙”适配器上的所有服务信息。

在这个输出中,你可以看到OS X笔记本电脑运行了五个服务:

·“A2DP音频源”服务 (A2DP Audio Source) 蓝牙设备使用“高级音频分发配置文件”(Advanced Audio Distribution Profile,A2DP)生成“流媒体音乐”(stream music)到A2DP的接收器上(比如蓝牙耳机)。

·目标设备的AVRCP控制服务 (AVRCP Target) 可以通过“音/视频远程控制协议”(Audio/Visual Remote Control Protocol,AVRCP)进行远程控制的蓝牙设备。

·蓝牙与PDA同步服务 (Bluetooth-PDA-Sync) 蓝牙设备通过“蓝牙与PDA同步服务”和手持设备进行数据交换。

·耳机音频网关 (Headset Audio Gateway) 蓝牙设备使用“耳机配置文件”(Headset Profile,HSP)服务作为网关,在设备和耳机之间,用于接收和发送音频。

·组间ad-hoc无线自组网络服务 (Group Ad-hoc Network Service) 蓝牙设备允许远端设备在连接网络的时候,使用“蓝牙网络封装协议”(Bluetooth Network Encapsulation Protocol,BNEP)。

从sdptool命令的输出,可以看到结果中为每个服务的配置文件都提供了额外的配置信息。下面让我们更详细地阅读输出内容中的每一个项。

“服务名称”(Service Name)和“服务描述”(Service Description)字段的内容是由编写服务程序的开发人员提供的。由于开发人员的个人因素,经常会看到多个“蓝牙主机”上,相似的服务,名称却出现很多不一致的现象。无论是“服务名称”,还是“服务描述”,其实都只是一个识别标志,只要用户想要查看某个“可发现的”模式蓝牙设备的信息,那么该用户的操作系统都会通过一个“可用服务列表”(list of available service)的形式把这些服务都列出来,并且大多数用户都可以直接在操作系统中看到它们。

“服务记录句柄”(Service RecHandle)表示的是“服务发现协议”服务记录的句柄(handle)。该句柄与这个服务关联,是一个32位的数字值,并且对于任何一个给定的“蓝牙主机”,该值都是唯一的,但对于不同的“蓝牙主机”,即使是相同的服务,也允许该值不同。通常情况下,每一个蓝牙在编程实现时都会使用一个特定的“服务记录句柄”记录特定的配置文件。例如Apple的OS X系统中蓝牙栈总是使用0x10006作为“A2DP音频源”服务的句柄。

随后的“服务类型ID列表”(Service Class ID List)字段,表示用于识别特定的蓝牙配置文件,这些文件就是为这个服务的实现而定制的。在这些例子中,“音频源”的配置定制文件主要是通过将一个数字的ID值分配给该配置文件,这个值是由“蓝牙技术联盟”分配的,可以确保数字的唯一性。并且该文件主要用于向“音频接收器”(Audio Sink)设备发送高质量的“音频流”内容。

提示

蓝牙定制配置文件信息的重要来源,是“蓝牙技术联盟开发者配置文件入门综览”(SIG Developer Portal Profiles Overview)页面,该页面的网址是http://en.wikipedia.org/wiki/Bluetooth_profile

网站

接下来的“协议描述列表”(Protocol Descriptor List)是用于支持所使用的配置文件。在上面的实例中,这些配置文件是通过“音频源”向蓝牙服务提供的配置文件。在本例中,“逻辑链路控制及适配协议”(Logical Link Control and Adaptation Protocol,L2CAP)实际使用的是“协议服务多开关选择器”(Protocol Service Multiplexer,PSM)协议,所用的端口值是25,该值相当于是蓝牙的端口值。还有“音/视频发分布式传送协议”(Audio/Video Distribution Transporc Protocol,AVDTP)。有关操作和使用“逻辑链路控制及适配协议”和“协议服务多开关选择器”这两个协议方面更详细的背景解释材料,可以参阅本书的配套网站http://www.hackingexposedwireless 下载。

对于一些配置文件来说,“语言基本属性列表”(Language Base Attr List)主要显示在服务实现的过程中,用于人可阅读的语言描述字段。对于我们来说最感兴趣的是code_ISO639字段,即ISO签署的639号规范,这个规范是用双字母表示某个国家或地区的语言名称。在本例中,0x656e是小写字母“en”的ASCII码值,在“ISO 639”规范中代表“英语”(即English的前两个字母)。通常情况下,在一台主机上所有的服务所使用的语言都是一样,这取决于你当初安装本地操作系统的时候所选的语言类型。如果你想尝试传送一个破解用的工具包,那么你需要指定用一个和远端主机系统上语音包相同的工具包,由此可见,这个字段的信息对于你选择合适的语言包(language pack)还是很有用的 [1]

提示

一份以十六进制方式表示双字母国家码的“ISO 639”规范文档修订版,可以从http://www.willhackforsushi.com/resources/iso639.txt [2] 上获得。

在前面的例子中,我们使用“sdptool browse 00:00:CE:E3:96:EB”命令通过“服务发现协议”读取了某个蓝牙设备的服务列表。虽然我们使用的“蓝牙设备地址”并不完整,但通过这个“模糊查询”的方式,对方“很好地”完成了“服务发现协议”的枚举操作,最终得到了完整的可用服务列表。然而,有一些“蓝牙主机”就不会这么友好地回复我们的枚举操作了,当我们如法炮制地向这些“蓝牙主机”发出枚举命令时,它们会尝试阻止向我们回复“服务发现协议”的信息。例如,当我们用同样的命令查询一个Pebble牌蓝牙智能手表的时候,其命令如下。

幸运的是,sdptool命令也设计了一组参数,即使目标蓝牙设备尝试隐藏可用的服务,该命令也能够拿到“服务发现协议”的服务枚举列表。其原理是,虽然该蓝牙设备不在对方要求服务枚举的时候提供服务列表,但是当对方明确提出要读取某一个指定服务的时候,这个蓝牙设备就不得不提供该服务的完整服务信息,否则,其他的蓝牙设备将无法与该蓝牙设备进行正常的通信。现在的问题是,怎么知道对方有哪些服务(因为这本来也就是我们要枚举的目的)?这就涉及一个“公共服务句柄基值”(common service-handle base value)的问题,如前所述,蓝牙服务中,每一个服务都有一个“服务记录句柄”,所有的“服务记录句柄”都是在“公共服务句柄基值”的基础上加一个数字。因此,我们可以基于这个“公共服务句柄基值”做出一个“可能存在服务”的列表值,sdptool命令会按照列表中的值,依次探测目标蓝牙设备上的服务,凡是该蓝牙设备上有的服务中,都如实回复,而该蓝牙设备上没有的服务,则不作回复,这等于间接地读到了所有的服务。要实现该命令,可以带上“records”参数后,通过sdptool命令实现。

注意

在编写本书的时候,sdptool工具的当前版本为“BlueZ 4.98”,如果要通过上面的方式进行“服务扫描”,会基于“公共服务句柄基值”向上累加384次,并分别使用每次新的“服务记录句柄”通过“sdptool records”进行读取操作。言下之意就是:如果某个蓝牙设备中的服务值在“公共服务句柄基值”~“‘公共服务句柄基值’+384”,那么该蓝牙设备上所有的服务都将被枚举出来;如果某一个服务的句柄超出了“‘公共服务句柄基值’+384”,则该程序将会漏掉该服务。实际中的蓝牙设备,很少能同时使用这么多服务的,因此,这个值在实践中,应该是足够了,毕竟盲目扩大该值所带的代价就是要花费更长的等待时间和更大概率上无功而返的结果。

提示

无论是“sdptool records”命令,还是“sdptool browse output”命令,其结果都是以“树型结构”(hierarchical tree format)显示的。这是其默认的显示形式,如上面的这些例子所示的效果。其实,还可以通过在上述两个命令中,在“records”和“browse”关键字后面,通过加上“--xml”参数,使得结果以XML的格式直接输出到另一个程序中,这样sdptool工具就可以和一些具有复杂分析机制的程序,通过标准数据编码格式,进行交互操作了。

服务枚举的防御措施

要防御服务的枚举,是一项困难的任务。蓝牙设备要在“射频通信协议”通过串口进行通信,要在“协议服务多开关选择器”协议中进行通信,以及要向对方提供“语言包”(language pack)信息,都需要将服务信息回复给查询方,所以完全杜绝服务枚举是不可能的。只不过,现在唯一可以考虑的是,只有与合法的对等蓝牙用户进行连接的时候,才会提供上述信息。

一个推荐的方法是将蓝牙设备设置成“非可发现的”模式。这样,攻击者在不能确定“蓝牙设备地址”的情况下,无法从目标设备获得“服务发现协议”记录。但是就像我们之前所看到的,如果一个攻击者使用了合适的攻击工具,那么这种方式只能使对方的服务发现变得更困难了一些,并不能从根本上阻止他们获得完整的“服务发现协议”服务列表。

防止“服务发现协议”信息泄漏的最好方法是在“蓝牙主机”中只打开那些需要用的服务。通过禁止掉不使用的服务配置文件,攻击者就只能获得更少的“服务发现协议”信息,从而减少了目标设备上可能被攻击的可能。考虑到有些“服务发现协议”服务是禁不掉的,但是这些服务确实又不需要运行,你可以配置蓝牙规则,使这些服务始终处于系统中最低的使用权限。总之,禁止所有你用不到的服务,对于禁不掉的服务,就将它们的权限降到最低。

不幸的是,上面这项技术通常都是不可能做到的,因为许多蓝牙设备都不允许终端用户指定支持哪些设备。在这些情况下,剩下的唯一防御方法就是知道你的蓝牙设备上服务信息是通过“服务发现协议”协议泄漏的。

[1] 对方的操作系统一旦选好语言类型,如果你上传的语言包与操作系统的语言包不同,则会产生乱码的现象。这个不仅与对方的语言有关,更重要的是所用的语言编码库是不是一样。如果一样,即使语言不一样,同样还是可以看的。比如英文版的Windows也是可以查看中文的信息。一般比较保险和通用的办法就是都只用英文ASCII编码库,基本上所有的操作系统都支持。——译者注

[2] 如果链接无法访问,可以从http://userpage.chemie.fu-berlin.de/diverse/doc/ISO_639.html获取。——译者注