破解与攻击智能门锁

百家 作者:Chamd5安全团队 2021-01-27 10:38:21

本篇文章由ChaMd5安全团队IOT小组投稿

实验说明

在本实验中,我们将研究如何分析OKLOK智能锁安全性,并分析安卓APP,动态代码调试和BLE分析控制,最终实现使用我们的代码来远程控制智能门锁。
我们将首先使用BLE适配器和Gatttool与智能锁进行交互,并探索设备上存在的服务和特征。然后,使用JEB对安卓APP进行逆向,以了解服务和特征的含义。接着,我们将研究安卓APP和智能锁之间的BLE流量。使用Android BLE日志记录功能查看BLE流量,但也可以使用Ubertooth或任何其他BLE siffer。BLE流量和移动应用程序的分析将使我们看到了通信已使用AES加密。
最后,我们将使用安卓APP插桩查找加密密钥和其他值,我们将使用它们编写自动脚本在无需任何身份验证情况下,来接管智能锁并解锁。

所需资源

硬件

  • 智能门锁(OKLOK)

  • BLE适配器

  • 安卓手机(安装OKLOK应用程序)

  • Ubertooth(可选)

软件

  • Wireshark

  • Bettercap/Bleah

  • Android device 1 Ubertooth-tools

  • Jeb

  • OKLOK.apk

  • OKLOK_gadget.apk


OKLOK智能锁介绍

OKLOK是具有蓝牙低功耗(BLE)功能的智能挂锁。除其他功能外,还可以使用适用于Android和ios的OKLOK应用从手机远程操作挂锁。在本实验中,我们将分析Android应用,了解如何将其与BLE利用方法结合使用以控制智能锁。
该锁支持使用注册用户的指纹进行解锁,但是在这里,我们仅关注BLE上的远程解锁功能。
默认情况下,锁处于睡眠状态,即蓝牙扫描器既看不到锁,也不响应BLE命令。为了使用它,必须通过触摸锁体上的指纹传感器来激活它。激活后,锁在闲置几秒钟后会自动返回到睡眠状态。

OKLOK分析

初步分析

为了分析智能插头,我们要做的第一件事是找到目标智能锁的地址。为此,我们将首先确保已连接BLE蓝牙。运行hciconfig以查看智能锁蓝牙是否已成功连接到VM。

现在我们已经将智能锁蓝牙连接到了VM,让我们找出目标Smart Lock的地址。

Hcitool检测到我们的蓝牙名称为BlueFPL(蓝色指纹锁)的锁,其蓝牙地址为F8:33:31:DC:10:1F。我们还可以通过运行hcitool leinfo来查看有关BLE设备的更多信息,如下所示

hcitool工具集可以对蓝牙进行控制,工具集参数分为两部分,一为正常的蓝牙设备调试,二为低功耗即BLE设备, 工具参数如下:

现在使用Gatttol连接到设备,并探索设备上存在的服务和特征列表。使用hcitool是为了对设备的连接进行管理,那么对BLE数据进行精细化管理的话,就需要用到gatttool,使用gatttool对蓝牙设备发送指令的操作上要比hcitool的cmd齐全很多,关于gatttool的使用分为两种,直接使用参数对蓝牙设备进行控制,使用-I参数进入gatttool的interactive模式对蓝牙设备进行控制。

sudo gatttool -i hci- interface -b device-address -I

现在,我们可以使用primary命令列出设备上存在的所有服务。

同样,我们可以使用characteristics命令查看所有特性。

其中handle是特性的句柄,char properties是特性的属性值,char value handle是特性值的句柄,uuid是特性的标识;

我们还可以使用诸如Bleah(更改为Bettercap)之类的自动化工具来枚举所有不同的特征,它们的属性和存储的值。为此,我们将使用以下命令。

$ bleah -b F8:33:31:DC:10:1F -e

Bleah扫描附近的BLE设备,以查找具有指定MAC地址的设备。找到后,它将连接到设备并枚举所有服务和特征。
为了了解服务的目的及其特征,我们需要分析蓝牙流量和Android应用程序。

使用Android设备分析BLE流量

我们需要捕获从应用程序发送解锁命令时生成的蓝牙通讯。我们可以使用电脑上抓包嗅探技术,也可以使用Android智能手机的内置BLE日志记录功能来实现。Android提供了“HCI监听日志”功能,可用于捕获智能手机的蓝牙流量。进入APP,点击“指纹设置”,然后点击开锁发送解锁请求。

捕获的蓝牙流量将存储在名为1.pcap的文件,我们可以将其传输到PC进行进一步分析。UUID fee7的服务具有两个特性- UUID 36f5和36f6 handle 分别是 0x3和0x6,以及相应的属性为WRITE和NOTIFY。
在Wireshark中打开1.pcap文件并应用过滤器(btatt.opcode ==“ Write Request” && btatt.handle == 3

使用0x6 handle的过滤器,我们可以看到数据被加密了


解密流量

要继续进行,我们需要解密流量以了解远程解锁过程的工作原理。我们使用JEB反编译器分析Android应用程序。

Package com.coolu.blelibrary.utils内的BLEUtils类包含两个方法Encrypt和Decrypt,从安全分析的角度来看,这两个方法需要重点分析,这些方法将两个字节数组作为参数。

第一个数组包含明文/密文,第二个数组包含密钥。所使用的加密是ECB模式下的AES,无填充。

接下来是需要给手机安装插桩处理过的应用程序,手机连接蓝牙锁并执行开锁的操作,查看插桩的输出结果。

AES密钥是210358453708121F305B503D3A5A5037。它的大小为16个字节,这意味着密码是AES-128。使用这个密钥,我们可以解密我们在Wireshark中捕获的数据包。我们将使用脚本oklok-decrypt.py来解密AES加密值。
在我们的加密数据包上运行脚本,我们得到以下结果。

我们来看看第一个解密的写请求。它的开头是0601,十进制为1537。分析反编译后的代码,我们可以在com.coolu.blelibrary.mode包中找到一个类Order,其中包含了这些值的映射。1537代表GET_ TOKEN命令。

第二个命令是0201或十进制的513。这是GET_ BATTERY命令.(InputDeviceCompat.SOURCE_ DPAD == 513).第三条命令是0501或1281(十进制),这是OPEN_ LOCK命令。命令本身的名称清楚地表明了它们的目的

在我们捕获的BLE流量中,还有4个NOTIFY包,其中包含了对发送命令的响应。

与WRITE数据包的情况相同,每个数据包的前两个字节表示数据包类型,不同之处在于,其数值比相应的WRITE数据包多一个。例如,GET_T0KEN的ID对于WRITE为0601,对于NOTIFY为0602。检查包com. coolu . blelibrary中的CMDAPI类,我们可以发现这些消息的作用

因此,这四项响应是

  • CMD_TOKEN (0602)

  • CMD_ GET_POWER (0202)

  • CMD_ OPEN_ LOCK (0502)

  • Unknown (050D): 在 CMDAPI 中没有这样的响应,但它很可能与 LOCK_ STATUS 有关。


解锁

了解解锁过程

通过研究流量,我们可以推断出Android应用通过写入0x3句柄来发送命令,并且相应的挂锁通过在0x6句柄上发送通知来响应。从Gatttool输出(以及Bleah)中我们知道0x3句柄 对应于UUID 000036f5- 0000-1000-8000- 00805f9b34fb,而0x6句柄对应于000036f6-0000-1000 -800000805f9b34fb

我们可以使用包com.coolu.blelibrary中的BLEService类的反编译代码来验证我们的发现。

TX_ UUID和RX_ UUID分别对应于写入和通知句柄。
下图显示了我们的目标智能锁的解锁过程如何工作。

首先,应用程序从设备获取令牌,然后在后续命令中使用令牌。如上所述,所有请求和响应均使用AES-128 ECB模式加密。
为了绕过应用程序,实现自己打开锁,我们需要遵循相同的逻辑流程。

为简单起见,我们将省略获取当前电池电量的第二步,因为这对于我们的目的而言是多余的。
请求和响应均为16字节,前两个字节指示命令类型。为了理解如何构造命令本身,我们可以再次引用包com.coolu.blelibrary.mode中的反编译类。
对于GET _TOKEN命令,我们有一个对应的类GetTokenTxOrder。

从构造函数调用的add方法在0601之后将两个01字节追加到命令缓冲区。缓冲区的其余部分(12个字节)在generateString方法中填充有随机值。从包com.oklok.y.activity.lock中的LockInfoActivity类的反编译代码可以明显看出,对通知句柄0x6上命令的响应将包含四个字节的令牌。

相似地,对于OPEN LOCK命令,我们有一个对应的类OpenLockTxOrder。


前两个字节将包含命令类型0501,后跟06。接下来的六个字节包含某种密码,在我们的测试中始终将其设置为0x30,而与锁定密码无关。在应用程序上设置。接下来的四个字节包含在上一步中获得的令牌。其余的三个字节填充有随机值。

远程开锁

利用所有这些信息,我们可以编写脚本以连接到智能锁并处理数据包,对其进行加密并将其发送到设备以解锁设备,而无需任何有关特定设备实例的身份验证。

首先介绍一个python的第三方库—bluepy

bluepy

bluepy 是github上一个很好的蓝牙开源项目(https://github.com/IanHarvey/bluepy),其主要功能是用python实现linux上BLE的接口。


安装过程参考官方说明。关于这个库的使用官方也提供了详细的文档(http://ianharvey.github.io/bluepy-doc/)

编写代码

首先是扫描附件的BLE设备,这里要使用bluepy 的Scanner类

通过官方文档的描述,我们可以知道Scanner对象用于扫描正在广播广告数据的LE设备。在大多数情况下,这将提供一组可用于连接的设备。(但是请注意,蓝牙LE设备可以接受连接而不广播广告数据,或者可以广播广告数据但不接受连接)。

扫描结束后,通过getDevices()方法可以获取扫描到的设备,寻找需要连接的蓝牙锁

for dev in s.getDevices():
    if dev.getValueText(0x9) == 'BlueFPL':
        print '[+] Found OKLOK'
        connect(dev.addr)
        break

找到后需要使用Peripheral类来连接蓝牙锁

通过官方文档的描述,可以知道该类封装了与Bluetooth LE外围设备的连接。可以直接通过指定其MAC地址来创建外围对象。建立连接后,可以发现并读取或写入该设备提供的服务和特征。

接着使用getCharacteristics方法获取设备的特性对象列表

p = Peripheral(addr)
write_char = p.getCharacteristics(uuid='000036f5-0000-1000-8000-00805f9b34fb')[0]
notify_char = p.getCharacteristics(uuid='000036f6-0000-1000-8000-00805f9b34fb')[0]

接着使用之前获取的AES加密要发送的指令,发送开锁的指令

if d.token != None:
    cipher = AES.new(AESKEY.decode('hex'), AES.MODE_ECB)
    # Send unlock command
    pt = '050106303030303030'.decode('hex') + d.token + '\x00\x00\x00'
    write_char.write(cipher.encrypt(pt))
    print '[+] Sent unlock command'

即可完成开锁。

end


招新小广告

ChaMd5 Venom 招收大佬入圈

新成立组IOT+工控+样本分析 长期招新

欢迎联系admin@chamd5.org



关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接