2020 看雪SDC议题回顾 | 敲开芯片内存保护的最后一扇“门”

发布者:Editor
发布于:2020-11-02 15:30

随着传感器技术、无线通信技术的迅速发展,越来越多物联网产品渗透进我们生活的方方面面。


但无处不在的物联网设备也可能成为无所不在的安全隐患。


其中,设备中芯片固件的安全性是最不容忽视的问题之一。芯片固件相当于是设备内部保存的设备“驱动程序”,任何操作系统都要通过固件才能按照标准的设备驱动实现特定的运行动作。因此芯片固件的安全与否,直接决定了操作系统能否正常运行。


内存保护芯片作为守卫所有设备数据和安全的最后一道防线,应当引起所有安全工程师和开发者的高度重视。


下面就让我们来回顾看雪2020第四届安全开发者峰会上《敲开芯片内存保护的最后一扇“门”》的精彩内容。


演讲嘉宾




付鹏飞,阿里云安全IoT平台高级安全工程师,主要负责阿里云IoT平台亿万级设备连接云平台的安全。曾任职知道创宇,联想全球安全实验室的安全研究员主要方向为IoT安全,硬件安全。


演讲内容



以下为速记全文:


大家下午好,我是来自阿里云IoT安全的付鹏飞,今天带来的议题是《敲开芯片内存保护的最后一扇“门”》,主要是针对于开启读保护后,芯片的一个防护突破吧。


自我介绍这块主持人已经说了,我个人平时比较喜欢DIY硬件,议题中也会提到很多自己设计的工具。对于这些工具,我是有开源的想法的,现在还在走流程,最后会开源给大家,让大家一起使用。


今天议题主要会讲四个方面。第一部分是常见芯片固件的提取,主要会介绍EEPROM、Flash之类的常规内存芯片的正常提取,还会介绍一下MCU和SOC的基本架构。第二部分是芯片内存保护攻击方法,主要是通过芯片Flash调用的过程,根据各个过程中暴露出来的弱点对其攻击方法进行描述。第三部分为大家介绍一个比较低成本的侧信道攻击方案,还有一些我自己设计的工具。第四部分是芯片内存防护方案,主要会说一下市面上比较常见的几种方案。



一.常见芯片固件提取


第一个就是常见内存芯片的固件提取,这张表主要是把现在常见的几种芯片的提取过程和提取工具都列了一下。其中,EEPROM和Flash都有常见的提取工具。而MCU和SOC之间,当它没有开始读保护的时候,也有一些特定的编程器让大家可以把固件提取出来。


今天主要给大家讲的就是在开启读保护的情况下,如何读取MCU和SOC这两类芯片的方法。


这是我自己设计的一个工具,主要是适配树莓派和一些开源软件。它主要会覆盖硬件协议UART、I2C、JATG、SPI等,使用这些硬件协议的芯片都可以用这个工具去做一个内存的提取。



这是现阶段比较常见的MCU主要架构,大家可以看到它的整个架构都是以总线控制为基础去控制各个资源单位的。黄色部分就是一个整体Flash调用过程,主要是通过SWD或JTAG进行内核调用,内核通过地址总线和数据总线,进行总线的一个调用,总线再去调用整个flash。这就是一个基本的过程。



这是SOC的主要架构。SOC的本质实际上就是在MCU的周围有一些特定场景的设计,主要的应用场景来自于蓝牙和Wifi芯片。现在市面上比较常见的集成芯片一般都是SOC架构的。


MCU和SOC内存保护的主要方式是配置字加密,主要是从内存中选择一个字段,通过配置这个字段起到内存保护的作用。这个字段主要的功能会禁止我们调试,也会禁止除Flash正常执行程序外的其他Flash操作,并关闭所有非正常执行的Flash指令。



二.芯片内存保护攻击方法


在第二部分我会重点给大家说明一下我们如何绕过读保护,在芯片整个Flash调用过程中存在哪些问题,以及我们可以用哪些方法把Flash里面的信息提取出来。


整个Flash的调用过程,主要分成三个方面,调试接口、数据总线和总线控制。


第一方面调试接口这块,我们用到的主要方法是通过调试总线的仲裁利用。关键调试接口信息主要是针对于SWD、JTAG调试总线的一个问题。



这是SWD总线的基本架构,大家可以看到,在DAP总线中会有三条总线去对内核进行调用,进行调用的时候主要是对JTAG和内存的调用。在调用的过程中,如果内存是第一个触发调用状态的话,会从内存中拉取部分内存数据出来,所以我们主要是要观察针对于调试接口的监控,并判断芯片启动之后,连接协议连进去之后要干什么,是访问内存还是要进行调试。


这是我针对于此设计的一个工具。这个是硬件工具,主要兼容开源的J-Link最新版V9,还覆盖JTAG、SWD等芯片总线的调试,并可以进行SWD等协议的自主开发和调试。


自主开发这一块,我们最需要注意的几个点是,首先要打印详细的报错日志。因为在详细的报错日志中,我们发现有一款芯片在进行调试的时候,芯片启动并访问内存的时候,它会从内存里面携带出一部分内存的数据出来,利用这个就可以不断从内存中调取数据,不断触发设备发生中断。


其次,我们还要修改SWD初始化状态。因为只有修改初始化状态才能改变它仲裁的规则还有读取系统的配置,能帮助我们更好地去下断点。


然后,还要注意Flash的锁定提前触发,这主要是为了监控即时总线的仲裁。每次要保证总线访问内存是第一个触达的,就可以把整个思路利用起来。我们重启设备之后,会进行一个调试协议的初始化,在协议初始化的时候,保证每次总线都是率先去访问内存的。此时它就会把内存的一段数据带出来,不断循环的过程就会把整个Flash里面的内存数据都携带出来。


第二方面主要是针对数据总线这一块。我们的内核在访问总线控制这块主要是地址总线和数据总线这两部分。



但是有些芯片在设计初期就缺失了一部分的协议控制。比如说这一块,我们看到这一块芯片的整个系统设计。大家可以看到在总线控制这块,只有数据主线到达了总线控制,地址总线是可以直接访问Flash的,这就造成了我们访问Flash的时候有两种途径的存在。


配置自加密就是读保护作用在总线控制这个区域会把地址总线的访问路径开启。我们就可以利用这个从内核到地址总线,再到Flash控制器再到Flash,把整个Flash一个字节一个字节地提取出来。



这是地址总线上复位向量的利用。它是一个ARM架构下中断的向量表,我们每次都可以精准触发芯片产生中断,通过PC指证的方式从Flash内存里面把内存的数据导出来。然后,这是整个实现的POC,就是如何去触发芯片异常的POC。


第三种方式就是总线控制这一块存在的问题。总线控制这块,由于权限控制不干净,会有一些异常的寄存器暴露出来,我们通过去观察寄存器的状态,去查看寄存器数值的变化。具体的方法是这样的,使用调试器访问控制权限,跳到受保护内存的一个指令,然后执行该指令。指令会把受保护的数据携带到CPU寄存器中,可以用调试器把CPU寄存器里面的数据读取出来,每次精准地跳到Flash里面指定的一个内存地址里,就可以把整个Flash数据一步一步迁移出来。



这是一步一步调试芯片的过程。主要是我们初始的时候会重置CPU,重置后查看初始化寄存器的值以后单步执行代码,因为每次单步执行,寄存器都会发生变化。我们去对比寄存器的变化,就能查看到控制权限不足的寄存器,最后通过这个寄存器把所有的内存值反推出来。这是我们实现的一个POC的结果。


需要注意的是,整个Flash的调取过程中,三个关键的部分都会存在一定的风险。这种风险的存在主要是因为某些厂商权限控制不完善,和设计上存在缺陷导致的。那有没有一种通用的方法去帮我们更简便地绕过这种读保护呢?这里肯定会提到大家经常用到的侧信道攻击。



三.低成本侧信道芯片攻击


侧信道攻击最主要的是寻找攻击点。在芯片的攻击点中,大家可以看到,这是芯片Bootloader激活启动的一个流程。在它启动过程中,大家可以看到2、3步会判断我这个芯片是否启动了读保护,判断是否可以去调试这个芯片。



整个激活的过程实际上就是一个硬件初始化的过程,在2、3步的时候,我们是否可以直接从第1步跳到第4步?这样我们就可以跳过读保护的判断,直接进入芯片调试的过程。


如果把刚才的流程图反映在实际侧信道功耗的攻击上,可以看到黄色线是芯片复位重启的过程,绿色的线就是功耗的过程,在我标红色位置的地方可以看到绿色线有明显的功耗变化,这是我们的一个注入点,用到的方法主要是VCC注入,学术上叫电压故障注入,主要的特点是使用超压或欠压的方式,让CPU处在一个短暂的休眠期。



因为超压和欠压,整个CPU会运行不正常。在启动过程中有短暂的运行不正常的话,侧信道防护做得不好的芯片会忽略掉这个,并且会按照硬件初始化的状态继续往下走,就会存在跳过的风险。而VCC注入的整个过程的时间要控制在百纳秒之内,但一般我们都是控制在微秒的。


VCC注入第一个关键点是要进行电源域的确认,确认内核的供电方式。内核的供电方式决定于我们注入的点在哪。我们使用芯片本身的供电的话,一般注入不会成功,因为芯片本身供电会有其它资源重启的过程,而不是说单作用于内核。所以我们确实需要关注一下电源域的确认过程,主要是要收集数据表,确认电源域的情况,特别是内核电源域的情况,确认电源稳压器引脚,并确定VCC注入点和功率观察的引脚。



至于我们在攻击之前要准备的东西的话,主要要准备的是控制器。控制器这块推荐大家使用FPGA,或者其它的开源硬件也可以,但是要注意的是工作频率,因为你注入的控制器的工作频率一定要大于等于被注入的工作频率。比如说我这个芯片被注入的工作频率是16兆,我们注入的控制器就要大于等于16兆,我们要比控制的芯片跑得快,只有跑得快才能抢先把错误的信息注入进去。


还有引脚切换非常重要。我刚才说过,我们主要的攻击途径就是过压或欠压,过压、欠压的控制方式就是引脚切换,而且实际上整个的控制核心就是在这一块,能起到切换电压的作用。


但是需要特别注意的是千万不要用芯片本身的引脚直接去切换供电。做过嵌入式开发的都知道,我们是可以用代码去控制芯片的高电平或低电平的。那个高电频或低电频,它的功率不够,而且电流非常小,千万不要用引脚直接去控制,而是要用一个转换器去转换,利用稳压器去供电。还有信号发生器主要是去诱发芯片注入的过程。而示波器主要是观察注入的情况。


抛开这些,为什么说低成本呢?信号发生器、稳压器、示波器,这些都可以不要,事实上我们用控制器和引脚切换就可以达到目的。



这是我自己设计的一个注入板,主要的能力是进行VCC的注入分析,也可以进行自主的二次研究,主要覆盖线性启动芯片的VCC注入攻击。我看了一下,市面上占比比较大的芯片都是可以用这种方法的。



这是整个低成本侧信道攻击的架构图。信号发生器主要作用是启动延时,芯片覆盖之后会触发信号发生器,信号发生器会把触发的指令发给示波器,示波器再把信号的结果反馈到注入系统。刚才说了注入系统可以用FPGA,也可以用我们自己设计的都可以,只要是大于等于你被注入的MCU和SOC芯片的工作频率就可以。


大家可以看到,在这一块主要的核心在稳压器。一般我们用的是低压,就是欠压的方式,在1.250左右。一般不用过压的方式,因为容易把芯片烧掉。而PC这一块主要作用是进行自动化的控制。



大家可以从这张图看到,当我们真正地发生注入的波形的时候,会看到下面功率的明显变化。这是一个注入成功的波形,黄色部分发生注入成功的时候,绿色部分功耗的位置会有明显功耗的变化。


我们在进行自动化控制的时候,最主要的关键点在于设置毛刺的延迟和宽度、测试范围、芯片复位初始化、触发毛刺的效果,还有就是连接调试器的时候要始终去查看是否已经可以调试内存了,一旦发现已经可以调试内存了,证明我们已经把读保护越过了。还有就是在崩溃的时候如何合理的去重置芯片,一般我们会把复位引脚直接拉低,拉低再拉高,对它进行复位。但是这种方式一般效果不会很好,所以我们会直接断电,断电之后效果好一些。


上面我介绍了四种方法。我把这四种方法全部集成到一个PCB板上了,它主要是覆盖了现在市面上常见的一些QFP48和32封装的芯片,可以进行自动化的分析。刚才提到的是BGA封装的,BGA封装的只是我们要把QFP这个封装的换掉,换成BGA的。这个也是可以覆盖的,只是多一道程序罢了。还有就是它也支持USB调试以及芯片固件的二次开发和修改,主要覆盖常用的MCU和SOC的芯片。



四.芯片内存防护方案


第四部分我介绍一下芯片内存防护方案,主要介绍嵌入式开发时比较常用的一些。没有给大家介绍一些比较成型的产品,是因为这种产品一般都不是开发所设计的,开发还是比较关注于我们如何快速地去做这个事情。


第一个方案针对芯片本身信号离散的特性。因为我们整个板子上会用到电容器、电阻、二级管这些模拟电路、数字电路的器件,一般在不焊接上去的时候,它的信号是离散的,一旦放在了板子上它的信号有时候是有规律可寻的,是稳定的,可以通过这种信号的方式对芯片进行加密。它的优点在于使用简单、成本低,缺点是场景比较特殊,因为我们需要去找芯片本身具有离散特性的器件。


第二个方案就是针对芯片本身序列号不可篡改。这个序列号本身不可逆且唯一,对序列号的加密方式优点在于没有成本,缺点在于加密程度不高。


第三种方式是现在大家比较认可的,而且安全程度比较高一点的,就是用硬件边界的方式进行隔离,加一块SE在里面,主要对数据流和业务流进行一个隔离。这种方式主要的优点是可以实现以芯片为边界的硬件隔离,缺点就是成本太高。



最后,这是我们一个还在不断优化的方案,主要是使用低成本序列号的加密验证方式,去对不同的数据和业务流程进行分块的软件隔离方法进行一个加密,最后再进行MCU的验证。这样既能节约成本,又能提高加密强度,还能实现软件之间的相互隔离。


那么我今天的演讲就到这里,谢谢大家!



本届峰会议题回顾


2020看雪SDC议题回顾 | 逃逸IE浏览器沙箱:在野0Day漏洞利用复现

2020 看雪SDC议题回顾 | LightSpy:Mobile间谍软件的狩猎和剖析

2020 看雪SDC议题回顾 | DexVmp最新进化:流式编码

2020 看雪SDC议题回顾 | Android WebView安全攻防指南2020

2020 看雪SDC议题回顾 | 生物探针技术研究与应用

2020 看雪SDC议题回顾 | 世界知名工控厂商密码保护机制突破之旅

……

更多议题回顾尽情期待!!



注意:关注看雪学院公众号(ikanxue)回复“SDC”,即可获得本次峰会演讲ppt!

其他议题演讲PPT,经讲师同意后会陆续放出,请大家持续关注看雪论坛及看雪学院公众号!



- End -



 


声明:该文观点仅代表作者本人,转载请注明来自看雪