by Shawn C[ a.k.a “citypw”]
云基础架构之CHIPSEC固件安全基线
不论是数据中心里的服务器还是工作站,厂商的闭源实现还是自由固件社区的开源实现都必须面临这个层面的安全风险,目前我们的测试数据显示服务器方面自从Haswell开始都比较注重固件的安全基线设置,而工作站和台式机则直到Skylake依然有不少机器会遗漏安全防护,McAfee高级威胁研究团队成员在今年BlackHat公布的数据也显示了不少Gigabyte和MSI主板也存在安全隐患。过去数十年的固件层面的攻防进化中产生的一些攻击平面和方法已经多到足以建立基础的安全基线检查,McAfee高级威胁团队此前开源了固件安全检测工具CHIPSEC框架对硬件平台实现进行了抽象可以更容易的编写固件安全检测的代码,CHIPSEC的开源是对于防御者的福音从而结束了硬编码的年代;-) 据McAfee高级威胁研究团队公开的固件安全培训,大概有以下安全问题需要检测:
| 安全风险 | CHIPSEC模块 | 引用 |
|---|---|---|
| SMRAM Locking | common.smm | CanSecWest 2006 |
| BIOS Keyboard Buffer Sanitization | common.bios_kbrd_buffer | DEFCON 16 |
| SMRR Configuration | common.smrr | ITL 2009, CanSecWest 2009 |
| BIOS Protection | common.bios_wp | BlackHat USA 2009, CanSecWest 2013, Black Hat 2013, NoSuchCon 2013 |
| SPI Controller Locking | common.spi_lock | Flashrom, Copernicus |
| BIOS Interface Locking | common.bios_ts | PoC 2007 |
| Secure Boot variables with keys and configuration are protected | common.secureboot.variables | UEFI 2.4 Spec , All Your Boot Are Belong To Us (here & here) |
| Memory remapping attack | remap | Preventing and Detecting Xen Hypervisor Subversions |
| DMA attack against SMRAM | smm_dma | Programmed I/O accesses: a threat to VMM?, System Management Mode Design and Security Issues |
| SMI suppression attack | common.bios_smi | Setup for Failure: Defeating Secure Boot |
| Access permissions to SPI flash descriptor | common.spi_desc | Flashrom |
| Access permissions to UEFI variables defined in UEFI Spec | common.uefi.access_uefispec | UEFI 2.4 Spec |
| Module to detect PE/TE Header Confusion Vulnerability | tools.secureboot.te | All Your Boot Are Belong To Us |
| Module to detect SMI input pointer validation vulnerabilities | tool.smm.smm_ptr | CanSecWest 2015 |
| SPI Flash Descriptor Security Override Pin-Strap | common.spi_fdopss | FLOCKDN |
| IA32 Feature Control Lock | common.ia32cfg | IA32_Feature_Control MSR lock bit |
| Protected RTC memory locations | common.rtclock | ?? |
| S3 Resume Boot-Script Protections | common.uefi.s3bootscript | ?? |
| Host Bridge Memory Map Locks | memconfig | PCI cfg |
在Debian 9上安装CHIPSEC需要的包:
apt-get install build-essential python-dev python gcc linux-headers-$(uname -r) nasm python-pip git
如果你使用的是PaX/Grsecurity 4.9.x:
apt-get install build-essential python-dev python gcc nasm python-pip git
安装CHIPSEC
cd chipsec/ pip install setuptools python setup.py install
固件白名单
由于固件安全领域的特殊性,可以为承载重要业务的机器在进入生产环境前建立白名单,比如:
chipsec_util spi dump firmware.bin chipsec_main -m tools.uefi.whitelist -a generate,harbianN_list.json,firmware.bin
审计时可以检查白名单:
chipsec_main -i -n -m tools.uefi.whitelist -a check,efi_lenovo.json,/fw-content/9sjt91a.img
coreboot加固
coreboot是一个自由开源实现的固件,可以支持多种平台,我们使用过的平台主要是x86和RISC-V,由于coreboot社区的哲学是用户在享受自由(“超级开发者”模式?)的同时也必须注意所带来的安全风险,所以coreboot并不会默认在启动时开启包括写保护在内的安全特性:

从安全评估的角度,在评估coreboot时并不应该使用和传统UEFI实现一样的方法,因为一些差异显而易见,比如coreboot并没有EFI runtime的特性以及涉及SMM的代码量比UEFI实现小很多,但即使如此,开源只是代表具有可审计性,开源并不直接影响安全防护能力,coreboot也是一样,对于固件基线的防护特性在coreboot上有一些是可以在运行时开启,而另一些则需要修改代码。对于前者,借助于CHIPSEC框架可以轻松的完成设置:
# Hardening tweaks via CHIPSEC framework:
# Enabling some security features at runtime in case of which vendor provided implementation improperly.
# WARNING: Please note that this script might put your prodcution at risk
from chipsec.chipset import *
def D_LCK_set():
# check if BIOS_CNTL register is available
if not cs.is_register_defined( 'PCI0.0.0_SMRAMC' ) :
raise Exception( "Couldn't find SMRAMC")
regval = cs.read_register( 'PCI0.0.0_SMRAMC')
d_lock = cs.get_register_field( 'PCI0.0.0_SMRAMC', regval, 'D_LCK')
if d_lock == 0:
cs.write_register( 'PCI0.0.0_SMRAMC', 0x1a)
regval = cs.read_register( 'PCI0.0.0_SMRAMC')
d_lock = cs.get_register_field( 'PCI0.0.0_SMRAMC', regval, 'D_LCK')
if d_lock == 1:
print "Enabled D_LCK successfully: SMRAMC: %x; D_LCK: %x" % (regval, d_lock)
else:
print "D_LCK is set already!"
def BIOS_WP_set():
regval = cs.read_register( 'BC')
ble = cs.get_control( 'BiosLockEnable')
bioswe = cs.get_control( 'BiosWriteEnable')
if ble != 1 or bioswe != 0:
bioswe = cs.set_control( 'BiosWriteEnable', 0)
ble = cs.set_control( 'BiosLockEnable', 1)
print "BLE & BIOSWE are looking good!"
else:
print "BLE is set already!"
def BIOS_TS_set():
bild = cs.get_control( 'BiosInterfaceLockDown')
if bild != 1:
cs.set_control( 'BiosInterfaceLockDown', 1)
print "BiosInterfaceLockDown (BILD) is enabled!"
else:
print "BILD is set already!"
def TSEG_LOCK_set():
tseg_base_lock = cs.get_control( 'TSEGBaseLock')
tseg_limit_lock = cs.get_control( 'TSEGLimitLock')
if tseg_base_lock !=1 or tseg_limit_lock !=1:
cs.set_control( 'TSEGBaseLock', 1)
cs.set_control( 'TSEGLimitLock', 1)
print "TSEGBase & TSEGLimit are locked!"
else:
print"TSEGBase & TSEGLimit are set already!"
def SPI_LOCK_set():
flockdn = cs.get_control( 'FlashLockDown')
if flockdn != 1:
cs.set_control( 'FlashLockDown', 1)
print "FLOCKDN is locked!"
else:
print "FLOCKDN is set already!"
def BIOS_SMI_set():
tco_en = cs.get_control( 'TCOSMIEnable')
gbl_smi_en = cs.get_control( 'GlobalSMIEnable')
tco_lock = cs.get_control( 'TCOSMILock')
smi_lock = cs.get_control( 'SMILock')
if tco_en != 1 or gbl_smi_en != 1:
return -1
elif tco_lock != 1 or smi_lock != 1:
cs.set_control( 'TCOSMILock', 1)
cs.set_control( 'SMILock', 1)
print "TCO/SMI are locked!"
else:
print "TCO/SMI are set already!"
if __name__ == '__main__':
# hardening init...
cs = chipsec.chipset.cs()
cs.init(None, True)
# common.smm
D_LCK_set()
# common.bios_wp
BIOS_WP_set()
# common.bios_ts
BIOS_TS_set()
# smm_dma
TSEG_LOCK_set()
# common.spi_lock
SPI_LOCK_set()
# common.bios_smi
BIOS_SMI_set()
