【胖猴小玩闹】智能门锁与BLE设备安全Part 3: 耶鲁智能门锁的简
3简介
我们在前面两篇文章中简单介绍了BLE协议栈,并对一款智能灯泡进行了分析。本篇中,我们选择Yale品牌的一款智能门锁进行安全测试,一起来研究一下这款锁是否存在安全问题。
我们测试的智能门锁如图1.1所示,这款门锁有一个可拆卸的蓝牙模块,该模块配合Yale厂商提供的一款名为Yale Bluetooth Key的app,可以实现蓝牙开锁功能。
图1.1 智能门锁
首先我们需要介绍一下这款智能门锁的使用方式。和上一篇的智能灯泡类似,正常情况下,使用门锁前需要先在手机app中绑定门锁,如图1-2所示
图1-2 绑定门锁
绑定之后,如果门锁在手机的蓝牙通信范围内,app就会自动向门锁发起BLE连接,连接成功后,即可点击开门按钮打开门锁,如图1-3所示。
图1-3 连接及解锁
分析过程
2.1 App初步分析
既然智能门锁也可以由app控制,那么我们参考上一篇的研究思路,首先查看app日志,尝试获取BLE通信的内容。然而当我们用Android Killer查看日志时,发现Yale Bluetooth Key这款app没有输出任何日志。通过对APK进行简单的逆向分析,我们找到了关于输出日志的部分代码,如图2-1所示:
图2-1 App Log代码
ILog类负责输出日志,但是这个类中所有的Log函数均为空,要解决这个问题有两个方法:一是修改app的smali代码并重新打包;二是用Hook的方式直接打印这些Log函数的参数。本篇我们采用了第一种方法,第二种方法将后续文章中介绍。
可以使用Android Killer完成修改smali代码并重打包等工作。将app反编译之后,找到ILog.smali,在需要修改代码的地方点击鼠标右键即可插入代码,如图2-2所示,这里我们在插入Log代码的同时,也在AndroidManifest文件里添加了android:debuggable标签,在《耶鲁智能门锁的简单测试(下)》会提到它的用处。
图2-2 修改app代码
2.2 通信数据分析
修复了日志输出代码之后,我们就可以看到BLE通信内容了。当门锁在手机附近时,app会自动向门锁发起连接,连接过程的日志如图2-3:
图2-3 手机连接门锁时的日志
根据日志中的关键字“_72_AUTHENTICATION_EVENT”和“send 72ACK”进行代码回溯,找到关键代码如图2-4所示:
图2-4 Authentication数据包相关代码
结合我们在本专题第一篇文章中介绍的Android系统BLE接口的相关知识。图2-4的处理流程是:
a. 当回调函数onCharacteristicChanged或onCharacteristicRead被调用时,会发出一个名为“com.irevo.bluetoothkey.regnosleep.ACTION_DATA_AVAILABLE”的广播,其中携带着接收到的BLE消息内容。
b. 相应的广播接收器接收到这条广播后,将其中的BLE消息内容取出,交由函数handleLockStatus处理,这里输出了图2-3的第一条日志。
c. handleLockStatus函数中输出了图2-3的第二条日志,BLE消息由encodeCounter函数处理完成之后,交给send72Response函数。
d. send72Response将encodeCounter的处理结果封装为ACK帧,也就是图2-3的第三条日志的主要内容。在send72Response函数的最后调用了writeCharacteristic将ACK帧发送给门锁。
可以看到,这是一次完整的BLE通信的收发处理流程,结合日志中的AUTHENTICATION关键字,我们推测这是门锁与手机建立BLE连接时的身份认证过程。这一过程非常简单,门锁向手机发送一组数据,我们暂且称之为Authentication Request,Request经encodeCounter函数处理后得到Payload,Payload在send72Response函数中封装成Authentication Response发送给门锁,如果手机通过了身份认证,就可以发送控制指令控制门锁的打开与关闭了。
接下来,我们重点分析手机如何处理Request生成Payload。encodeCounter函数的参数counterData就是门锁发来的Authentication Request,图2-5展示了 counterData的处理方式:counterData被分割成若干个字节,每个字节都与key1~key6中的某一个相加,相加的结果放在c1r1~c3r4中。具体过程请看图2-5。
图2-5 Authentication Request的处理
c1r1~c3r4最后重新拼接成字节流形式,作为encodeCounter的返回值,也就是手机返回给门锁的Payload,如图2-6所示。
图2-6 Authentication Response拼接
已知Payload是由Authentication Request与key1~key6相加得到的,Request是门锁发送来的,那么key1~key6的来源是什么呢?如图2-7所示,encodeCounter函数首先读取了this.keyModel.productInfo变量,然后将productInfo变量逐字节存储到 key1~key6这些变量中。
图2-7 Authentication Key的处理
key1~key6来源于productInfo,那productInfo是哪里来的呢?我们继续回溯,可以发现productInfo是在门锁与手机进行绑定时,由门锁发送给手机的,在完成绑定后,将productInfo存储在数据库里,每次使用时直接读取数据库即可。回溯过程可以参考图2-8。
图2-8 productInfo的处理
上图中,箭头方向表示数据的流动方向。经过多次实验可以发现,门锁绑定不同手机时发送的productInfo是相同的,这应该是门锁出厂时就烧录在flash里的一组固定密钥。
经过分析,我们可以确定以上身份认证机制中存在这样一个问题:门锁对手机进行身份认证的算法是加法运算,如果我们能嗅探到Authentication的Request和Response两个数据包,就能直接通过减法运算得到productInfo,从而通过门锁的身份认证,控制门锁。
小结
本篇是我们对Yale门锁研究的上篇,在上篇中,我们主要对Yale门锁的app进行了分析,最终发现在门锁与手机的BLE通信机制中存在一些问题。在接下来的下篇中,我们会引入一个USB dongle用于对BLE通信进行嗅探,并利用本篇中发现的问题,通过嗅探而来的数据,计算得到productInfo,最终实现在任意手机上进行未授权开锁。