智能门锁与 BLE 设备安全 Part 8:果加智能门锁的全面分析(下)
2021-03-30 14:55:00 Author: paper.seebug.org(查看原文) 阅读量:149 收藏

作者:Yimi Hu & Light @ PwnMonkeyLabs
原文链接:https://mp.weixin.qq.com/s/F5YHjG1t67Np53_kobG73Q

简介

本篇为家庭版果加智能门锁全面分析的最后一篇,在此前的两篇中,我们分析讨论了门锁固件和配套的app。家庭版果加智能门锁的app相对较容易分析,通过日志可以直接定位到java层代码,并进一步追溯到native层代码,在libBleCmd.so中,我们看到了所有BLE指令的生成代码以及相关的加密和解密函数。在解密函数中,我们找到了参与解密算法的几个常量,通过这几个常量,我们在门锁固件的大量代码中,定位到了进行解密运算的几个函数,详细分析这几个函数后,确定了BLE解密密钥存储的内存地址,接收到的BLE指令存放的内存地址等,并根据交叉引用的结果不断增加我们对固件程序的理解,展开了固件代码的分析讨论。

在这篇文章我们顺着这条主线继续深入分析,随着我们理解的内容不断增多,我们会发现更多有有意义的函数。最后,我们会展示一个家庭版果加智能门锁存在的严重问题,该问题已于2018年修复完毕,现在拿出来讨论一下应该还未出“小玩闹”的范畴。

固件分析

继续我们上一篇的思路,回到上一篇结尾时遗留的sub_80000C8函数位置。此函数为整个固件中最复杂的函数,我们将其F5反汇编之后,整理一下代码,可以看到该函数函数只有入口,没有出口:

图片

图2-1 整理后的sub_80000C8函数

然后我们再搜索下sub_80000C8函数的交叉引用,如下图所示:

图片

图2-2 sub_80000C8函数的交叉引用

继续向上溯源,可以找到下图所示位置:

图片

图2-3 loc_80000C0标签的交叉引用

可以看到,sub_80000C8函数是系统复位中断之后执行的第二个函数。一般情况下,复位中断会执行两个函数,第一个函数为init函数,即图2-3的sub_800D704函数;而第二个函数为main函数,即图2-3的loc_80000C0标签处的代码。此外,单片机的main函数一般都是死循环,不存在执行完毕后退出的情况,这与我们在图2-3中看到的while死循环相对应。与我们常见的运行于操作系统之上的程序不同,比如说’ ls’、’pwd’等常见的程序,他们完成各自的功能之后,就会退出,而单片机上电之后,MCU就要开始运行给他编写的程序,一直到单片机断电为止。

确定main函数之后,我们把目光重新聚焦在上一篇分析的sub_800EB20函数,当时我们把这个函数的功能概括为预处理,即完成消息头校验、crc校验、数据解密等工作的函数。那么在预处理之后,就应该是解析BLE数据、完成逻辑功能的代码。相关代码截图如下:

图片

图2-4 BLE命令解析相关代码

上图中,我们可以根据代码结构进行一些猜测:MEMORY[0x20000140]和MEMORY[0x20000169]应该是两个标志位,其中一个标志位标识收到了BLE指令;v115是预处理函数的返回值,返回值为0代表预处理成功,这与上一篇的分析是一致的;绿框部分的代码,即为真正解析BLE指令的代码。

然后我们再来看看sub_800F9EC函数,即图2-4绿框中的代码。将代码反汇编后,稍作整理,可以看到下图所示的特征:

图片

图2-5 BLE指令解析代码

再结合app的输出日志,如下图所示:

图片

图2-6 家庭版果加智能门锁app部分日志

可以确定图2-5 中,变量v3是保存了门锁发给手机的BLE指令类型,如图2-6中,0x2004类型代表开锁命令的返回数据。

下面我们仔细阅读一下图2-5中case 0xE004部分的代码,该分支是门锁对于BLE开锁指令的回复信息,将相关代码截图如下:

图片

图2-7 BLE开锁指令回复分支

进一步分析图中涉及到的函数,可以确定sub_80125C8函数的作用是日期转时间戳,其返回值v57就是时间戳。变量v57将会与v59和v60进行了比较,当v57不在[v59, v60]区间内时,就会调用sub_800D40C(0x1B)函数。此处的比较,我们是能够猜想到的:如果密码过期了,是无法开启门锁的,但是sub_800D40C(0x1B)函数就不太确定其含义了。所以我们再来研究一下sub_800D40C(0x1B)函数。

查找sub_800D40C(0x1B)函数的交叉引用,可以发现其调用位置有很多,如下图所示:

图片

图2-8 函数sub_800D40C(0x1B)的交叉引用

上图中列出了大量调用sub_800D40C函数的位置。点开每个调用位置,可以发现每次调用该函数时都会传递一个常量作为参数。而且在main函数进入while循环之前,也会调用此函数,如下图所示:

图片

图2-9 进入while循环之前调用sub_800D40C函数。

为确定sub_800D40C函数的真正含义,我们尝试更改函数的参数,然后将更改之后的固件刷入门锁。其更改方法并不复杂,直接进行16进制的固件文件编辑即可,如下图所示:

图片

图2-10 sub_800D40C函数参数

上图中,红框部分为传入参数的数值,截图中分别是0x09和0x0A。在16进制编辑软件中打开固件文件,找到该偏移位置:

图片

图2-11 十六进制编辑固件文件

将上图中的高亮字节0x09改为其他字节,如0xB,接着保存固件即可。然后将修改之后的固件刷到智能门锁设备中,刷入方法也比较简单,只需要在Fiddler中做一个AutoResponder,用修改过的固件替换原本固件,就可以了,具体操作如下图所示:

图片

图2-12 利用Fiddler替换原本固件

待智能门锁完成固件更新之后,我们给门锁重新上电,当门锁运行至while循环之前的sub_800D40C(0xB)函数时,门锁发出提示音:“请输入新密码”,而不是往常的“设置成功”提示音。再次修改固件,使智能门锁调用sub_800D40C(0xC)函数,上电后门锁发出提示音:“请再次输入新密码”。由此,我们可以判定sub_800D40C函数正是发出语音提示的函数,而该函数的参数代表了不同语音提示内容。通过反复修改并刷入固件,我们整理了一部分语音提示内容的编号,如下表所示:

图片

表2-1 家庭版果加智能门锁语音提示编号表

分析到此时,其实我们相当于在固件中找到了一个非常关键的函数:sub_800D40C函数。对于我们分析者来讲,这函数相当于日志输出的作用,在他的帮助之下,我们就能理解绝大部分代码,这里不再占用篇幅讨论更多内容了。

后门密码分析

在表2-1中,我们可以看到有一个“进入测试模式”的语音输出。顺其自然的,我们想看看测试模式都干了点什么。通过sub_800D40C(0x3)函数,我们可以定位到原固件中进入测试模式的代码,如下图所示:

图片

图3-1 进入测试模式的相关代码

上图中,可以看到一个关键的判断是v84的返回值。观察图中的函数参数,应该是和0x80126EE内存地址有点关系。我们跳转到0x80126EE函数的位置,可以看到如下内容:

图片

图3-2 偏移为0x80126EE位置的内存内容

上图中的内容,我们打了码,不过还是可以看出来,这些内容是智能门锁的键盘内容。如果不打码,我们担心影响太糟糕。

我们试着在门锁关闭的状态下输入这一串字符,当输入前两位时,门锁提示说“密码错误”,此时不要停,继续输入,待全部输入完毕之后,门锁果然提示说“进入测试模式”。然后,我们随便在门锁键盘上按了2个数字加‘#’号键,门锁竟然开启了。就这样,我们有了一个惊天发现:后门密码。看起来这并不是故意留下的后门密码,但确实实现了开门的效果。

图片

图3-3 通过测试模式开启门锁

小结

到这篇为止,我们完成了关于果加智能门锁的分享内容,在这次分享中,我们着重介绍了IoT固件的分析方法,解析固件内容,反汇编固件程序,并分析这些看起来意义不明的代码。在分析过程中,可以以其配套的手机app作为切入点,凭借此app与门锁之间的通信内容,在门锁固件程序中定位关键的代码,逐步理解固件内容。最后,我们还演示了关于果加智能门锁的一个小玩闹。纸上得来终觉浅,绝知此事要躬行。建议感兴趣的读者还是亲自尝试分析一下。最后,希望大家能够喜欢这个分享内容,如若有什么想讨论的,可以随时联系我们。


Paper 本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/1534/



文章来源: https://paper.seebug.org/1534/
如有侵权请联系:admin#unsafe.sh