在STM32F4微控制器上进行电压故障注入

文摘   2024-07-15 18:16   上海  

绕过读取保护,从STM32微控制器中提取固件。

概览

     这篇文章是关于STM32F4系列微控制器的电压毛刺攻击的研究报告。旨在提供一个执行电压毛刺攻击的实践案例,同时也讨论了在这个过程中可能遇到的挑战和限制。


电压毛刺攻击

     故障注入攻击包括故意向系统引入控制或有目标的故障,使系统出现异常行为,但又不至于导致严重的故障。电压毛刺攻击是针对系统的电源供应。这里的目标是在特定时刻精确地操纵目标系统的电源,使系统出现诸如跳过指令、破坏内存和寄存器内容等异常行为。

     从安全角度来看,这可以被用来绕过安全机制,例如安全调试访问、访问受保护的内存、提取密钥、认证绕过等。


目标描述

STM32F4系列

     STM32F4https://www.st.com/en/microcontrollers-microprocessors/stm32f4-series.html)系列微控制器是由STMicroelectronics开发的流行嵌入式系统处理器系列。以其高性能、低功耗和丰富的外设集成而闻名,STM32F4微控制器广泛应用于工业自动化、消费电子、汽车系统和物联网设备等多种应用场景。

     本研究使用的目标设备是STM32F401CCU6最小系统STM32 ARM核心板,它包含一个STM32F4系列微控制器。目标详细信息如下:

Model: STM32F401CCU6.Core: ARM 32 Cortex-M4 CPU.Debug mode: SWD.84MHz work frequency.256K flash memory, 64K SRAM.


STM32技术细节

Boot Process and Boot ROM

      Boot ROM是微控制器内部的初始代码,在启动过程中执行。这些ROM包含负责初始化基本硬件参数和设置的固件代码,如内存配置、安全配置(选项字节)和启动模式。

Boot ROM在微控制器的初始引导过程中起着至关重要的作用,确保在将控制权交给主应用程序代码之前进行适当的初始化。它们是微控制器启动序列的组成部分,帮助建立稳定和功能性的操作环境。

     Bootloader存储STM32设备的内部 Boot ROM(系统内存)中,由STM在生产期间编程。其主要任务是通过可用的串行外设之一重新编程Flash存储器。关于STM32引导加载程序的更多细节可以参阅AN2606:Application Notehttps://www.st.com/resource/en/application_note/cd00167594-stm32-microcontroller-system-memory-boot-mode-stmicroelectronics.pdf


Enabling Bootloader

     STM32F4拥有一组专用的I/0 引脚,称为启动引脚(Boot Pins)。这些引脚用于确定启动选项。STM32微控制器中的Boot ROM会检查启动引脚上预定义的逻辑电平,然后据此启用引导加载程序。在STM32F4中,可以通过在启动引脚上设置一个特定的模式来激活引导加载程序,具体模式如本文件https://www.st.com/resource/en/application_note/cd00167594-stm32-microcontroller-system-memory-boot-mode-stmicroelectronics.pdf中所述。


STM32 Bootloader 特性

     STM32 Bootloader  支持USART协议,并提供了许多功能。这个引导加载程序支持应用程序说明https://www.st.com/resource/en/application_note/cd00264342-usart-protocol-used-in-the-stm32-bootloader-stmicroelectronics.pdf中描述的大量命令。


     我们特别关注的是读取内存命令,因为它有助于转储MCU的闪存内容。然而,该读取命令有一个限制——它只能从特定内存地址位置获取256字节的内存。

STM32安全概述
     STM32微控制器提供了这里(https://www.st.com/resource/en/application_note/an5156-introduction-to-security-for-stm32-mcus-stmicroelectronics.pdf)描述的大量安全特性。STM32 mcu还提供了一种称为读出保护(RDP)的安全机制,以防止未经身份验证的访问闪存内容。STM32提供了一组特定的Option Bytes来配置MCU的安全设置。Option Bytes主要用于在启动Cortex®-M和用户代码之前在芯片上预配置系统。它们基本上代表了允许用户自定义微控制器的一般设置的方法。
     STM32F4提供了三个级别的读取保护(https://www.st.com/resource/en/application_note/dm00186528-proprietary-code-readout-protection-on-microcontrollers-of-the-stm32f4-series-stmicroelectronics.pdf)


RDP0

     这是默认级别,在此模式下没有保护。

RDP1

     在RDP1级别下,无法访问闪存。通过SWD或JTAG读取、编程和擦除闪存也被禁用。任何对受保护闪存的读取请求都会生成总线错误。在此级别下,可以从SRAM或系统引导加载程序启动。

RDP2

     在这一级别,芯片完全受到保护。所有选项字节都被冻结且不可修改。JTAG、SWV(单线查看器)、ETM和边界扫描均被禁用。从SRAM或系统内存引导加载程序启动不允许。

     RDP级别总是可以升级。从RDP1降至RDP0可以通过重新编程选项字节完成,但这会导致闪存、SRAM和备份寄存器的大规模擦除。RDP2级别是不可逆的,不能降级。

STM32电源管理/调节
     了实施电压毛刺攻击,我们需要瞄准MCU的电源供应。每个MCU都有专门设计的电源管理和调节系统,用于供电给内部电路和外设等。STM32的电源供应方案如下图所示。

     从供电方案中可以清楚地看出,我们需要针对稳压器将故障注入电源轨中。VCAP_1和VCAP_2引脚使我们可以直接访问内部电源轨。

瞬变设置
     正如前面所述,我们的研究使用了STM32F401CCU6 Minimum System STM32 ARM Core Board(https://robu.in/product/stm32f401ccu6-minimum-system-board-microcomputer-stm32-arm-core-board/)作为研究对象。

硬件设置

     系统中通常会有设计来维持其操作电压在适当水平的组件,比如去耦电容器。本方法的一个挑战/要求是对硬件电路进行修改或篡改,以克服这些组件提供的保护。这包括移除一些组件,替换为定制组件,以及选择瞬变注入点。

     我们选择了VCAP_1作为瞬变注入点。去耦电容器被替换,这会增加我们瞬变对目标的影响。一个定制的电压瞬变注入电路,包括电容器、电阻器和MOSFET,被创建以确保精准的瞬变注入。每个组件都是经过详尽研究后精心挑选的,以确保电路能够可靠地提供所需的瞬变。

     我们使用Teensy开发板来开发我们的毛刺软件,这将帮助我们控制毛刺并精确注入所需毛刺。

     我们后来在一篇文章(https://sec-consult.com/blog/detail/secglitcher-part-1-reproducible-voltage-glitching-on-stm32-microcontrollers/中找到了这个问题的解决方案,但当时我们已经开始了一种不同的方法。

     研究中使用的硬件设置如下图所示。

     Teensy开发板通过串口与目标的UART端口通信。它还控制瞬变注入电路,以便精确地注入瞬变。我们把瞬变注入电路的输出焊接到了VCAP_1引脚上,确保瞬变的损失最小。在“启用引导加载程序”部分提到的逻辑电平被应用到启动引脚上,使目标进入引导加载程序模式。

软件设置

     ST-Link V2编程器被用于通过SWD接口连接到目标。我们使用STM32Cube IDE编写了一个示例程序并将其烧录到目标中。我们从闪存中获取了数据转储,以便稍后验证结果,下面是一个转储的快照。

启用RDP1前的固件转储

     接下来,我们使用STM32CubeProgrammer在目标上启用了RDP1。STM32CubeProgrammer允许我们编程STM32微控制器的选项字节。RDP1可以通过设置除了0xAA和0xCC之外的任何值来启用。

在目标上启用了RDP1

瞬变软件

     由于我们的目标是转储固件,如前(https://jerinsunny.github.io/stm32_vglitch/#stm32-bootloader-features)所述,我们将针对读取内存命令(0x11)。正如这里(https://jerinsunny.github.io/stm32_vglitch/(https://www.st.com/resource/en/application_note/cd00264342-usart-protocol-used-in-the-stm32-bootloader-stmicroelectronics.pdf))所描述的,当接收到读取内存命令时,设备会检查是否设置了任何RDP级别,并根据这个决定是否提供对闪存的访问。如果RDP处于活动状态,设备会对读取内存命令返回NACK字节;否则,设备返回ACK字节。

     瞬变软件执行以下操作:

send_read_memory_command()inject_glitch(glitch_parameters)result= read_response()if result == ack:  # RDP1 Bypassed  data = read_265K_from(address)  # memory read successful  print(data)elif result == nack:  #Print RDP1 active  send_read_memory_command()


毛刺攻击目标

     一旦硬件和软件都设置完毕,我们开始运行初始表征过程以获取瞬变参数。从所做的表征测试中,关键的瞬变参数是瞬变偏移量和瞬变宽度。瞬变偏移量决定了何时注入瞬变,而瞬变宽度则确定了瞬变的持续时间。我们通过示波器观察瞬变,以此关联软件设定的瞬变参数与实际产生的瞬变效果。基于每次运行后所获得的表征结果,逐步优化瞬变参数。

观察触发与瞬变参数

Note

     值得注意的是,在优化瞬变参数的过程中,我们发现尽管读取内存命令收到了肯定的应答(ACK),但在对比数据时,我们仅读取到了零数据,如下面所示。这意味着虽然成功绕过了RDP1保护级别,但我们并未能真正读取到数据。

     进一步分析后,我们发现电压瞬变过程中无意间设置了PCROP(即SPRMOD选项字节)。这表明我们需要更精细地调整瞬变,以防在瞬变过程中意外设置PCROP。



     我们手动清除了PCROP位,将RDP级别退回到RDP0,然后重新进行了整个软件设置,并重启了整个过程。


毛刺成功

     在精细调整瞬变参数后,最终我们成功实现了瞬变,并读取到了一些数据,如下面所示。为了验证我们的结果,我们将输出数据与在启用RDP1之前的原始转储进行了比对。


     正如上文解释,单一的读取内存命令只能在读取下一数据块前读取256字节的数据。鉴于目标的闪存大小为256KB,总共需要1024次成功的瞬变才能提取整个闪存的内容。我们保持瞬变设置运行,直到整个固件被提取为止。

     大约经过22小时,以及在总共621594次尝试中成功了1024次瞬变之后,整个固件被成功提取,如下面所示。





安全脉脉
我们致力于提高车联网安全的意识,推动行业发展,保护车辆和驾驶者免受潜在威胁的影响。在这里可以与车联网安全领域的专家和爱好者分享知识、深入思考、探讨标准法规、共享工具和讨论车联网热点事件。
 最新文章