前言

“2020年4月30日起,丰巢快递柜开始实行超时收费的“会员制”,非会员包裹只可免费保存12小时,超过需收取0.5元/12小时的费用。”
这则新闻甫出,可谓一石激起千层浪,各方媒体、民众声讨声不断。商人逐利本无可厚非,但君子爱财,取之有道,若是这“道”实为对用户的暗度陈仓之道,那么这“财”该不该取、该向谁取?这是一个值得丰巢与广大快递收、发用户好好商榷的问题。
img

所谓“术业有专攻”,目前丰巢与用户之间的收费矛盾该如何善后我们姑且不谈,但是对于在我们当下生活中普及率越来越高的如智能快递柜、自动售货机、自动洗车机器人等这些线下终端锁具安全性,我们研究院的小伙伴还是非常感兴趣的,现在让我们通过几个具体的案例研究来探讨一下智能终端存在的某些风险。

智能终端安全

沙箱绕过

绕过特殊手势、断电重启等特殊操作绕过沙箱 。

img

通过某些特殊手段使快递柜返回到安卓桌面。

img

可以通过中间层管理APP调试快递柜,可打开所有快递柜门 。

物理安全

img

智能终端机箱主机柜通用钥匙。

img

可简单物理开启机柜进行调试。

img

某自动售货主机机柜可被轻松技术开启。

供应链安全

智能终端固件、文档等泄露。

img

img

img

可搭建出模拟环境

通过以上案例我们可以看出,类似这种智能终端在目前还是存在很多的安全风险的,所以某些企业在想着如何从用户那里赚钱的同时,是不是也应该多花些时间在提高产品的安全性能上下功夫呢?

回归正题,在上一期《锁王创造营》我们对“New Orieans”成功解锁后,地图上会出现下一个level——“Sydney”,现在让我们开始新的挑战吧。

img

第二关:Sydeny

Lockitall LockIT Pro, rev a.02,作为前一个的更新版本,我们有必要浏览一下显示的手册:

DETAILS

​ …

​ This is Software Revision 02. We have received reports that the prior version of the lock was bypassable without knowing the password. We have fixed this and removed the password from memory.

大概意思是从内存中删除了密码,密码不会在内存中以硬编码的形式存在了。

首先查看main函数,显然,并没有之前create_password函数。main中仍然有put函数打印字符串输出,check_password函数检查密码是否正确,以及INT函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
4438 <main>
4438: 3150 9cff add #0xff9c, sp
443c: 3f40 b444 mov #0x44b4 "Enter the password to continue.", r15
4440: b012 6645 call #0x4566 <puts>
4444: 0f41 mov sp, r15
4446: b012 8044 call #0x4480 <get_password>
444a: 0f41 mov sp, r15
444c: b012 8a44 call #0x448a <check_password>
4450: 0f93 tst r15
4452: 0520 jnz #0x445e <main+0x26>
4454: 3f40 d444 mov #0x44d4 "Invalid password; try again.", r15
4458: b012 6645 call #0x4566 <puts>
445c: 093c jmp #0x4470 <main+0x38>
445e: 3f40 f144 mov #0x44f1 "Access Granted!", r15
4462: b012 6645 call #0x4566 <puts>
4466: 3012 7f00 push #0x7f
446a: b012 0245 call #0x4502 <INT>
446e: 2153 incd sp
4470: 0f43 clr r15
4472: 3150 6400 add #0x64, sp

根据静态分析,在check_password函数调用后,根据之前的经验,函数返回值存放在r15寄存器。返回后下一条指令”tst r15“,检查r15寄存器也就是的值是否为零。我们查看check_password函数进一步分析。

1
2
3
4
5
6
7
8
9
10
11
12
13
448a <check_password>
448a: bf90 2c41 0000 cmp #0x412c, 0x0(r15)
4490: 0d20 jnz $+0x1c
4492: bf90 3c67 0200 cmp #0x673c, 0x2(r15)
4498: 0920 jnz $+0x14
449a: bf90 3c65 0400 cmp #0x653c, 0x4(r15)
44a0: 0520 jne #0x44ac <check_password+0x22>
44a2: 1e43 mov #0x1, r14
44a4: bf90 6b63 0600 cmp #0x636b, 0x6(r15)
44aa: 0124 jeq #0x44ae <check_password+0x24>
44ac: 0e43 clr r14
44ae: 0f4e mov r14, r15
44b0: 3041 ret

可以看到,check_password中一共有4个cmp指令,将源操作数与r15寻址的内存中的内容比较,且目的操作数之后都是以两个字节偏移递增。若是经过4次cmp比较,r15将会被赋值为0x1,也就是能通过密码检查。

需要注意的是这里使用的是cmp,与上一等级的cmp.b相比,少了.b扩展名也叫助记符,所以操作数不再是一字节(byte);cmp虽然省略了.w扩展名,但其相当于cmp[.w],操作数是一个字(word)。在msp430用户指南中解释,如果不使用扩展名,指令是一个字指令

img

此时,我们需要知道r15所寻址的内存地址,我们回到main函数中可以发现,调用check_password函数前,将sp 当前栈指针移动到r15sp的值我们还不知道,那我们开始调试吧。

1
2
3
4
5
4438 <main>
...
444a: 0f41 mov sp, r15
444c: b012 8a44 call #0x448a <check_password>
...

使用break 444a命令,在地址0x444a处设置断点,查看sp的值以及sp指向的栈空间的内容。首先会调用请求输入get_password函数,我们输入”test“,进行测试。

输入完毕后,在此c命令运行,执行到地址0x444a后中断,我们可以查看sp的值,栈空间(sp)的内容正是我们输入密码。

img

继续设置断点break check_password,然后c运行,进入check_password分析,我们已经知道r15寻址的内存中内容正是我们输入的密码,所有将cmp的源操作数提取出来,依次是0x412c、0x673c、0x653c、0x636b,这应该就是正确密码了。

1
2
3
4
448a: bf90 2c41 0000 cmp   #0x412c, 0x0(r15)
4492: bf90 3c67 0200 cmp #0x673c, 0x2(r15)
449a: bf90 3c65 0400 cmp #0x653c, 0x4(r15)
44a4: bf90 6b63 0600 cmp #0x636b, 0x6(r15)

这里有一个问题,将以上16进制数组合起来:412c673c653c636b,若是直接作为输入肯定是会出错的,因为,我们还忽略了字节序的问题,MSP430的是小端存储(little-endian),所以我们需要将其高字节与低字节进行交换。

关于字节序,大家都不陌生,维基百科中关于字节序中介绍:

字节的排列方式有两个通用规则。例如,一个多位的整数,按照存储地址从低到高排序的字节中,如果该整数的最低有效字节(类似于最低有效位)在最高有效字节的前面,则称小端序;反之则称大端序

解锁

勾选16进制编码输入复选框,以16进制编码输入:2c413c673c656b63。

img

解锁成功!

img

以上就是本期《锁王创造营》的全部内容了,对闯关以及其他问题感兴趣的小伙伴可以加一下我们的技术交流群哦!

img

参考

1、 MSP430 用户指南 http://www.ti.com.cn/cn/lit/ug/zhcu032i/zhcu032i.pdf
2、智能锁具攻防一:初探 https://yaseng.org/intelligent-lock-attack-and-defense-1.html
3、智能锁行业安全分析报告 https://yaseng.org/intelligent-lock-industry-safety-report.html
4、物联网安全百科 https://iot-security.wiki