0x01 基础概述
故障注入是一种侧信道攻击技术,会将将某种形式的干扰或无效状态引入到系统中,以更改该系统的行为。通常,在嵌入式硬件和电子设备中,这种干扰可能有多种形式。电子设备中故障注入的常见方法包括:
- 时钟毛刺注入(错误的时钟沿被强加到IC的输入时钟线上)
- 电压故障注入(对IC电源线施加高于或低于预期电压的电压)
- 电磁干扰(引入电磁干扰)
本文将重点介绍电压故障注入,特别是目标设备电源正常工作条件之外的瞬时电压的引入。这些瞬时脉冲或输入电压下降(毛刺)会影响设备的运行,并达到特定的效果。通常期望的效果包括“破坏”指令或处理器中的存储器以及跳过指令。先前的研究表明,可以预见地实现这些效果,并且也对可能由各种行为引起的EM效果(由毛刺引起)提供了一些解释 。
但是,在将故障和相关的EM效应与处理器级别的具体状态变化(即,在导致指令被破坏或跳过的故障时刻,处理器中确切发生的情况)相关联方面,已发表的研究存在差距。本文旨在量化和限定处理器在注入故障之前,之中和之后的状态,并描述标记的离散变化,例如寄存器(包括通用寄存器)以及控制寄存器(例如$ pc和$ lr),内存。
特别感谢Toothless Consulting的同事,他的优秀博客文章系列是我对故障注入的介绍以及对该项目的启发。还要感谢克里斯·格林斯基(Chris Gerlinsky),他对嵌入式设备安全性的研究,特别是他关于打破LPC系列芯片上的CRP的演讲,是该项目中的宝贵资源。
https://toothless.co/blog/bootloader-bypass-part1/ https://recon.cx/2017/brussels/talks/breaking_crp_on_nxp.html
0x02 测试设置
选择进行测试的目标设备是NXP LPC1343,这是一种ARM Cortex-M3微控制器。为了控制输入目标电压并协调毛刺,使用了基于Xilinx Artix 7 FPGA的Digilent Arty A7开发板。为Arty板开发了定制的门控软件,以便于基于多种因素来控制和触发毛刺。出于本文的目的,使用的两个主要触发器是一条GPIO线,该GPIO线与某些设备操作同步地高/低,以及对应于“ step”事件的SWD信号。FPGA网关软件的源代码可[在此处获得](https://github.com/Ethan-ks/glitcherPlatform)。
https://github.com/Ethan-ks/glitcherPlatform
为了在标准电压电平(Vdd)和毛刺电压电平(Vglitch)之间切换,使用了Maxim MAX4617多路复用器IC。它能够在短至10ns的输入之间切换,因此适合在LPC 1343电源轨上以足够的精度和时序产生毛刺波形。
如上图所示,Arty A7监视“触发”线,即从目标输出的GPIO或目标与调试器之间的SWD线,具体取决于操作模式。当满足预期条件时,A7将根据提供的波形说明符将“毛刺消除”,通过电源多路复用器电路触发Vdd和Vglitch之间的切换,并将其馈送到目标Vcore电压线。Segger J-Link用于提供对目标的调试访问,并且SWD线也被馈送到A7进行触发。
为了方便触发任意SWD命令,在A7上实现了准系统SWD接收器。接收器解析从总线嗅探到的SWD事务,并输出反序列化的标头和事务数据,然后可以将这些值与预先配置的目标值进行比较。这允许基于任何SWD数据(例如S TEP和RESUME事务)触发glitchOut线,从而为单步指令提供了定时毛刺的方式。
在单步执行指令期间对故障进行任何直接测试之前,观察正常操作期间的故障及其引起的影响有助于提了解基本信息,并为假设提供平台,以便以后进行测试。为了提供观察各种形式和持续时间的故障注入结果的环境,程序执行包括一个简单的循环,递增和递减两个变量。在每次迭代中,将根据已知的目标值检查每个变量的值,并且当满足任一条件时,执行将跳出循环。在循环之外,将根据预期值检查这些值,如果这些值不同,则将这些值通过UART传输到攻击的PC。
使用Binary Ninja逆向软件提供了已编译C的可视化表示。由于所提供的程序集表示在编译和链接后生成的机器代码,因此我们可以确保它与处理器的行为完全匹配(忽略诸如并行执行之类的概念)。
尽管很简单,但此环境为故障注入提供了许多有趣的目标。循环中包含内存访问指令(LDR,STR),算术运算(ADDS,SUBS),比较和分支运算。此外,PIO2_6的脉冲为来自FPGA的glitchOut信号提供了触发信号,根据对该信号施加的延迟,可能会针对整个环路中的不同区域/指令。通过使用分流电阻器和传输线探针跟踪ARM内核的功耗,可以看到执行情况。
以下波形显示了GPIO触发线(蓝色),以及来自LPC的电源走线(紫色)。GPIO线先变高电平一个周期,然后变低,这标志着环路的开始。接下来是重复16次的模式,表示循环的16次迭代。这在任一侧上都由与用于将数据写入UART的代码相对应的电源迹线限制,并分支回到主循环的开始。
获取到了以下内容:
1. 处理器正在执行的实际指令的参考(通过Binary Ninja进行反汇编)
2. 该执行的可视化表示,可在处理器执行时实时查看(通过电源跟踪)
3. 一种在被测系统中采取措施的手段,可以根据处理器(FPGA干扰器)的行为进行校准。
使用以上信息,可以改变故障与触发器之间的偏移,并且可以(大致)将该时序与正在执行的给定指令或指令组相关联。例如,通过在电源轨迹上的模式的第六次重复过程中的某个时间触发毛刺,我们可以观察到电源轨迹的该部分似乎过早被切断,并且目标在UART上报告的值反映了某种循环的第六次迭代期间行为不当或损坏。
到目前为止,所采用的方法已与传统的故障注入参数搜索技术保持一致,使用设备操作中固有的某些行为(此处为GPIO线脉冲)优化系统可见性,以确定最有效的时序和毛刺持续时间。尽管这可以粗略了解成功注入的故障的影响(对于上面的示例,我们可以假设在循环的第六次迭代期间某个点的操作已更改,但更多的特异性只是推测),可能是跳过的加载指令,存储损坏或比较失败等其他可能性。
为了说明这一点,下面是运行外部循环几千次迭代的故障后,来自目标设备的UART流量的解析,排序和计数输出。毛刺延迟和持续时间保持不变,但在循环结束时导致离散状态对变量状态的影响相当广泛。有些条目很容易推论,例如第一个也是最常见的结果:B是六次迭代(16-6 = 10)之后的期望值,但是A是16,因此跳过的LDR或STR指令可能已经离开了通过先前的操作将寄存器中的值16放置在该寄存器中。但是,其他结果很难推理,例如包含ascii文本的条目或具有错误值的变量似乎与循环的迭代次数不相关的条目。
在故障注入的某些应用中,这种模糊程度是可以接受的,例如打破无限循环,就像在安全启动旁路技术中有时看到的那样。但是,对于更复杂的攻击,其中特定的操作需要以正确的方式进行破坏,因此必须具有更高的特异性,从而需要更精细的理解。
因此,接下来是本文进行的研究的创新部分:创建一种将错误注入攻击针对单个指令的方法,并利用SWD / JTAG等调试接口来实现指令隔离和计时。除了这项工作提供的研究价值外,在某些非常见的设备情况下,所开发的方法也可能具有实际应用,这将在后面的部分中进行讨论。
0x03 SWD协议概述
SWD是ARM开发的调试协议,用于调试许多设备,包括LPC 1343目标板上的Cortex-M3内核。从[ARM调试接口体系结构规范ADIv5.0到ADIv5.2](https://developer.arm.com/documentation/ihi0031/latest/)
https://developer.arm.com/documentation/ihi0031/latest/
Arm SWD接口使用单个双向数据连接和单独的组来同步传输数据。线路上的操作包括两个或三个阶段:数据包请求,确认响应和数据传输。
当然,还有更多的功能,但是就本文而言,我们真正感兴趣的是数据传输,这要归功于Cortex-M3调试寄存器的特殊情况:停止,步进和连续执行都得到了管理通过写入调试暂停控制和状态寄存器(DHCSR)。此外,对该寄存器的写操作始终以0xA05F为前缀,并且仅低4位用于控制调试状态-[MASKINTS,STEP,HALT,DEBUGEN]从高到低。因此,我们可以通过查找数据为0xA05F0001(RESUME)和0xA05F000D(STEP)的SWD写入事务来跟踪STEP和RESUME动作。
由于该协议具有上述双向性,因此它不仅仅与匹配位模式一样简单:根据是发生读还是写事务以及当前正在进行的是哪个阶段,数据可能在任一时钟沿有效。事实证明,最简单的解决方案是实现协议的一半,并摒弃不相关的部分,仅保留数据以进行比较。以下是SWD实现的Vivado ILA跟踪,该跟踪可以成功解析从SWD线嗅探到的STEP事务。
0x04 故障注入
因此,通过单步执行一条指令并从A7嗅探SWD线,就有可能在目标板的调试设备锁存数据的瞬间(或非常接近,在10ns内)触发故障。由于目标需要几个尾随的SWCLK周期来完成调试探针需要执行的任何操作,因此在锁存的数据与指令的实际执行之间有很大的摆动空间。实际上,由于有了电源跟踪,因此可以清楚地表明SWD事务完成之后处理器活动的开始。
从上面可以看出,在4us附近存在某个延迟,这是A7的100MHz处的永恒。通过将毛刺延迟到与指令执行相对应的“凸块”中的各种偏移量,我们终于可以做到这里要做的事情:毛刺单步处理器。
为了产生更有趣的结果!通过OpenOCD编写了一个简单的脚本来管理调试器/处理器的行为。该脚本有两种模式:一种是“快速”模式,它是调试器可以跟上的单步速度,用于查找故障的正确定时和波形;另一种是“慢速”模式,它检查寄存器和寄存器。在每个故障事件之前和之后都进行堆栈,突出显示任何意外行为。我们会看到一些有趣的结果,这些错误使最里面的循环的中间的加载寄存器指令出现故障,在这种情况下,LDR r3 [sp]将A变量的先前值加载到r3中,并在其中递增下一条指令。
我们可以看到没有任何变化,这表明这些操作根本没有发生或没有完成-一条跳过的指令。这可靠地导致设备的UART输出出现一对一的差异:由于inc / dec操作之一正在起作用,所以A / B的结果比循环结束时少1 /多,实际上与A变量的状态无关的数据。
有趣的是,这项研究表明,故障注入的有效性不仅限于访问存储器(LDR,STR等)的指令,还可以用于影响算术运算的执行,例如ADDS和CMP,甚至分支指令(尽管指令本身是否已损坏,或者在确定分支的ASPR上是否正在发生损坏,还需要进一步研究)。实际上,尽管成功率确实根据指令而有所不同,但没有针对本文进行测试的指令证明可以单步执行滑行。
我们在这里看到CMP指令,该指令确定A是否与预期的目标0x10相匹配。我们看到xPSR没有更新(这意味着未设置零标志,就处理器而言,CMP的值不匹配,因此A和B的值是通过UART发送的。)有趣的是,我们看到r1已更新为0x10,与原始CMP中使用的立即数相同。 CMP r3的机器代码为0x10,应为0x102b。考虑到所观察到的行为的可能解释,可以考虑使用一条指令,如LDR或MOVS,它们可能会将值移至r1寄存器中。
尽管这并不是导致观察到的行为的明确答案,但其猜测远远超出了通过功率跟踪分析和类似技术获得的信息水平。
0x05 研究总结
如果你可以通过JTAG / SWD调试器访问设备,就可以进行故障注入研究我最近读了一篇很棒的博客文章 ,学习了如何利用它获取一个JTAG接口!
https://labs.ioactive.com/2021/01/taping-stack-for-fun-and-profit.html
但是,对于嵌入式设备来说,存在一种非常普遍的配置,在这里提出的研究可能会证明对这种配置很有用。包括STM32系列在内的许多设备(例如本文的DUT)都实现了一种“高但不是最高”的安全模式,该模式允许有限的调试功能,但会阻止对某些内存区域的读写操作,使利用开放式JTAG连接的大量技术无效。之所以选择此选项,是因为更安全的选项是完全禁用调试,因为后者没有留下修复或更新设备固件的选项(没有自定义引导加载程序),并且许多OEM可能会选择转向可维护性而不是安全性。但是,在大多数此类实现中,仍然允许单步执行!
在这种情况下,借助设备固件的副本,类似于此处所述的探测设置或两者的结合,可能会使得原本耗时且繁琐的攻击变得几乎无足轻重,所有校准和时序参数化的条件通常是故障注入攻击所必需的。是否需要在部分锁定的设备上绕过安全启动?只要在CMP上中断一下即可检查is_secureboot_enabled()的返回值。
需要进行进一步的研究以对实时测试中该方法的适用性进行真正的分类,但是初步结果的确令人鼓舞。可能会在更现实/更实用的设备固件上执行进一步的测试,例如前面提到的安全启动方案。
此外,更直接的是,本系列文章的第二部分将继续致力于更好地理解集成电路在发生故障注入攻击时,特别是在复杂的集成电路(例如CPU)中发生的情况。在过去的几个月中,我一直在业余时间将74个系列离散组件中的8位CPU组装在一起,一旦完成,它将成为该研究的理想目标:外部时钟是可控/可步进的,每个模块都是独立的(示波器,ALU,寄存器等)(可通过标准示波器探头和其他设备访问)。
视频演示:
https://youtu.be/HYmDWs_sAhA
参考资料:
[1] J. Gratchoff, "Proving the wild jungle jump," University of Amsterdam, Jul. 2015
[2] Y. Lu, "Injecting Software Vulnerabilities with Voltage Glitching," Feb. 2019
[3] D. Nedospasov, "NXP LPC1343 Bootloader Bypass," Aug. 2017, https://toothless.co/blog/bootloader-bypass-part1/
[4] C. Gerlinsky, "Breaking Code Read Protection on the NXP LPC-family Microcontrollers," Jan. 2017, https://recon.cx/2017/brussels/talks/breaking_crp_on_nxp.html
[5] A. Barenghi, G. Bertoni, E. Parrinello, G. Pelosi, "Low Voltage Fault Attacks on the RSA Cryptosystem," 2009
本文翻译自:https://labs.ioactive.com/2021/04/watch-your-step-research-into-concrete.html如若转载,请注明原文地址: