NRF52固件读取和反向工程现已成为可能

2020-06-11 14:49:59

是的,JTAG/SWD接口在受保护平台上的恢复一直是嵌入式安全领域的敏感话题。

此安全调查提供了一种绕过受保护nRF52840上的APPROTECT的方法,以便重新激活串行线调试接口(SWD),从而在目标上提供全面的调试功能(对闪存/RAM/寄存器的读/写访问、代码执行和重新编程)。所有nRF52版本都会受到影响。

由于其固有的特性,如果没有硅片的重新设计,漏洞就无法修补,从而导致无数易受攻击的设备永远出现在现场。

北欧半导体(Nordic Semiconductor)和有限结果公司(Limited Results)没有就负责任的披露达成一致。这就是生活。

整个nRF52系列由六个不同的nRF52平台组成,全部围绕ARM Cortex-M4F CPU构建。

让我们把重点放在家族的旗舰平台上,我的意思是nRF52840。

nRF52840 SoC(片上系统)是nRF52系列SoC家族中最先进的成员。它是一款先进的蓝牙、线程和Zigbee多协议SoC,围绕64 MHz Cortex-M4F CPU构建。它配有1MB的闪存和256Kb的RAM,两者都是完全集成的。

在安全性方面,片上集成了ARM TrustZone CryptoCell密码单元作为密码引擎。SoC的框图显示了nRF52840的功能(和复杂性):

如今,大多数半导体供应商在其MCU/SoC内部实现了名为代码读出保护的安全功能,以防止具有物理访问权限的攻击者转储存储在集成闪存中的代码/数据并对其进行修改。

根据芯片供应商的不同,此安全功能可以有不同的名称(crp、rdp、pcrop…)。

通常,一旦攻击者获得固件副本,他就可以开始反向工程过程,或者只获取一些敏感数据(如密钥和密码)。

2015年,Include Security在nRF51代码读出保护功能(称为RBPCONF)的设计中发现了一个漏洞,使得攻击者能够使用SWD调试界面恢复整个固件。

在nRF51上,启用RBPCONF保护后,使用调试器直接访问闪存或RAM只返回零。但是,仍然可以控制代码执行和读写寄存器(甚至是程序计数器)。因此,在受保护的存储器中找到“小工具”,例如从某个寄存器中的地址读取存储器到另一个寄存器的简单加载字指令,就足以提取整个固件。因此,对基于nRF51的设备具有物理访问权限的攻击者能够转储闪存,从而利用此设计漏洞。

因此,nRF51代码读出保护(RBPCONF)被认为是一种损坏的安全机制,不能防止固件被提取。

在这一失败之后,北欧半导体决定设计具有更严格安全机制的nRF52,以防止存储器读出。此安全功能称为访问端口保护(APPROTECT),在每个nRF52产品手册中都有简要提及:

通常,外部调试器通过调试访问端口(DAP)访问ARM CPU。然后,可能会有两个不同的端口可用:

-CTRL-AP。这是主调试端口,它不依赖于APPROTECT。它将用于恢复,例如,在设备被砖封的情况下。

-AHB-AP。这是通过SWD访问存储器和控制CPU的真正调试端口。

北欧半导体不提供任何有关APPROTECT机制的信息。我推荐阅读Cortex-M的ARM参考文档。

用户信息配置寄存器(UICR)是用于配置用户特定设置的非易失性存储器(NVM)寄存器。它们被映射到0x10001000。

APPROTECT属于UICR。需要在地址0x10001208写入0xFFFFF00才能启用访问端口保护,如下图所示:

根据北欧的说法,如果不擦除所有RAM和内存闪存,则无法禁用APPROTECT安全性。

用户手册和原理图可在制造商的网站上找到。nRF52840是QFN73版本,7x7 mm,位于右侧。

该套件具有嵌入式Segger J-Link调试器(白色贴纸的最大芯片)。

首先,我只需编译并刷新SDK中的一个示例,以检查我的环境是否正常。

$openocd-s/usr/local/share/openocd/scripts-f./interface/jlink.cfg-c";Transport select SWD";-f./target/nrf52.cfg#telnet$telnet localhost 4444>;闪存填充0x10001208 0xFFFFF00 0x01>;重置。

此后,任何连接CPU的尝试都将失败,并显示“Error:Can not find MEM-AP to control the core”(错误:无法找到MEM-AP来控制内核):

#read APPROTECTSTATUS#(0x0访问端口保护启用-0x1应用程序禁用)>;nrf52.dap apreg 1 0x0c 0x00000000#write ERASEALL register>;nrf52.dap apreg 1 0x04 0x01>;Reset。

在此过程中,所有闪存和RAM都会被擦除。复位后,可以再次对nRF52进行编程。

引导过程相对简单,因为nRF52840不包含bootROM代码(因此没有嵌入式引导加载程序例程,也没有用于反向工程…的iap/isp例程)。

到目前为止,这真的很简单。所有模块,如NVMC、存储器、调试访问端口…。完全在硬件中初始化。

在nRF52 SoC中,几个源可能会触发复位。下表汇总了所有重置源及其目标:

最后一行很有趣。上电重置将重置整个SoC,包括调试端口。

目标是重新启用对AHB-AP调试的访问,尽管有APPROTECT。

上电复位后,AHB-AP必须根据APPROTECT的值进行自身初始化,APPROTECT存储在UICR(专用闪存分区)中。

在启动期间,内存控制器(NVMC)必须与CPU(或直接与AHB-AP模块)通信,以提供存储在闪存中的APPROTECT值,然后相应地设置其保护状态。

由于没有BootROM,这是通过纯硬件实现的,必须在CPU开始加载和执行代码之前的早期引导过程中完成。

我将尝试识别这个“纯硬件进程”,然后尝试修改AHB-AP调试初始化。如果成功,调试功能将重新激活,直到下一次开机重置。

该系统包含两个不同的调节级,REG0和REG1。基于低压差稳压器(LDO)和降压稳压器(DC/DC),每个稳压器级有两个不同的可配置选项。

我对连接外部去耦电容器的DEC引脚(DEC1、DEC2至DEC6)特别感兴趣。北欧半导体没有提供有关nRF52电源网络的任何细节。

经过快速测试,我决定将重点放在DEC4(1.2V-1.3V)和DEC1(0.8V-0.9V)上:

DEC4是REG1阶段之后的功率。因此,它可能提供整个数字系统(CPU和存储器)。

要分析芯片内部的活动,通常需要稍微修改PCB:

我的低成本电压闪光灯是一个自制的硬件电子系统,致力于以适当的方式执行故障注入。该电路板的总成本不到5美元,证明了故障注入是一种成本很低的技术,可以由有限的黑客来实现。

我的低成本电压毛刺系统的输出将使用先前安装的SMA连接器连接到DEC1。

将一根红线焊接到DEC4,并将一根细线焊接到DEC1:

注:我在C5位置重新焊接了一个100nF的电容器,以便在启动过程中CPU功率有更多的“稳定性”。这并不是真正必要的,但它可以在意外的CPU崩溃的情况下提供帮助。

我将两条导线连接到SMA连接器,并使用GND点作为公共接地:

微型USB电缆用于为整个电路板供电。连接USBtoSerial电缆以显示来自应用程序(115200、8N1)的通用异步收发器消息。

CHANNEL3(CH3)=闪烁脉冲命令CHANNEL4(CH4)=芯片通过DEC4的功耗(示波器触发)。

我们的目标是确定功耗中的特定模式,这可能验证我之前的假设。

为此,监控DEC1上的CPU功耗(CH2)和DEC4上的系统功耗(CH4)。

首先,闪存活动可清楚区分(在触发T标记处),并对应于来自闪存的连续读取操作:

在下一个屏幕截图上,ARM CPU开始执行(触发标记后19us)。它在CH2(CPU功耗)上是可区分的:

然后,我决定通过比较两个电源信号DEC4和DEC1,集中分析以找出NVMC活动:

我非常确信此模式(红框)对应于存储器控制器将UICR值传输到内核(或直接传输到AHB-AP块),以配置调试端口(AHB-AP、CTRL-AP),并将APPROTECT设置为最终禁用调试接口。

Python脚本负责启动示波器、设置不同的毛刺参数并重置电路板。

开始毛刺活动,在DEC1电源线上产生非常短的脉冲,以特别针对先前识别的图案。

请注意在故障发生后系统的功耗是如何修改的。这就是你需要的结果。

在每次故障尝试之后,脚本将播放以下OpenOcd命令,以便转储整个闪存(仅在成功连接到AHB-AP调试接口的情况下才会发生此情况):

$openocd-s/usr/local/share/openocd/scripts-f./interface/jlink.cfg-c";Transport select SWD";-f./target/nrf52.cfg-c";init;dump_image nrf52_dumped.bin 0x0 0x100000";

AHB-AP调试端口被毛刺效应成功解锁。外部调试器现在可以连接到nRF52840 CPU(Cortec M4F)以转储闪存:

然后附加一个ARM GDB会话。即使APPROTECT值显示nRF52840受到保护(0xFFFFFF00),我现在也可以调试目标,例如通过读取0x00000000处的固件:

您可能会猜想,完全控制设备也是可能的(因为重新激活了调试界面)。

在我的实验期间,在故障之后,CPU在0x61C4处陷入死循环。因此,下面的屏幕显示了如何将程序计数器(PC)设置为执行第一条指令(在0x2b4),然后作为概念验证进入代码:

对寄存器的读/写访问如下(相信我,SRAM和闪存读/写操作也可用):

工厂信息配置寄存器(FICR)在工厂预编程,用户无法擦除。这些寄存器包含芯片特定信息(设备ID、密钥、设备地址…)。和位于0x10000000:

目标是永久重新激活基于nRF52 SoC的设备的全部调试功能。

再次刷新nRF52以写入闪存内容和UICR(当然,APPROTECT值的适当补丁设置为0xFFFFFFFF)。

此后,将永久启用SWD接口上的永久完全调试,不需要出现毛刺。

为了证明应用这个漏洞是多么容易,攻击已经在一个真正的产品上重现,我每天使用的罗技专业G鼠标。

这将是对nRF52 SoC的调查的第二部分。在这第二部分中,我还将演示此漏洞当前如何影响从nRF52810到nRF52840的所有nRF52SoC。

接入端口保护APPROTECT是北欧半导体为防止固件读出和反向工程而设计的最新安全功能。因此,整个nRF52 SoC系列都采用了此APPROTECT功能。

在这篇博文中,在nRF52840上成功实现了一次低成本的故障攻击。它允许具有物理访问权限的攻击者绕过APPROTECT永久重新激活SWD调试接口(对存储器和寄存器的读/写访问、控制中央处理器代码执行、转储闪存、FICR和UICR…)。

由于复杂度低,这种对nRF52840的攻击很容易在现场复制。我毫不怀疑,任何有动机的熟练黑客都可以在不到一天的时间里,用不到500美元的设备复制这种攻击。

该漏洞存在于Silicon中。没有硬件修订是无法打补丁的。这影响了大量基于nRF52平台的产品。

2020年4月28日:LimitedResults建议与北欧合作,基于CVE流程进行负责任的披露。

2020年8月6日:在一个月的沉默和几次北欧人没有任何回应的后续行动之后,北欧人拒绝与LimitedResults合作,以获得负责任的披露结果。