导语:拦截BLE的通信 由于各种原因,在现实生活中,大多数BLE设备(包括智能锁)都还没有实现蓝牙链路层安全性的配对、绑定和加密,这就意味着BLE设备(包括智能锁)的通信协议是在未加密的BLE链路传输的。这使得蓝牙链路层上的数据包不但可以
拦截BLE的通信
由于各种原因,在现实生活中,大多数BLE设备(包括智能锁)都还没有实现蓝牙链路层安全性的配对、绑定和加密,这就意味着BLE设备(包括智能锁)的通信协议是在未加密的BLE链路传输的。这使得蓝牙链路层上的数据包不但可以轻易被拦截,而且还能利用它们实施攻击。
一般来说,拦截无线传输时首先想到的是利用专业的嗅探器,不过这不是我的首选方案,因为除了特殊硬件外,被动的嗅探并不是很可靠,通常都是杂乱的数据包,并且分析传输的数据(例如在Wireshark中)并不是很简单。
所以我利用了我自己开发的GATTacker来对无线传输信号进行捕捉,GATTacker是一种低功耗蓝牙中间人攻击代理工具。而GATTacker所需要的硬件配置也仅仅是价值5美元的Bluetooth 4.0适配器。
只需简单地输入scan命令,即可开始查询,如下所示,你会发现你附近的所有设备信息。
可以看出,信息很短,一般来说,BLE设备会通过不断广播的来证明它的存在。所以,如下所示,可以很容易发现了我所使用的一款智能锁,以及它所使用的mac地址和设备名称。接下来,就要对智能锁的服务特点进行扫描。
你可以简单地把BLE的服务特点想象成存储在设备中的一个简单的uid变量,可以进行读写。
在扫描后,模拟原始设备所需的所有数据都被存储为json文件。这样,我就可以准备启动拦截代理了。GATTacker将作为原始设备的软件仿真器,欺骗移动应用程序进行连接,然后将可交换的数据来回交换。在本文中,由于智能锁的移动应用程序会检查扫描设备的BT MAC地址,所以我必须欺骗它。
注意:大多数内置在笔记本电脑中的Bluetooth 4.0适配器是不允许更改MAC地址,所以我会使用一个CSR8510 USB加密狗,还有一个简单的脚本。
现在只需重新插入USB加密狗即可填充新的MAC地址,并启动中间人攻击代理了:
如果你看到紫色的“初始化”文本,则意味着中间人攻击代理已经正确建立了与原始设备的连接,启动软件设备仿真器,并准备拦截。
由下图可以看出,一旦攻击目标的移动应用程序连接到我的模拟设备,代理就会开始来回传送数据:
上图中的蓝色写入部分就是从移动应用程序发送到设备的数据,可以看出括号中的ascii值被解码,其中, ffe0 – > fff1是服务id。
通信以一些较长的二进制数据包开始,接下来会有几个相同的写入和读取过程,大约每秒一次。这些过程完成后,我通过点击移动应用程序中的“解锁”选项,就会得到一些各式各样的数据包。
明文登录
在上一部分中,你可能已经注意到了 “6666666”(十六进制编码为363636363636)不断在重复,其实,这就是设备的当前密码,且以明文形式发送。顺便说一句,你还可以使用Ubertooth进行远程嗅探。获得密码后,攻击者就可以很容易地实施攻击了,通过在他们自己的设备上输入其他人的登录凭证就可以完全控制智能锁了。
如果是这样的话,那本文就可以到此结束了。现在,让我假设密码不是以明文的方式进行传输,看看会发现什么。
重播
如上所述,最初移动应用程序很少与设备交换复杂的数据包。
每隔一段时间,数据都会有所不同。
与设备初始握手后,就可以发送命令了。在该设备的情况下,如果你尝试在连接时直接发送命令进行解锁,例如,a136363636363601,则无需事先握手。所以这种握手就是认证的一个形式。
你可以通过各种方式检查这个协议的细节,并进行反向操作,并理解来回发送的每个字节。你可能已经注意到重复的十六进制编码“741689”了,稍后我会对它进行详细解释。
以下是移动应用程序发送的第一个数据包(蓝色部分):
虽然开头部分相同,但结尾每次都不同。接下来,设备会对这些数据进行再次响应:
可以看出,反应取决于初始值:
这看起来像是一个简单的挑战响应方法,类似的方法在应用程序层非常常见,它是BLE设备的专有身份验证方式。在最流行的硬件模块中,只有简单的AES才有加密支持。因此,当一个开发人员试图提出自己的加密协议时,他通常会使用AES和静态的加密,在设备和移动应用程序之间共享一些东西。而对于那些复杂的部分,就像对于对称密码,共享和验证密码都会进行明文传输。由于没有公共密钥算法的支持,开发人员就只能想办法进行解决。
由上图可以看出,最初的挑战是由手机发送的,而不是智能锁设备。所以,如果设备仅基于挑战来计算响应,那对于相同的挑战,响应将始终是相同的。这就使得解决方案容易受到简单的重播攻击,攻击者在记录所交换的数据后,简单地进行重播,而不需要深入分析数据包:
于是,我尝试执行这个重播攻击,此时,GATTacker工具记录了转储子文件夹中的所有拦截数据,文件名只是设备的MAC地址,文件如下所示。
2017.10.24 10:50:54.531 | < C | ffe0 | fff1 | a137343136383905789a3b246c6c17164f0121 ( 741689 x ;$ll O !) 2017.10.24 10:50:54.702 | > R | ffe0 | fff1 | a20500f0c77f162e8bd21110841e641e641480 ( . d d ) 2017.10.24 10:50:54.980 | < C | ffe0 | fff1 | a137343136383909bcaafbae83b5babc02b8f7a0 ( 741689 ) 2017.10.24 10:50:55.156 | > R | ffe0 | fff1 | a20900 ( ) 2017.10.24 10:50:55.610 | < C | ffe0 | fff1 | a136363636363606 ( 666666 ) 2017.10.24 10:50:55.735 | > R | ffe0 | fff1 | a206002c010000 ( , ) 2017.10.24 10:50:56.645 | < C | ffe0 | fff1 | a136363636363606 ( 666666 ) 2017.10.24 10:50:56.769 | > R | ffe0 | fff1 | a206002c010000 ( , ) 2017.10.24 10:50:57.277 | < C | ffe0 | fff1 | a136363636363606 ( 666666 ) 2017.10.24 10:50:57.400 | > R | ffe0 | fff1 | a206002c010000 ( , ) 2017.10.24 10:50:57.951 | < C | ffe0 | fff1 | a136363636363601 ( 666666 ) 2017.10.24 10:50:58.076 | > R | ffe0 | fff1 | a20100 ( )
该文件的格式非常简单,“<C” 表示写入命令,“> R”表示设备的读取响应。接下来的运行都会尊徐这个特点,并以十六进制形式发送数据。括号中的时间戳和解码的ascii十六进制值仅供参考,不会被解释为重播。
如果要重播,只需使用此转储文件作为输入参数,来调用replay.js辅助脚本:
这样,智能锁设备就会被解锁。
你也可以使用你的手机实施同样的操作, nRF Connect应用程序有一个非常有趣的功能:macros。它可以提供特殊格式的XML输入文件,之后,nRF Connect就可以重播任何BLE通信序列,而我只需将GATTacker转储转换为nRF macro XML格式:
# node gattacker2nrf.js -i dump/f0c77f162e8b.log > dump/f0c77f162e8b.xml
你可以在点此查看生成的文件,并将文件导入nRF Connect。接下来,只需连接到设备,然后按重播按钮进行重播:
你可以稍后利用该技巧与你的设备进行交互,且无需任何其他硬件的支持,当然,你也可以根据你的需要修改XML输入文件。
不管哪种嗅探和重播攻击,都需要具备一个攻击条件:攻击者的嗅探或重播攻击的蓝牙范围必须覆盖受害者的解锁设备。同时,这也是许多用户懒得更改默认密码的原因,他们总以为他们的设备处于安全范围,无法被人嗅探到。
所以,我接下里,我会继续进行一个更有挑战性的攻击,即不需要事先嗅探就能发起攻击。
专用协议(proprietary protocol)
我将会用到这种专用通信协议,不过前提是逆向移动应用程序。
逆向移动应用(mobile application reverse)
关于逆向移动应用的教程,网上有很多,本文就不赘述了。基本上这些方法都依照获取应用程序的apk二进制文件,然后将其进行反编译,最后再检查java源代码的步骤进行的。大多数情况下,生成的反编译代码都是可读的。
可能打开的第一个类就是“SmartLock”:
我很确定SUPER_PASSWORD(上图右边第4行)引起了你的注意,它在移动应用中是硬编码的,所以很可能也嵌入到了硬件中。看到其中的 “741689”,你会想到什么呢?你是不是以为这是登录密码,那让我试试,看在初次握手中会发生什么?
简单的反编译源代码会允许你找到特定的代码片段,并告诉你这个握手过程是如何工作的:
一开始,移动应用程序会生成随机数据,并根据MsgRequestVerify格式将其附加到“741689”。在MsgRequestVerify类的源码中你还会发现以下代码段:
于是,我尝试将其与刚开始捕获数据包进行匹配:
如上图所示,我已经知道它已经嵌入了十六进制编码的SUPER_PASSWORD:
在经过多次的挑战之后,我已经可以指出随机数据了:
如果你还记得MsgRequestVerify通信格式,那应该能想起MSG_STX = 161;,在十六进制中,161的十进制值等于a1,这是数据包中的第一个字节,似乎是一个消息头。所以我有必要对另一部分数据包进行解码:
MsgRequestVerify再次出现MSG_CMD = 5,以下是是命令ID:
剩余的静态部分也在MsgRequestVerify类中定义:con1 = 120(在十六进制中为78),con2 = -102(在十六进制中为9a)。至此,我已经解码了整个数据包结构:
接下来,从设备接收到的数据包的验证就是基于简单的CRC:
这个挑战是根据该响应(mFirstReceiver)计算出移动应用程序发送的数据包:
事实证明,在某些情况下智能锁在质询响应中交换的数据是不需要密码的,仅仅使用静态硬编码的“SUPER_PASSWORD”就够了。这一方法适用于目前所有的智能锁,这意味着,它是一个严重的漏洞。但就如你在上文中了解的那样,我的设备实际上是按照以下命令发送密码的。不过,我不确定为什么要引入握手机制,可能只是为了“身份验证”(不管我们是否是合法使用)。
所以,让我来分析一下其他的命令,看看在最初的握手之后他们是怎么通过BLE发送给设备的。
协议命令( ProtocolCommand)
进一步浏览源代码,你会发现“message”子文件夹:
“MsgRequestLockInfo”的一个反编译片段:
我会再次尝试将其与GATTacker拦截的数据包进行匹配:
至此,我就知道了这个包的核心是十六进制编码的密码(在十六进制的ascii中为666666 = 363636363636):
你还应该识别MSG_STX(标头)和MSG_CMD(命令ID):
还记得解锁时发送的不同命令吗?它的结尾处是“01”而不是“06”。该命令和MsgRequestOpenLock类都匹配。
这样,你就完成了对专用协议的逆转。
“CANCER”攻击
虽然上面做了很多的工作,但我仍然在寻找一种不需要先前嗅探的攻击方法。
此时,我会用到SUPER_PASSWORD,它会在初始握手时使用。如果我直接在OpenLock命令中使用这个SUPER_PASSWORD,那只会对转储文件进行编辑,并且在初始握手后发送写入的a1 373431363839 01命令(OpenLock的标头+ SUPER_PASSWORD +命令ID),然后像之前那样进行重播:
2017.10.24 10:50:54.531 | < C | ffe0 | fff1 | a137343136383905789a3b246c6c17164f0121 ( 741689 x ;$ll O !) 2017.10.24 10:50:54.702 | > R | ffe0 | fff1 | a20500f0c77f162e8bd21110841e641e641480 ( . d d ) 2017.10.24 10:50:54.980 | < C | ffe0 | fff1 | a137343136383909bcaafbae83b5babc02b8f7a0 ( 741689 ) 2017.10.24 10:50:55.156 | > R | ffe0 | fff1 | a20900 ( ) 2017.10.24 10:50:55.610 | < C | ffe0 | fff1 | a137343136383901
不过这招显然不奏效,设备还是锁定的。
那除了上面的命令外,是否还有其他命令可以执行呢? 比如RequestAutoLock,RequestLock,RequestModifyName,RequestModifyPassword,RequestResetPassword,MsgRequestVibrate等,不过在测试后发现都不灵。这时,我发现了一个ModifyPassword (MSG_CMD = 7)命令,使用这条命令,截获的数据包中就会包含当前的密码以及新生成的密码:
不过要注意的是,在使用该命令后,你依然要使用当前的密码,如果只使用SUPER_PASSWORD则依然会不灵,因为智能锁会对该数据包进行验证。那么,让我再来试试ResetPassword命令吧,但我发现在官方移动应用的用户操作界面中,是没有密码重置操作的,不过这可难不倒我,因为我会将MSG_CMD值内置其中。
接着,我会把用于重播的输入文件进行重新修改,过程很简单,只需将OpenLock命令01更改为ResetPassword 08,不过此时,仍然使用的是“741689” – 373431363839 SUPER_PASSWORD):
(...) 2017.10.24 10:50:55.610 | < C | ffe0 | fff1 | a137343136383908
想不到,竟然成功了!智能锁现在的默认密码已经变成了为“123456”。接下来要做的就是修改脚本对智能锁实施最后的攻击,过程很简单就是在原来的脚本后加个 OpenLock命令,且使用默认密码(十六进制中为313233343536):
2017.10.24 10:50:54.531 | < C | ffe0 | fff1 | a137343136383905789a3b246c6c17164f0121 ( 741689 x ;$ll O !) 2017.10.24 10:50:54.702 | > R | ffe0 | fff1 | a20500f0c77f162e8bd21110841e641e641480 ( . d d ) 2017.10.24 10:50:54.980 | < C | ffe0 | fff1 | a137343136383909bcaafbae83b5babc02b8f7a0 ( 741689 ) 2017.10.24 10:50:55.156 | > R | ffe0 | fff1 | a20900 ( ) 2017.10.24 10:50:55.610 | < C | ffe0 | fff1 | a137343136383908 2017.10.24 10:50:55.610 | < C | ffe0 | fff1 | a131323334353601
详细解释如下所示:
首先脚本会重置智能锁的密码,然后自动打开智能锁。
当然,你也可以使用nRF Connect移动应用程序来执行此操作,关于它的操作,我已经在上文的重播攻击中进行了介绍。你可以点此直接获取转换好的XML宏文件。等以后你再进行解锁时,只需在你的手机上通过导入该XML宏文件,然后进行重播时,它就会自动运行了。
现在让我们把话题转回到“CANCER”攻击,在进行“CANCER”攻击时,如果密码被重置,则就会与移动应用程序中保存的默认密码不匹配,这时用户就会受到以下错误提示。
供应商的缓解措施
很明显,在这个攻击中,智能锁本身的漏洞攻击的关键。所以在确定了这个漏洞后,我就向相关的智能锁供应商提交了此漏洞。以下是一些厂商的回复,比如2017年3月的:
你好,我们已经确定了智能锁和移动应用程序中的这几个安全漏洞。现在我们已经将其分类为严重漏洞。
显然这是一个很负责人的回复,不过以下供应商的回复就显得很不负责任了,甚至有些令人气愤:
你好,我们已经修改你提交给我的漏洞,我们会继续改进我们的产品。
但当我重新对他们的产品进行测验时,发现他们的回复竟然是骗人的。
我也试图联系了Android手机应用开发者,不过大约3个月后,我才得到了回复,回复如下:
对不起,这个和本公司的业务不相关,所以我帮不到你。
所以看到这些回复,我就对官方的修复彻底失去了信心,以我的为例,我所使用的智能锁目前已经停产,就连其后台的密钥服务器也关闭了,所以为了不让我的智能锁失效,我试用了几个简单的技巧,详情请点此详细了解。
总结
使用手机攻击蓝牙智能锁设备总共经历了四个步骤:
1.拦截通信,
2.重播,
3.逆向专有协议,
4.在逆向协议中找到的漏洞。
当然这并不适用于所有的攻击情况,我会在未来的文章中进行详细分析。
看完这篇文章,你是不是觉得智能锁简直就是不堪一击,没有任何安全保护措施,恨不得要把你正在使用的给扔掉。其实真实的情况是,智能锁比大多数BLE设备都安全,比如BLE性玩具,、灯泡或传感器,这些才是真正的安全炸弹,因为它们几乎没有任何安全防护措施,甚至连最简单的静态明文密码的认证过程都没有。所以蓝牙设备的安全还得看具体的设备,另外就是你的蓝牙设备保护意识也得提高,比如修改默认密码。