我最喜欢的一种硬件黑客攻击方法是使设备执行原本不希望的操作,这让我很有成就感。
每个人都有自己的处事方式,不同的方法,习惯和技能集意味着攻击方法将是多种多样的。
前言
这是我去年为44CON大会准备的一个项目,你可以点此观看相关视频。
在这个项目中,我想要修改的设备的需求列表如下所示:
· 液晶屏
· 菜单按钮
· USB设备通信
· 板载存储器
总之,这些功能合在一起就可以构成有效的USB仿真和开发设备。
一位同事向我展示了一些OBD-II reader,他通过逆向工程来确定它们的能力,我觉得这将是一个完美的目标,如果我能找到一个合适硬件。
四处查看之后,我发现了一款看起来具有该项目所需功能的设备——Nexpeak NX301。
对设备内部的模糊了解为我提供了足够的信息,以确定这将是该项目的理想设备:
1. 使用STM32F103 MCU,具有64KB的Flash,20KB的RAM;
2. 最大时钟速度为72MHz;
3. 具有LCD屏幕,USB接口,CAN接口和菜单按钮;
4. 包含8MB SPIFlash。
人们发现该设备有许多不同的名称,但是它们似乎都具有相同的功能。
固件介绍
设备上的USB接口被发现用于固件更新,使用的工具可以在线被下载到。
快速浏览程序文件可以发现,它使用标准的STM32 USB CDC接口上传固件,这意味着程序文件使用了标准的系统库,没有额外的硬件用于板上的USB通信。
发现该程序可以使用HTTP从互联网上下载固件文件,这意味着一旦使用Wireshark找到URL,就可以快速找到并下载固件文件。
快速分析此固件的有效载荷后,就会发现它已被高度加密,这意味着破坏固件更新的速度将会很慢。
除此之外,连接到板上的STM32芯片后,发现它已被锁定,这意味着无法从设备读取固件,但可以覆盖固件。
此时,固件升级是加密的,读取保护是启用的,所以我有两个选择:
1. 从头开始构建固件:
1.1 不需要进行软件逆向工程;
1.2 需要进行硬件逆向工程;
1.3 允许访问整个64KBFlash;
1.4 不允许使用设备的固件更新功能;
2. 破坏读出/固件的保护:
2.1 允许修改原始应用程序;
2.2 需要发现设备中的可利用漏洞;
2.3 允许使用内置固件更新;
2.4 不需要进行任何硬件修改。
最后,我决定两种方法都采用。
从头开始构建固件
我先将SWD接头焊接到板上,然后如下图所示放置,这样即使在关闭情况下也可以轻松地对设备进行编程。
建议在从芯片删除代码之前对所有外设进行逻辑分析,但是在本例中,我没有这样做,而是决定从头评估它们的功能。对于板上的SPI Flash和CAN接口,这很简单,因为它们都有已知的数据表。然而,对于LCD屏幕,情况却有一些复杂。
评估板的关键要素还包括将所有标准外围设备追踪到其在微控制器上的引脚,例如菜单按钮和LED。这是一个简单的任务,因为该硬件可以直接连接到引脚。
在该案例中,我使用STM32Cube设计软件设置了一个项目,标记了每个引脚,并配置了SPI,USB和CAN接口。
SPIFlash已映射到SPI2端口,并且标准SPIFlash命令可用于通信。
此外,STM32Cube具有内置的USB库,可以对其进行修改以模拟几乎任何USB设备,这意味着它可以配置为充当我们想要欺骗的任何硬件。
对屏幕进行逆向工程
不幸的是,LCD屏幕具有部件号(DJM12864G13),但没有公开的数据表。但是,可以在销售页面上在线获得引脚分配,从而可以更轻松地评估每个引脚的用途。
跟踪每个引脚并对该引脚进行评估,如上所述,该设备处于并行模式。根据引脚排列中概述的命令/数据和读/写信号信息发送随机数据包,可以进一步识别协议。结束时表明它使用了标准协议,其他制造商的LCD控制器也使用了标准协议,但确实有其数据表可用。这些备用数据表的使用允许与LCD控制器进行适当的通信。
这样,就可以在屏幕上绘制ASCII位图。
对该协议的进一步评估表明,尽管有些困难,仍可以将映像绘制到屏幕上。
USB连接
现在,是时候来看一下芯片的USB接口了。我的意图是创建一个能够将自身显示为USB磁盘,以便向其中写入文本文件的设备,以及一个USB键盘,以便使用LCD屏幕和菜单按钮将预编程命令输入标准PC来创建自己的设备,选择要处理的文件。
对我来说幸运的是,STM32Cube提供了用于标准设备类型的库,包括可用于仿真USB驱动器和键盘的HID和大容量存储库,大容量存储库与板上的SPIFlash配对,可将8MB数据存储到设备。
我把我的软件设计成两种启动模式,首先,将其配置为在启动时按住菜单按钮时可以启动为USB磁盘。可以利用板上的SPI Flash来存储FAT32文件系统。
从USB库提取的读取和写入命令可以映射到SPI Flash读取和写入命令,主要区别在于USB磁盘被配置为一次可读取和写入4096字节的块,并且Flash被设计用于256个字节的块。这一切意味着通过USB进行的所有读取和写入将转换为Flash的16个读取和写入。
我对该设备进行了编程,以便在不按住任何按钮的情况下,它都可以作为USB键盘显示给主机。为了允许从文件中选择菜单,我需要能够读取FAT32文件系统。
为此,我利用了FATFS库,该库允许挂载、读取和写入FAT32文件系统,为读取和写入提供回调函数,以允许开发人员提供自己的硬件集成。使用此功能,可以读取文件并将其打印到屏幕上。
为了将这些文本文件的内容转换为USB键盘接口,需要将它们转换为使用标准USB HID接口的扫描代码,这可以简单地通过生成查找表来执行。
为了整合这个项目,我使用了一些开发捷径。由于硬件的限制,必须使用一些技巧。其中最关键的是板载USB仅在初始连接到主机时枚举,因此,通过在启动时按住按钮来选择“大容量存储”或“键盘”模式,并且要更改模式,必须将整个设备与PC断开连接。
这构成了一个可以正常工作的设备,可以满足我对设备的预期,但是如果不进行固件保护,就不能将其上传到全新的Nexpeak而不进行硬件修改。
破解固件加密
现有的限制如下:
· 固件更新有效载荷已加密;
· 代码读取保护被启用;
· 没有发现针对该芯片的已知通用攻击是可行的;
· 众所周知,STM32F103很容易受到故障攻击,但这需要对电路板进行修改。
固件升级模式中启用了SWD,这是导致固件保护失效。尽管在STM32F103上启用了读取保护功能,但即使在Flash无法读取的情况下,RAM仍可以随时读取,这有助于揭示可以存储在此处的关键信息。
此外,由于固件更新是通过标准的USB CDC通信来使用的,如果可以执行中间人攻击,则攻击者很容易伪造这些更新。
使用我的BeagleBone Black和USBProxy USB分析工具,可以在执行过程中查看这些更新。可以使用USBProxy和任何具有USB设备功能的嵌入式Linux设备(例如Raspberry Pi Zero或NanoPi)执行此方法。
快速浏览一下该通讯,可以轻松地通过LibUSB对其进行重播,但是在命令末尾使用了CRC,这需要在修改有效载荷时进行更改。
现在,编写了一个工具来仿真和重放固件更新。每个单独的数据包都可以根据其响应进行重放和验证。发现正在使用的CRC是标准X.25 CRC-16,可以很容易地对其进行更改以修改更新的元素。该分析还显示,更新以512字节块发送。
对固件更新文件的粗略分析发现,它与芯片的潜在内存空间相匹配,这在很大程度上意味着没有常规的完整性检查。如果向设备发送了损坏的固件在和,则该设备将无法启动,这一事实证实了这一点,上传旧固件文件的能力也表明没有回滚保护。
可以在每个512字节的块发送后停止固件更新进程。这样,就可以确定固件有效载荷在RAM中的哪个位置被解密和存储,因为Cortex-M芯片(如正在使用的STM32F103)使用的前两个32位块总是分别以0x20和0x08结束。
这样就可以手动提取RAM中解密的固件,并将其缝合在一起。即使可以解密固件,也无法编写新固件,因为加密算法和使用的密钥仍然未知,每次RAM读取后芯片都会崩溃。
虽然无法从RAM转储中确定正在使用的加密算法,但是很可能将任何加密密钥存储在此处。这样,如果可以识别加密算法,则可以将它们一起使用以加密和解密固件。
因此,我们采取了猜测加密算法的步骤。对第一个512字节的固件块进行了细微的修改,以查看它们对RAM中已解密的固件的影响。这个过程可以缩小加密算法的使用范围。
如果在解密的固件中只改变一个字节,那么这很可能是一个流密码。
如果修改了一个字节,并且仅更改了解密固件中前几个字节中的字节,则表示ECB模式块密码,最可能是AES。
如果在固件的后续部分中修改了一个字节,并且仅更改了所有后续数据块,则它将表示CBC模式的块密码。
然而,最后,对有效载荷的任何字节进行修改都会改变解密固件的整体,这意味着最可能的算法将是Block TEA或XXTEA。
根据这个假设,第一个512字节的块和RAM转储一起处理,循环遍历RAM的每个块。
这表明使用接近RAM转储开始位置的数据来显示解密固件的开始位置,意味着已找到XXTEA密钥。
· key[0] = 0x00001494;
· key[1] = 0x0000d65b;
· key[2] = 0x05e2e03f;
· key[3] = 0x00005426。
卸载引导程序
现在可以将我们的自定义固件部署到芯片上,但是我想更进一步。我想快速转储处理来自芯片的安全固件更新的引导程序。
通过修改原始固件有效载荷,现在我们有了加密密钥,我们可以覆盖固件以将引导加载程序的全部内容转储到RAM中。
这样可以将其读出,然后再将其重新部署到设备(如果已擦除),我编写了一个小的ARM有效载荷来保护这种持久性。
依次,这个固件将一个小的魔法数字加载到RAM的开头(0xBBAA),然后循环遍历Flash并将其写入RAM的其余部分,并以无限循环结束,因此不再执行进一步的处理。这可以在任何汇编器中快速编译,但是我使用了shell-storm.org提供的在线汇编器。编译代码后,可以将其写入更新有效内容中。
为了快速执行此操作,我想将其直接粘贴到更新数据中。通过识别二进制文件中地址0x04处的微控制器的重置向量,我可以确定它需要在固件中的偏移0x100处写入,这可以基于一些假设来计算。
发现重置向量为0x08004101,首先,所有Flash均始于0x08000000,这意味着可以将其从地址中删除。接下来,我们知道引导加载程序的大小为0x4000,因此可以将其删除。最后,我们知道所有Thumb代码都具有地址集的最低位,以便将其与ARM代码区分开来,因此可以将其删除。这给我们留下了0x100的值,以下就是我编写组装好的有效载荷。
在运行这段代码后转储RAM显示了神奇数字,然后是引导加载程序。
了解固件更新过程意味着无需进行硬件修改即可部署固件。
总之,这种访问可以使我们无需任何硬件修改即可将本设备用于任何目的。因此,我决定让这个设备也有一个需要修改硬件的目的。
修改硬件
简单的硬件修改可以为设备增加额外的功能,而移除辅助组件则可以将新组件安装在原位。
我不想使用设备上的CAN接口,因为这是设备的原始用途。
因此,我从引脚设计中删除了它,并用定时器和中断引脚替换了它。
这些足以让我复制我以前的一些工作:创建NFC标签仿真设备。
板上的CAN通信的原始组件可以拆装,并且可以在其位置上添加电线,以便连接一个新的子板。
使用我以前使用的相同标准设计,可以制作一个小的子板并将其连接到这些电线上。
然后可以将天线添加到该板上,并穿入设备外壳的背面。
使用为USB仿真设备开发的软件,可以使用USB Mass Storage功能将二进制NFC标签数据存储在设备上,然后可以将其用于仿真。
芯片上可用的72MHz时钟速度意味着几乎所有软件都可以直接移植到新设备上,而LCD屏幕用于选择通过USB部署的标签数据。
我有一块锂离子电池,它被绑在设备的后面,可以直接连接到SWD的引脚上为其供电。
由于对芯片的内存限制,对FATFS库进行了一些修改,可以将其整合到具有菜单功能的完全正常工作的13.56MHz NFC标签仿真器中。
本文翻译自:https://www.pentestpartners.com/security-blog/turning-an-obd-ii-reader-into-a-usb-nfc-attack-tool/如若转载,请注明原文地址: