当代许多信息系统在设计的时候就认为不会被其他人接触到,开发者们通常假定攻击者和安全研究人员无法获取到这些系统的内部信息。
ATM机就是这样的一个典型例子,攻击者会使用例如Cutlet Maker或者其他未公开的工具来将电脑接入ATM机上并在不留下系统记录的情况下盗取现金。这也证实了安全界长期持有的观点——没有牢不可破的系统,只有还没被充分测试的系统。
开始
即使是现在,也有许多人认为唯一能抢劫ATM机的方法就是暴力形式的物理攻击:在用电锯、撬棍和电焊砸爆ATM机之前,先用钩子尝试弄开保险箱上的锁。
但下面还有另一种攻击方法:
在通过eBay搜索以后,我购买了这块带有NCR USB S1 ATM机固件的主板,而我有两个攻击目标:
绕过ATM电脑通过USB接口向主板发出的加密后的操作指令(例如‘提款’)
绕过物理接口来实现身份认证(也就是需要修改保险箱底部的开关),从而获得上述操作所需要的加密密钥。
固件
固件包含了运行在VxWorks v5.5.1上的NXP Cold Fire处理器(摩托罗拉68040,我最喜欢的CPU)和对应的ELF文件。
ELF文件中包含了两块有趣的部分:.text和.data
前者包含了当取款机与上层ATM机连接后,大部分情况下使用的代码(我们称之为’主固件’)。
后者包含了一个zlib压缩后,负责升级固件和运行主要代码的bootloader(又称作“USB安全Bootloader)。
另外最棒的一点(对于研究者来说),ELF文件中的调试符号都可以轻易地在网上搜索到。
固件的主体工作流程
- 我们可以将代码分为四个流程,从上到下的顺序依次为:
- USB进程接受,获取USB口发来的数据包并发送到对应的服务端中。
- 主系统的执行功能,每个进程服务都负责特定的工作和任务(类)
- 上述的类是指由特定进程通过控制器执行的任务。
- 控制器是负责验证、执行任务并生成结果数据的功能模块。
由于有固件代码十分庞大,所以我打算尽可能的找出所有服务,并试图理清楚任务处理的流程。
下面是我找到的所有相关的服务。
DispTranService(现金转账服务)负责处理加密操作指令,生成对应的银行记录、身份认证等各种重要的信息。
securityService通过身份认证后,创建本次取款的会话密钥。当收到ATM机的请求后,会话密钥会以加密的形式发送,这个密钥用于加密所有该供货商的重要操作指令,例如提取现金或是生成转账记录。
但还有一项名为UsbDownloadService的服务引起了我的注意,这个服务是在ATM机连接到电脑上,发现双方固件版本不同时,切换相应的bootloader(存储在供货商计算机上)来升级系统中的固件版本,因此该服务可以告诉我们固件的当前版本等信息。
物理认证
事实上物理认证在通过保护ATM机不受未授权的USB操作影响上,这一块做得非常好。只有打开ATM保险箱才可以进行下列行为:
取下并插入下方的底板
切换提款机主板上的开关
但这些防护的前提是访问等级已经调到最高。一共有三个访问等级:USB(0),逻辑防护(1)和物理防护(2)。前两者都用于固件开发商进行调试和系统测试,供货商则会强烈建议默认选择最后一个物理防护等级。
漏洞
接下来我会讲述一个严重的漏洞(已经由供货商进行修复),该漏洞通过物理接入ATM机的服务区域,但不需要接入安全区域(例如用钻机打一个ATM前面板的洞),从而允许执行任意操作指令——即便命令是:现在立刻滚出现金!
我发现UsbDownloadService服务允许未加密过的操作指令,这听起来很诱人,不过安全Bootloader不应该像它的名字一样,阻止进一步的恶意攻击吗?
我们需要进一步的深入研究
正如之前描述的一样,.data部分包含了我和同事一开始没注意到的,压缩后的bootloader代码。
我们没有办法在不清楚bootloader过程的情况下回答“计算机上的软件是如何更新取款机固件的”这一问题,而主固件部分也没有给出任何线索。
所以对bootloader解包并加载到IDA中,从0x100000偏移处开始分析,发现这里没有任何调试符号。
不过与主固件的bootloader代码以及控制器中的数据表对比后,我又有了新的发现。
尽管固件升级的过程看起来很安全,但实际上并非如此。关键就在于如何正确的更新固件。
我们花费了大量的时间和精力(详情可参考BlackHat 2018的议题”Blackbox is dead – Long live Blackbox!),进行了如重新焊接NVRAM,复制备份来解锁控制器等一系列尝试行为。
这里需要感谢我的同事Alexey提供的帮助。
下面是更新提款机中固件的流程:
1) 生成一对RSA密钥并将公钥上传到控制器中。
2) 依次将ELF中对应的.data和.text数据写入物理地址中。
3) 计算新写入数据的SHA-1校验和,采用密钥加密该校验和,将结果发送到控制器中。
4) 计算并发送所有新写入的固件信息。
到这一步位置,如果所有的内容都计算正确并成功写入,主固件就能顺利的重新启动。
在写入过程中发现的唯一问题就是:新的固件版本号不能低于旧固件版本号,不过没有什么能阻止你简单修改版本号这几个数字。
也就是说,我到这里位置成功地上传并运行了带有后门的,不安全的固件系统。
至此,我大致了解了用域提取现金和其他行为的主固件中的操作命令,接下来提款机就会自动执行所有我发送的(没有加密过的)操作命令。
提取现金
能够入侵真实的ATM机是我一系列努力后获得的最有意义的(当然不仅仅是金钱上的)收获。我的好奇心激励着我在其他品牌ATM机上再次利用这一攻击技巧。
最终,一台真实的ATM机开始飞快地突出虚拟的纸币(类似于好莱坞电影用的银行纸币),这并不是什么魔术,只需要一台笔记本,一个脑子和一张USB卡。
总结
通过混淆实现的安全并不安全,单纯的将代码和固件进行混淆
正如开发应该交给开发者来做一样,安全也应该是安全专家的工作。供货商最有效的方法应该是和具备足够经验和资历、能够根据不同场景对系统进行安全测试和加固的专业安全公司进行合作。
结束语
供货商确认了该漏洞(在S2型号ATM中同样存在该漏洞)并宣布在2018年二月的补丁中进行修复
CVE编号:
CVE-2017-17668 (NCR S1 取款机)
CVE-2018-5717 (NCR S2 取款机)