对 KeyWe 智能门锁的漏洞挖掘分析总结
导语:攻击场景:用户使用app开锁,攻击者在距离门锁15米以内的地方使用nRF Sniffer嗅探获得流量,攻击者可以从流量中获得此用户用于开锁关锁的EKEY验证命令,使用此EKEY验证命令对锁进行重放开锁就可以打开门锁。
0x01 分析介绍
在智能设备时代,越来越多的设备变得智能化就不足为奇了,KeyWe智能锁也不例外,为了使生活更方便,它被设计为同时具有机械锁结构和其他功能,这些包括生成一次性访客验证码并根据接近程度解锁门。
但是,便利总是以安全为代价的!
0x02 设备概述
KeyWe智能锁包括三个重要部分:
· 前面板:用于与锁进行交互
· 机械锁:由软件和机械部分独立使用
· 背面板:用于供电和转动锁的机械部分
两个面板都已连接,如果有人试图断开连接,则会触发警报。
可以通过以下几种方式打开它:
· 使用钥匙机械开锁
· 使用已登录的app开锁(无需其他确认)
· 使用门卡开锁(NFC-Mifare Classic)
0x03 门锁硬件分析
拆下电路板分析各个部分的作用。
KeyWe的电路板
KeyWe电路板背面
前面板仅用于处理用户输入(数字键盘和RFID芯片),攻击者无法访问的背面将处理所有应用程序逻辑。
在背面面板进行串行和JTAG访问尝试无法调试。但是,组件标识表明使用的是STM微控制器。在裸露的SWIM端口:单线接口模块上,STM uC中使用的调试协议已启用,焊接到引脚并使用ST-LINK适配器后,设备固件就会被接通了。
虽然不完整,但可以在下面找到主板上标识的组件列表:
0x04 bridge分析
桥接设备是为了通过WiFi 检测发现通过蓝牙BLE处理的锁。尽管在外部相当复杂,但内部却装有基于ESP32的电路板。该板最有趣的部分是白板上的引脚。
KeyWe Bridge的板子
用万用表和引脚图花费一些时间之后,可以识别大多数引脚:
KeyWe Bridge-引脚图
尽管ESP已经相当成熟,具有读取保护,加密等功能,但桥接器未使用任何此类功能。串行和JTAG访问都保持启用状态,并且没有使用加密。可以通过以下输出确认:
$ espefuse -p /dev/ttyACM0 summary espefuse.py v2.5.1 Connecting.... Security fuses: FLASH_CRYPT_CNT Flash encryption mode counter = 0 R/W (0x0) FLASH_CRYPT_CONFIG Flash encryption config (key tweak bits) = 0 R/W (0x0) [...] JTAG_DISABLE Disable JTAG = 0 R/W (0x0) [...] Efuse fuses: WR_DIS Efuse write disable mask = 0 R/W (0x0) RD_DIS Efuse read disablemask = 0 R/W (0x0)
由于访问固件非常容易,因此自分析以来,Bridge就一直没有深入研究。
0x05 BLE蓝牙分析
我们现在移到通信和应用程序层,根据公开可用的材料以及锁随附的包装,我们知道它使用的是“ Bluetooth Smart”。对于那些不知道的人,这只是BLE / BTLE的别称:低功耗蓝牙。
BLE检查最方便的工具是Nordic Semiconductors的nRF Connect。在继续之前,先科普一下BLE一些基本概念:
与Bluetooth Classic相反,Bluetooth Classic是众所周知的技术,并且很可能每天都在使用,BLE不能做到发现设备。相反,每个外围设备都会向足够接近以接收它们的任何人发送消息。advertisements包含有关外围设备的信息:名称,地址(用于建立连接),功能等。这样的设备公开了服务的分组实体的列表。它们包含的特征可能包含一些值(文本,数字等),这些值可以被读取(读取访问),更新(写入访问)或可以通知另一连接方该值已更改(通知访问)。
KeyWe锁公开了具有两个特征的单个服务,一个读取和一个通知:
nRF Connect:KeyWe
现在已经可以假定它们用于向锁发送/从锁接收消息。话虽如此,但只有一种方法可以验证这一点:检查移动应用程序。
0x06 软件破解
在搜索与BLE相关的功能时,我们偶然发现了包含多个方法的DoorLockNdk类。对于不熟悉Android的用户,NDK代表Native Development Kit,并且是一种将Java本地(编译的)代码桥接(使用Java Native Interface,JNI)的方法。
每个上述方法都返回一个字节数组。详细说明一下:如果我们以某种方式截获了消息,那将是毫无用处的。发送前,每条消息均使用AES-128加密。通过访问DoorLockNdk类(特别是其方法),我们可以在接收到消息之前加密。这意味着可以分析通信协议。但是,我们如何截获函数调用?答案很简单使用Frida:https://frida.re/!,这里有hook相关的基础知识:https://www.fuzzysecurity.com/tutorials/29.html,我们创建函数dump参数和返回值。该代码可以在GitHub中找到:https://github.com/FSecureLABS/keywe-tooling。
在锁和移动应用程序之间交换的消息日志(基于使用Frida获得的信息)可以在下面找到:
值得一提的函数是:makeCommonKey,makeAppKey和makeDoorKey。它们在应用程序内部或在锁上被调用,但不会直接发送消息。
函数makeAppNumber和makeDoorNumber用于生成两方之间交换的值。这用作简单的“密钥交换”协议:双方生成一个值,然后将其发送给另一方,一旦接收到这个值,就可以计算出密钥对。一个密钥用于加密/解密源自锁的消息(makeDoorKey),另一个用于移动设备(makeAppKey)。在发送之前,这些数字中的每一个都用“公共密钥”进行了加密。可以在下面找到
示例性的makeCommonKey调用结果(公共键值)列表:
可以看到,公钥不发生变化,但是设备地址却变了。
这是一个很严重的漏洞!当使用内部密钥交换(仅涉及两个值)来解密所有通信时,一个密钥交换只需要拦截即可。然后可以根据设备地址轻松计算出公钥。
用于计算密钥的代码已在下面公布:https://github.com/FSecureLABS/keywe-tooling
这样,我们就有了打开门锁的钥匙!
0x07 通信嗅探
难题中仍然缺少一部分,我们实际上如何获得锁和移动应用程序之间交换的消息?常规应用程序/适配器没有这种功能。幸运的是,可以同时使用硬件和固件。为了嗅探蓝牙BLE流量,可以使用提供的nRF Sniffer。使用Waveshare BLE400或USB Armory Mk II等板卡(因为它具有基于nRF的蓝牙SoC),这样嗅探BLE数据就像运行带有一个插件的Wireshark一样简单。
0x08 厂商回应
厂商已确认该问题,正在努力解决。自F-Secure披露此问题以来,他们一直在做出回应,并积极参与了沟通。不幸的是,没有固件升级功能,因此问题将一直存在,直到更换设备为止。根据供应商的说法,新设备将包含安全修复程序。此外,下一版本的锁将具有固件升级功能。
不能说KeyWe锁没有对安全性给予任何关注。涉及密码学时,所使用的AES算法是事实上的标准。但是,所使用的协议是一种内部加密 。并且,正如行业多年来所证明的那样,这种协议永远不会奏效。而且,供应商似乎对威胁模型含糊不清。
0x09 漏洞分析
KeyWe智能锁存在多个设计缺陷,导致未经身份验证的(可能是恶意的)actor能够拦截和解密来自合法用户的流量。如下所述,此流量随后可用于代表所有者执行操作(例如打开/关闭锁,拒绝服务,使锁静音等)。
攻击者可以通过拦截任何合法的通信来利用此漏洞,以窃取密钥并在任何时候远程解锁门。
合法应用程序和锁之间的通信消息是使用Bluetooth Low Energy传输的。在发送之前,它们使用带有随机2B(两字节)前缀的AES-128-ECB进行了加密,从而使第三方无法轻易地窃听和篡改来自合法方的命令。但是,密钥生成过程受到严重缺陷的影响。
KeyWe当前使用的消息通道的安全性取决于两个因素:
1、用于启动密钥交换的公钥
2、应用程序/锁的密钥计算过程
F-Secure已证明可以克服这两个限制。首先-基于全局可用的设备蓝牙MAC地址创建公钥,因此解密协商的第一阶段很简单。其次,可以从移动应用程序检索密钥生成过程。
在使用锁之前,应先注册设备。注册过程包括三个阶段:
· 阶段1:设置锁定模式以检查是否需要注册
· 阶段2:为设备注册密码-以后称为EKEY
· 阶段3:验证EKEY值(身份验证和授权)
一旦设备成功通过身份验证/授权步骤,就可以进行其他操作,例如打开锁,关闭门等。上述每个阶段都包含几个其他步骤。
首先,基于设备蓝牙地址,计算一个公共密钥。双方使用计算出的密钥(以后称为comm)来加密任意12B(十二字节)值,然后将其发送到另一端,如下所示:
app num app --[comm(12B value)]-> door door num app <-[comm(12B value)]-- door
一旦交换了数字,双方就分别为自己和另一方计算密钥:
door_key = make_door_key(app_num,door_num) app_key = make_app_key(app_num,door_num)
通讯(称为握手)如下:
app door app <-[ door(START) ]-- door
握手结束后,还会出现其他消息-包括EKEY验证命令。
尽管门/钥匙的生成是基于自定义算法的,但可以(即从Android库中)检索它并以相对较低的成本进行逆向。因此,只要恶意攻击者在15米左右的有效范围内,就可以类似于上面提供的描述来拦截和解密流量。
流量拦截也可以以相对较低的成本进行,例如,能够嗅探BLE通信的nRF51822芯片的价格约为5美元。
检索到EKEY值后,攻击者即可执行合法用户能够执行的任何操作。只要原始应用程序已注册到设备,这都是可能的。
如果设备根本没有注册(仅使用机械锁),则恶意行为者可以劫持该锁并对其进行操作,而无需进行任何其他交互。由于机械部件取决于操纵锁定机构的伺服机构,因此也会导致完全失效。
0x10 学习总结
电路板的后面板芯片是用于处理开锁逻辑的,前面板用于处理用户输入:数字密码和门卡。
在背面面板进行串行和JTAG调试,但是无法接通,改变思路发现主板使用了SMT微处理器,STM uC使用的调试协议是开启的,焊接到SMT微处理器的引脚上就可以调试固件了。
用万用表和引脚图发现了大部分引脚,这里的串行和JTAG都开启了,且没有加密,就可以调试分析。
安装nRF Connect就可以嗅探BLE信息。
Bluetooth Classic会发现周围的设备,但是BLE会以一种广播的方式向能接受的设备发送消息。
app发送的消息都是通过AES-128加密的,即使截获了消息也没用,DoorLockNdk类中有很多BLE通信的方法,使用Frida对方法做hook就可以截获参数和返回值。
https://www.fuzzysecurity.com/tutorials/29.html
输入数字密码,函数makeAppNumber和makeDoorNumber用于生成两方之间交换的值,这种秘钥交换协议是:双方生成一个值,然后将这个值发送给对方,双方各自计算出一个秘钥,这样就有一个秘钥对,锁上的秘钥用于数字和门卡开锁关锁密码解密,app上的秘钥用于app开锁解密,在发送这个值前都会经过公钥加密,到了目的端再用私钥解密。
漏洞发生在设备MAC变了,但是公钥却不发生变化。
计算公钥的密码:https://github.com/FSecureLABS/keywe-tooling
使用nRF Sniffer就可以嗅探到BLE通信私钥:
https://www.nordicsemi.com/Software-and-tools/Development-Tools/nRF-Sniffer-for-Bluetooth-LE
KeyWe当前使用的消息通道的安全性取决于两个因素:
1、用于启动密钥交换的公钥
2、应用程序/锁的密钥计算过程
秘钥交换的公钥是基于MAC地址创建的,可以轻松获得。
门锁注册过程包括三个阶段:
· 阶段1:设置锁定模式以检查是否需要注册
· 阶段2:为设备注册密码-以后称为EKEY
· 阶段3:验证EKEY值(身份验证和授权)
上述每个阶段都包含几个其他步骤:
1.基于设备蓝牙地址,计算一个公共密钥。双方使用计算出的公共密钥来加密任意12B值,函数makeAppNumber和makeDoorNumber用于生成两方之间交换的值,然后将其发送到另一端
app num app --[comm(12B value)]-> door door num app <-[comm(12B value)]-- door
2.一旦交换了数字,双方就分别为自己和另一方计算密钥(相同):
door_key = make_door_key(app_num,door_num) app_key = make_app_key(app_num,door_num)
3.通讯(称为握手)验证授权:
app door app <-[ door(START) ]-- door
握手结束后,还会出现其他消息-包括EKEY验证命令。
4.嗅探拦截解密流量,检索到EKEY值后,攻击者即可执行合法用户能够执行的任何操作
攻击场景:用户使用app开锁,攻击者在距离门锁15米以内的地方使用nRF Sniffer嗅探获得流量,攻击者可以从流量中获得此用户用于开锁关锁的EKEY验证命令,使用此EKEY验证命令对锁进行重放开锁就可以打开门锁。
学到了一种新的门锁漏洞挖掘骚姿势:)
发表评论