UEFI安全浅析

前因

在Legacy BIOS时代,对于BIOS的保护一直是一个让业界头疼的问题。根据计算机系统的设计,CPU上电就会加载内存地址为0xFFFF-FFF0处的代码,而这正是BIOS的内存映射代码,即CPU执行的是BIOS芯片上代码,BIOS通过南桥,将自己的代码映射到CPU的内存地址的0xFFFF-FFF0处,然后BIOS开始进行一系列的硬件初始化(如内存探测)和硬件检测,如果各硬件状态都正常,则开始加载系统的MBR(主引导记录),开始引导操作系统的启动。从整个启动过程中我们能看到,在BIOS被CPU执行之前并没有任何的验证机制来保证BIOS中的代码是未被篡改过的,不是非法的。显而易见,BIOS是被直接显露在外的,没有任何防护而言,而且权限极高,在BIOS的初始化过程中就可以执行很多非法的代码。

在一开始的时候,BIOS被写在EPROM中,但是由于EPROM只能通过紫外线才能擦除,因此更新BIOS是一件非常困难的事,这给厂商带来了很多不便,不利于BIOS的功能扩展,后来BIOS被写到EEPROM中,通过对指定引脚加上高电压即可擦除,在更新BIOS变得方便的同时,也给攻击者带来了可乘之机,可以随意的修改BIOS的代码,做各种非法的操作。BIOS遭受过很多病毒的攻击,而且BIOS病毒都有一个特征,就是通过重装操作系统无法被清除,非常顽固,更有甚者,直接导致无法正常进入操作系统。其中非常著名的就是1998年源自台湾的CIH病毒,它破坏硬盘数据,导致系统无法正常启动。据统计,CIH病毒在全球共感染了6000多万台电脑,造成了巨大损失;再比如2011年的BMW, 比CIH更具有破坏性,不仅破坏了BIOS,还能修改MBR,在Windows系统中加载恶意代码,使之成为黑客的“肉鸡”,被远程控制,还会遭受窃取文件,盗号等各种攻击。有兴趣的同学可以自行 了解一下它们的破坏性有多大。总之,BIOS的安全问题引起了包括BIOS-IBV,CPU厂商,操作系统厂商等所有业内企业的重视。

在前面的系列文章中介绍过,UEFI得以发展并快速被业内所认可和推广,其中很重要的原因就是由于Legacy BIOS存在诸多方面的不足,不仅仅是功能扩展的局限性,也包括“0”安全性,在BIOS的设计框架下没有任何有效的防护手段能阻止BIOS病毒和木马的攻击,除非不让写,但这又给BIOS-IBV带来了易用性和扩展性的限制。

UEFI安全机制

UEFI的安全保护机制,可以保证UEFI的代码在IBV发布之后不会被篡改,并且只有IBV能更新UEFI的固件;UEFI还定义了Secure Boot,Secure Boot作为UEFI的一个重要功能,同时也能保证系统能在安全信任链的多重保护下启动系统,避免受到BIOS病毒的攻击,从源头上保证系统引导过程的安全。

UEFI自我验证

关于UEFI自身的安全保护,在UEFI启动的整个过程中,分为了6个阶段,在系列的上一篇文章《UEFI运行原理》提到过,在每个phase最后会加载下一个phase的模块并传递参数,而在这之前,可以先验证下一个phase的代码完整性,至于验证方式,有很多种方式,标准规范中没有定义验证方式,这是其一;其二,UEFI定义了两种模式,Setup Mode和User Mode,只有在Setup Mode时,UEFI才允许被随意写入,而在User Mode模式下,只能通过特定方式写入。

在PC出厂之前,UEFI处于Setup Mode模式,此时OEM可以写入UEFI应用程序,数据库文件等内容,在写入UEFI数据后,UEFI将从Setup Mode变成User Mode,此时UEFI将不被允许随意写入。

出于UEFI更新固件的需求,在User Mode模式下(在这里可以理解为用户终端),也是可以进行UEFI数据写入的,不过需要通过特定的方式写入。

UEFI在出厂之后已经变成了User Mode,在此模式下有两种写入方式:一种是人为的在UEFI管理环境中手动的将模式切换为Setup Mode,但这样会清除所有的PK和KEK密钥,同时会清除数据库文件,后续就无法再进行固件更新,有一定的局限性,所以此种方式很少被使用,一般只在设备维修,重刷固件时使用;另一种方式是通过签名验证的方式进行更新,UEFI厂商在进行固件更新时,就是选择此种写入方式。

应用基础

  • PKI

PKI是Public Key Infrastructure的简称,中文通常称之为公共密钥基础设施,是当今数字时代的安全基石,数字证书,数字签名,数字信封,VPN等都是PKI的应用,PKI是以现代密钥学为底层基础的软硬件结合的整体,而现代密码学又主要是以数学为理论基础的学科,如椭圆曲线,离散对数,大质数分解,费马定理、欧拉定理,欧几里德算法等。正是这些数学理论,构建了整个信息安全的世界,并保护着我们信息传播的安全。

  • 对称密钥与非对称密钥对

首先解释何为密钥,密钥即钥匙,也为一段有效数据,是数据加密解密过程的关键信息,通过密钥和一系列的运算将明文数据变成看不懂没有逻辑的密文数据,反之怡然。

所谓非对称密钥对是相对于对称密钥来说的,对称密钥的意思是由明文变成密文的过程和由密文变成明文的过程,所使用的都是同一个密钥,常用的对称密钥算法有AES、DES、3DES等;而非对称密钥对,则是不相同的两个密钥,即公钥和私钥,公钥是对外公开的,私钥只保留在持有人手中,公钥用于加密数据,私钥用于解密数据;常用的非对称密钥算法有RSA,ECC等。

  • 数字签名

无论古代还是现代,现实生活中任何具有法律效力的文件都需要我们签名画押,因为个人签名或者手印代表着我们,字迹或者指纹可以被甄别。而在虚拟世界,同样需要有代表我们的存在,而在如金融、银行等众多的关键信息领域中,数字签名就是最好的载体体现,独一无二,不可伪造。数字签名即使用非对称密钥对中的私钥,使用非对称算法进行运算,获得一段“数字版个人签名”数据,在PKI的整个体系架构中,我们可以取得该“数字版个人签名”对应的公钥,当我们使用数字网络中确定的人所持有的公钥对这个签名进行数学运算验证,如果通过验证,则说明数字签名正是来自公钥持有人,签名生效,如果验证失败,则说明此人非彼人。

  • 数字证书

数字证书也叫x509证书,是在PKI体系下通过CA(证书颁发机构)颁发给特定的人使用的。在数字网络中,数字证书就代表持有人,数字证书中包含了持有人的基本信息,如姓名、使用单位、城市等,同时还有持有人的数字ID,即非对称密钥对中的公钥,以及验证颁发机构的数字签名。而颁发机构则是被信任的第三方,在整个PKI体系中扮演着“检查官”的角色。

UEFI关键结构和数据

关键数据库

UEFI固件中有两个关键数据库,即Signatures Database(DB)和Forbidden Signatures Database(DBX),用于存储UEFI的关键敏感数据,它们都是一个数据项的集合,每个数据项存储一种类型的数据,这些数据类型包括非对称密钥,公钥Hash,签名,证书,证书文件Hash和文件Hash等。

DB中存储的是目前系统中允许被运行的PE所对应的证书或者hash,在Secure Boot开启时,所有的签名PE需要使用DB中的证书对应的私钥签名才能被允许在内存中运行,所有未签名PE的文件Hash需要在DB中被记录;相对的,在DBX中存储的是UEFI禁止加载运行的PE,如果UEFI检测到PE的签名是DBX所存储的证书对应私钥签名的,亦或者是未签名PE的文件Hash在DBX被记录,就拒绝加载运行该PE,这在后面介绍Secure Boot过程的时候会详细介绍。

DB或者DBX中的数据项结构如下:

 

       Secure Boot解决了信任链的问题,也就保证了源头UEFI的可靠性问题。相比于传统BIOS,Secure Boot可以有效抵抗大部分的BIOS病毒和木马的攻击,即使通过清除PK和KEK的方式能够改变信任链,但这样的攻击方式必须在接触到物理设备的情况下才能进行这也大大增加了攻击的难度。所以现在微软也是大力推荐终端用户开启Secure Boot,甚至推出了Secured-Core PC,即默认开启Secure Boot、TPM等一系列安全保护机制,目的就是希望能最大程度上保护用户的设备环境。

KEK

KEKs,即Key Exchange keys,是OS系统与OEM厂商之间的信任连接,使用的非对称密钥对,其公钥保存在UEFI固件中,一个系统可以有多个KEK。KEK可用于Secure Boot时验证启动信任链,可以对UEFI应用进行签名(KEK的私钥签名,然后在UEFI中使用KEK的公钥进行验证),也可用于更新数据库,如DB和DBX(DB或者DBX在更新时带KEK签名,需要KEK进行验证)。

PK

PK即Platform Key,即UEFI的制造商拥有的非对称公钥,也是UEFI环境的管理密钥,一个系统中只能有一个PK,通常为RSA-2048,用于管理UEFI自己的固件环境和KEK。

通常PK有几种模式:

  1. 每台设备一个PK:出于高安全性的要求,如政府部门、金融机构等,这种模式维护的成本相对较大,需要管理好PK和设备的对应关系,更新时比较麻烦,但安全性足够高,如果有安全漏洞,只有一台设备受影响;
  2. 每种型号一个PK:这是微软推荐的桌面PC模式,通过一个PK就能对所有同型号的设备进行维护升级,但如果PK密钥被攻破,则整个型号的设备都会有安全问题;。
  3. 每条产品线一个PK;
  4. 整个OEM一个PK;

可以看到,在越大范围上使用一个PK,管理上会带来更多的便利,维护成本就越低,但同时又会增加安全风险,一旦密钥被泄露,影响的范围就越大,所以一般不推荐使用后两种模式。

固件更新

通常固件更新可以是以下几个方面的更新,比如PK和KEK,也可以是UEFI自身环境中DXE阶段的驱动文件,或者是BDS阶段的UEFI应用。在整个更新过程中,UEFI是有验证机制来保证整个过程的合法性的,首先对于更新数据包Capsult,需要IBV(独立BIOS制造商)使用PK或者KEK的私钥对其进行签名,然后再下载至操作系统中,最后由操作系统通过UEFI的Service接口传递给UEFI。在UEFI接收到Capsult之后,解包之前,使用本地存储的PK或者KEK的公钥对其进行签名验证,证明Capsult的来源合法有效,然后更新PK、KEK,签名数据库数据库或者其他文件。

更新PK和KEK

步骤大致如下:

  1. 使用PK的私钥对更新镜像进行签名;
  2. 操作系统将待更新的固件镜像通过网络下载到本地,称之为Capsule数据包,这是由UEFI规范定义的更新格式进行封装的数据包;
  3. 操作系统通过UEFI的Update Service接口将Capsule传给UEFI;
  4. 在重新启动计算机时,,由UEFI对Capsule进行签名验证,然后进行镜像解析和解包,提取其中的PK或者KEK并进行更新。

更新UEFI应用、驱动及数据库

更新过程大致如下:

  1. 用KEK的私钥对更新数据包Capsule进行签名;
  2. 操作系统调用UEFI的服务接口将更新数据包Capsule传递给UEFI,操作系统重启后,由UEFI对更新数据包Capsule进行验证;
  3. 使用KEK的公钥对其进行签名验证。
  4. 验证通过后,更新UEFI应用、驱动或者数据库。

Secure Boot

Secure Boot是UEFI的一个重要功能,其核心就是让系统核心组件处于绝对安全的环境下运行,保证每个运行在内存中的的文件镜像都是“原装正品”,不会存在恶意代码。

当Secure Boot开启后,UEFI会按照下图所示的验证链对加载的镜像进行验证,如果通过链上所有的检查,则允许加载镜像,否则UEFI认为此镜像是不合法的,可能存在安全隐患的。UEFI验证链如下:

在进入TSL phase之前,即DXE、BSD phase:

 

验证说明:

  1. DBX中包含了公钥证书或者文件的Hash,如果EFI程序不带签名,但在DBX数据库中有对应的文件Hash,则UEFI环境禁止运行该EFI程序;如果EFI程序带签名,但在DBX中证书对应的公钥证书,同样UEFI环境禁止运行该EFI程序;
  2. DB中包含了公钥证书,文件Hash、非对称密钥对等,如果EFI程序不带签名,只有当EFI程序的文件Hash包含在DB中,UEFI环境才允许该EFI程序运行;如果EFI程序带签名,当DB中包含签名对应的公钥证书或者公钥,UEFI环境允许该程序运行;
  3. 当文件带签名,但签名的公钥证书不在DB中时,如果程序文件是使用的KEK进行签名的,也允许该程序运行;
  4. 其他所有情况,UEFI环境都拒绝允许该EFI程序;

TSL phase

在TSL阶段,由Boot Loader加载操作系统启动代码,从而进入操作系统环境,Windows和Linux在这点上存在部分差别。

当UEFI完成Secure Boot链上所有的验证,最终会进入TLS阶段,调用系统引导模块,在windows中为bootmgfw.efi,在linux中为shimx64.efi,之后UEFI的工作告一段落,接着由引导模块接着往后验证,由上一个模块验证下一个模块的签名,直到操作系统内核完成加载。

  • windows依次验证:bootmgfw.efi -> winload.efi -> ntos;

 

  • Linux依次验证:bootx64.efi -> shimx64.efi -> grubx64.efi -> vmlinuz (bootx64.efi只在安装完成后第一次启动时用于定位 shimx64.efi,之后从shimx64.efi开始启动);

 

在TLS phase中,UEFI验证链如下:

 

验证说明:

  1. MOKX作为Linux特有的数据库,其中包括了证书或者hash,如果文件不带签名,出现与MOKX数据库中的文件Hash一致的文件将禁止加载;如果文件带签名,签名对应的证书在MOKX中,此镜像文件也将被禁止加载。
  2. DBX检查逻辑与DXE、BSD phase一样;
  3. MOK是Linux特有的数据库,如果文件不带签名,只有当文件的Hash存在于MOK中时,文件才允许被加载;如果文件带签名,当其对应的证书存在于MOK中时,文件允许被加载;
  4. DB检查逻辑与DXE、BSD phase一样;
  5. 对于带签名的文件,如果此文件的签名不在DB中,但如果是由KEK进行签名的,也被允许加载运行。

被遏制的Secure Boot证书

在前面介绍Secure Boot的验证链时提到,DB受到KEK签名的限制,签名的文件受DB的限制,DB中包含了证书,文件签名必需是由DB中的证书对应的私钥签名,所以Boot Loader签名对应的证书必须在DB中。前篇提到过,微软是UEFI的主要推动者,也是最早在自己的操作系统中使用Secure Boot的OS制造商,并使用微软自己的CA管理着Secure Boot的签名证书,签名证书存放在DB中。在Windows中,通过Powershell命令可以导出DB,可以看到其中只有微软的证书,左边是微软给自己的产品使用的,右边是微软给第三方使用的,而BootLoader(bootmgfw.efi)正是由DB中的CA颁发的证书进行签名的,因此可以使用DB中的此证书来验证bootmgfw.efi的签名合法性。

windows使用的UEFI CA证书:

微软给第三方使用的UEFI CA证书

 

 

 

Linux如果想启用Secure Boot,需要将自己的Boot Loader送到微软进行签名,并且签名还需要收费。虽然微软已经将Secure Boot的证书CA、DB与DBX的管理权交给了UEFI论坛,但实际上,CA的维护依然由微软负责。

使用的微软CA颁发UEFI证书,究其原因我想可能是因为UEFI当初是由微软力推的,所以微软的证书首先进入了市场,也因为微软在PC市场的绝对占有率,微软在这件事情上拥有绝对的话语权,OEM与微软建立起了完整的业务链。所以当后来Linux也想加入Secure Boot时,就产生了一个使用哪个CA颁发证书的问题,Linux的分支众多,每个服务商各自为营,如果大家都使用自己CA颁发的证书,汇集到OEM是一个漫长的过程,同时也增加了OEM的证书管理成本和安全风险;如果大家使用同一个CA,使用谁的CA,由谁决定,这又是一个利益分配的问题,况且Linux的市场占有率并不高,这其中到底有没有足够的利益让OEM妥协配合,又是一个未知。所以一直以来,Linux如果想要使用Secure Boot,就需要将自己的Boot  Loader交给微软进行签名,使用微软CA进行管理。这不得不说是一个Linux的“鸡肋”。

       如果将自己的Boot Loader直接给微软签名,但凡有点改动就需要重新进行签名,比如使用新的签名算法进行签名验签,或者程序出现了漏洞需要修复等等,为了解决需要频繁到微软签名的问题,Linux采取了一种取巧的方式,即在Boot Loader之前加一个垫片,承上启下。目前主要采取由Fedora发明的shim方案,shim可以理解为一个功能和逻辑都非常简单的中间层,作为一个Windows和Linux的桥接,shim接受UEFI的验证,同时shim内嵌Linux厂商的公钥,用于验证操作系统启动代码,即由shim验证grub,再由grub验证内核,以此减少对Windows CA的依赖。所以通常每个Linux厂商都会自己编译shim并内嵌有自己的公钥,然后用自己的公钥验证接下来的boot loader,即grub。如下图所示,Ubuntu和Fedora的shim都被微软签名,但各自的grub使用了自己的签名。

微软给shim的签名

 Ubuntu grub签名

 

Fedora grub签名

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值