STM32F1系列芯片可以配置读保护,从而保护Flash中的代码,增加读保护之后无法从调试接口(JTAG/SWD)读取Flash数据,一旦解除读保护,芯片内部逻辑则会立即擦除整块Flash,从而达到保护代码的目的。

CVE-2020-8004这个漏洞则可以从读保护的芯片中读出89%的Flash数据。

在此只阐释最小的依赖知识和核心原理,基础知识请自行参考《Cortex-M3权威指南》。

前置知识

中断向量表

中断向量表存储着各个中断处理函数的内存地址,在系统发生中断时,CPU内部逻辑会自动将中断向量表中的数据(也就是中断处理函数的地址)装载到PC(当然还有一系列的自动保存寄存器上下文操作)。

Cortex-M3中的VTOR寄存器存储着中断向量表的地址,上电启动时VTOR寄存器默认为0x08000000,即Flash基地址。在程序运行过程中,可以通过配置VTOR寄存器重新定位中断向量表,典型的场景为从bootloader跳转到firmware执行,则需要切换中断向量表从而切换到新的异常处理。

读保护

为了保护固件的安全,stm32系列芯片可以对Flash配置成读保护和写保护。

读保护:Flash中的数据无法通过调试接口(JTAG/SWD)读取,也无法通过SRAM中的程序读取Flash。读保护有三个等级L0,L1,L2,L0即没有读保护,L1为可恢复读保护,L2为不可恢复读保护。通常最常见的为配置成L1可恢复读保护,在此种模式下,用户一旦解除读保护,则芯片内部逻辑会自动擦除所有Flash数据,从而保护代码。

写保护:以page为单位,可对page添加写保护,从而保证数据不会被异常更改,一般不常用。

中断环绕

STM32F1 共有 43个外部中断,加上16个内部异常,总共59中断向量。内部异常中除去0号向量(栈指针)1号向量(复位),以及另外5个预留的异常向量,总共7个。59个中断向量向上取整到64,这意味着有5个外部中断向量是预留的,故整个中断向量表有12个向量是无法读出的。

若通过普通中断向量触发的方式,这12个向量永远无法触发而读出数据。然而通过中断环绕,可以让我们触发出所有12个向量,从而读出更多的有效数据。

正常来说VTOR的地址需要如下方式对齐:

59个中断向量向上2幂次取整为64,每个中断向量4Bytes,64 * 4 = 256,VTOR需要256字节对齐,即放置在0x0、0x100、0x200....地址处。然而若放置在128字节对齐地址处,则会发生中断向量环绕。环绕的意思就是此时中断向量表里只能容纳32个中断向量0, 31,假若触发32号中断,则产生环绕会进入和0号中断向量同一个的中断入口,而0号中断向量默认是栈指针,原先是根本无法触发的,现在则可以通过触发32号中断的方式触发。

不过通过中断环绕,切换中断向量表到非256字节对齐的地址(128字节对齐),只能多读出一些数据,若中断向量表在256字节对齐的地址,保留向量仍然是无法读出的。

CVE-2020-8004-读保护越过原理

在读保护模式下,虽然通过调试接口(JTAG/SWD)无法访问Flash,然而却可以访问寄存器,包括CPU寄存器R0-R15,NVIC寄存器,亦可读写SRAM空间,甚至可以在SRAM中执行部分指令,这就留下了足够的想象空间

以前也曾经尝试过将访问Flash的指令放在SRAM中执行,也试过执行被读保护的Flash里的某些访问Flash的指令,然而一旦执行,系统则会立即HardFault,这种常规的指令执行的方式应该早就被内部逻辑做好访问控制了。

CVE-2020-8004 则另辟蹊径,巧妙的使用了中断触发实现了Flash数据的读取,简单来说,就是不断的切换中断向量表在Flash中的位置,通过触发中断(异常和外部中断都可以通过执行SRAM中的特定指令和配置NVIC寄存器实现触发相应的中断),CPU逻辑自动从中断向量表里装载数据到PC寄存器中,然后读取PC寄存器即可获取出Flash中的数据

此时中断向量表可看成一个数据窗口,通过配置VTOR寄存器切换窗口基地址,用窗口扫描整个Flash区域,再通过PC寄存器这个特殊的通路,即可dump整个Flash的数据。

不过由于中断向量表中存在保留条目,尽管通过中断环绕可以多读出一些数据,每256字节仍然有28字节是无法读出的。然而其他有效数据包含的指令和变量、字符串泄露出来的信息或许足以造成足够的影响。

标记为ff即为保留向量无法读出

如何测试

请参考 https://github.com/wuxx/CVE-2020-8004.git

参考资料

  • https://blog.zapb.de/stm32f1-exceptional-failure/
  • https://gitlab.zapb.de/zapb/stm32f1-firmware-extractor/
  • https://github.com/wuxx/CVE-2020-8004.git
  • 《Cortex-M3权威指南》