Can you give a hacker your hardware and still trust that computer later? Yes - and here's how.
Imagine that malware with root-level privileges has been found on a machine that you manage. You might immediately re-image the affected machine, but can you be certain that the attacker’s modifications haven’t persisted in low-level firmware or via a malicious kernel-mode driver? This article explains modern and antiquated protections which attempt to prevent attackers who have already achieved root-level access from persisting via kernel-mode drivers or firmware implants. Much of the information comes from the excellent Rootkits and Bootkits book.
Following, I’ll describe a series of test steps which allow security engineers to determine what attack vectors are available to an attacker who is looking to persist their root level privileges beyond the capabilities provided by user-mode exploits.
TLDR: Here’s a CSV of test cases to evaluate a system’s vulnerability to rootkits and bootkits.
Hardware Root of Trust
Techniques invented to mitigate this threat are categorized under hardware roots of trust, which attempt to create a secure foundation for all security primitives required to protect the integrity and confidentiality of a device placed in this hostile environment.
Firmware configuration analysis is essential when evaluating devices from companies who ship custom hardware directly into customers’ hands and later ingest the potentially malicious hardware. One example is Amazon Snowball, which is used for large scale data transfer via a physical device’s shipment. If this device cannot be certified to boot securely, where the low-level firmware is known to be uninfected, future customer data or the entire data center could be at risk of compromise.
Rootkits vs. Bootkits
RootkitsRootkits are persistence mechanisms that allow an attacker code execution within kernel space. This can be achieved via an LKM (Loadable Kernel Module), an exploit within an existing kernel-mode driver, or vulnerabilities in the interface the kernel exposes to UserLAnd processes. A rootkit allows an attacker to maintain root-level access to a system and grants permissions beyond those provided to the root user by allowing the direct modification of kernel space memory structures. These include a host of scarcely documented and sensitive system configuration structures that control core security functions within the operating system.
BootkitsA Bootkit differs from a rootkit in that it infects the firmware of the host instead of merely infecting kernel space. Bootkits hijack a portion of the boot process in order to inject malicious code earlier within the system start-up before security protections are enabled. By attacking the system very early within the boot process, they can ensure that they have the opportunity to subvert all future attempts to verify the integrity of the system.
This issue reinforces the need for a hardware root of trust. If an attacker can infect any portion of the boot process, defenders need a safe space where keys can be stored and cryptographic operations can be performed with strong integrity guarantees.
A dedicated hardware module that has been audited for physical security is needed to provide this space. This piece of hardware is called a TPM (Trusted Platform Module), and is the strongest defense against dedicated bootkit infections.
Before we dive into the details of how to properly configure a system to take advantage of a TPM, let’s first understand the boot process and its vulnerabilities.
What is BIOS and why do we care?
As rootkit mitigation techniques get more sophisticated, the level of effort associated with writing sophisticated rootkits rises. This drives attackers deeper into system internals to find softer targets. If defenders want to be able to follow them and protect systems against infection, we have to understand the BIOS (Basic Input Output System.
The BIOS began as a mechanism to prepare the system for higher-level operating system abstractions. At the most basic level, without added security protections, the BIOS follows these steps.
- BIOS Initialization - hardware self-tests, skipped if warm boot
- MBR (Master Boot Record) -> Find OS on the hard drive
- VBR (Volume Boot Record) -> Find Active Partition within drive -> Run Initial Program Loader (EFI executable)
- bootmgr (Windows Bootloader) -> Read BCD (Boot config data containing kernel code signing policy)
- winload.exe -> Loads OS Kernel module, deps, and ELAM (Early Launch Anti-Malware) modules
- Kernel Image Starts -> Boot-start drivers
- First User-Mode Process
Each of these layers depends on the previous layer. As an attacker, if you compromise an earlier layer, you can always compromise the layers that occur further down the stack, which depend on that layer.
What security mechanisms exist?
For a complete list of test cases, take a look at the CSV of test cases. In addition to this exhaustive list, the following section will provide additional details and context about completing these tests and what each protection mechanism accomplishes.
ELAM (Early Launch Anti-Malware) ModuleThis protection module was introduced starting with Windows 8. The intent of this protection is to defeat rootkits, but it cannot protect against bootkits. This mechanism allows security software to register a kernel-mode driver, which is guaranteed to launch very early in the boot process, before any non-ELAM drivers. When any future drivers are loaded, the ELAM-loaded driver has an opportunity to inspect it and if it is malicious, prevent it from being loaded.
- Only a subset of information is available to ELAM drivers.
- The name of the image
- The registry location where the image is registered as a boot-start driver
- The publisher and issuer of the driver’s certificate
- A hash of the image and the hashing algorithm
- A certificate thumbprint and the thumbprint algorithm
ELAM drivers don’t get access to the contents of the driver, so various bypasses are possible based on the superficial level of inspection. Since the ELAM module is loaded after the windows bootloader, any bootkit compromise which occurs earlier in the boot process will be able to nullify this protection.
Test Steps: Verify ELAM Policy RegistryThe ELAM module uses a policy written to a registry value at:
HKLM\System\CurrentControlSet\Control\EarlyLaunch\DriverLoadPolicy
This registry value can be viewed using standard registry tools such as regedit.exe. This policy value determines what happens when an invalid driver is found by the ELAM module. The policy decides if the ELAM module loads only known good drivers, good drivers and unknown drivers, or good drivers, bad essential drivers, and unknown drivers. This final option allows loading known bad essential drivers to ensure system stability and is the default on most systems.
It’s worth checking if the default has been changed since this protection is rendered useless if an attacker is able to replace an essential driver with a malicious one.
Kernel Mode Signing ProtectionsThis protection was introduced with Windows Vista. The intent is to ensure that all kernel modules are signed by known parties to raise the cost associated with creating malicious kernel-mode drivers. It’s important to note that this is different from the PnP Device Installation Signing Policy. This latter signing policy requires a separate check when testing as covered in the following section.
When kernel-mode drivers are loaded into the system, all drivers are verified against a known good list. It should be noted that on 32-bit Windows, only boot-start drivers are verified, but all others are left unprotected. This means that any driver which has been marked for early startup will not be verified on 32-bit Windows systems.
The logic responsible for executing this signature verification is stored in the ci.dll file. In Windows Vista and Windows 7, a single variable in the kernel image (nt!g_CiEnabled) controlled if the code verification logic occurred.
This is set in a kernel-mode memory structure, which any kernel module can alter. If code execution was ever found inside of signed 3rd party kernel modules, it could be leveraged to load arbitrary Loadable Kernel Module rootkits! Test Steps: Verify Windows Version
This security issue was patched in Windows 8 and the variable was deprecated in favor of Secure Boot. If a project requires a hardware root of trust and wants to implement kernel-mode driver signing to mitigate rootkits and subsequent bootkit infection, security engineers should recommend that the system be updated to utilize Windows 8 or later.
Additionally, the system should use a 64-bit version of Windows. If a 32-bit version is used, only boot start drivers will be verified allowing attackers to install malicious drivers which do not designate themselves as boot-start drivers.
Test Steps: Check Boot Configuration Data RegistryTo check if the kernal driver signature verification is enabled, view the registry data at:
HKEY_LOCAL_MACHINE\BCD000000
Check the following parameters as they have direct impacts on the security posture of the BIOS boot process:
BcdLibraryBoolean_DisableIntegrityCheck, BcdOSLoaderBoolean_WinPEMode, BcdLibraryBoolean_AllowPrereleaseSignature
Verify that these three boolean values are configured correctly and are not disabling crucial security mechanisms.
PnP Device Installation Signing PolicyThe Plug and Play Device Installation Signing Policy offers a separate set of protections for Kernel-Mode Signing. The requirements enforced by the PnP policy only apply to Plug and Play device drivers.
The goal of this protection is to verify the identity and integrity of the publisher of the PnP driver. To verify these drivers, the protection mechanism checks that the driver is signed either by a Windows Hardware Quality Lab (WHQL) or a trusted third party.
If these requirements are not met, a warning prompt will be shown to the user who must manually accept to proceed with the boot process. This policy is only enforced during PnP driver installation, not during future runs. This is not an inherent vulnerability, but rather an extra set of verification as the mechanisms described in the Kernel-Mode Signing Protections will still apply to PnP drivers.
Test Steps: Check the “Disable PnP Signing Registry”Check the following registry entry to see if PnP Signing has been disabled to allow for kernel module debugging
HKLM\SYSTEM\CurrentControlSet\Control\CI\DebugFlag
If this registry is set to 0x00000001, a debugger will be launched when an improperly signed PnP driver is loaded. An attacker with local access to the system can then press “g” at the debugger prompt to load the malicious driver.
Ensure that this registry value is instead set to 0x00000010 which signifies that any debuggers should be ignored and the driver should be rejected.
Secure Boot
Secure Boot was an overhaul of the BIOS startup process to incorporate further security measures. This alters the flow of early boot as follows:
- BIOS Initialization — hardware self-tests, skipped if warm boot
- UEFI
- bootmgr -> winload.exe
- Kernel Image Starts -> Boot-start drivers
- ELAM Drivers
- Kernel-mode boot-start drivers
- First User-Mode Process
In theory, when Secure Boot is enabled, all UEFI drivers must have a digital signature in order to be loaded by the system. In practice, there are a number of configurations that can substantially weaken or disable this protection. Before we cover these, you'll need context on UEFI.
Universal Extensible Firmware Interface
UEFI differs from the typical BIOS process in several key ways. There is no longer an MBR and VBR to locate the code. Instead, the GPT (GUID Partition Table) is configured as a special partition within the bootloader which points to the FAT32 EFI system partition. It contains a polyglot MBR entry within the GPT entry to prevent old systems which only recognize MBR from nuking this new format.
The path to this bootloader partition is controlled by an NVRAM variable (hints for exploitation later). The bootloader here is responsible for finding the OS kernel loader and transferring control to it. This code is stored in SPI flash stored directly on the motherboard and is loaded into RAM during startup.
The OS Loader consists of multiple files stored within the EFI system partition. It’s important to note that it’s within this bootloader that control shifts from code stored on SPI flash to code stored on the HDD. This is the location where attackers with physical access to hard drive memory have an opportunity to strike. If Secure Boot is disabled, any code can be changed here as patchguard is not present until the windows kernel has been initialized.
Once the control has been transferred from the OS Loader to winloader, boot services will be removed; however, all runtime services are enabled. Keep in mind that the OS Loader exposes a set of runtime services via the hal.dll module to kernel modules after boot. Errors within this module are often used as an insertion point for bootkits. These services include the ability to read/write NVRAM variables, perform firmware updates via capsule update, and reboot / shutdown facilities.
The UEFI SpecThe UEFI Spec defines 4 distinct stages of boot
- SEC - Security boot: finds the loader for PEI and runs from SPI Flash
- PEI - Pre-EFI Initialization: configures memory, does basic hardware things, runs in tmp memory then transitions to perm memory
- DXE - Driver Execution Environment: Initializes System Management Mode (also called ring -2) and DXE service executables. It also provides boot and runtime services
- BDS - Boot Drive Selection: discovers the HW device from which the OS will be loaded using the GPT
A number of configurations can substantially weaken the security of UEFI Secure Boot. The following memory bits are stored within SPI flash and control crucial pieces of secure boot. Note: always check that directly writing to SPI flash via kernel modules is restricted to prevent attackers from changing these variables.
- BIOSWE - BIOS Write Enable Bit (0 is locked, 1 is unlocked)
- BLE - BIOS Lock Enable Bit (1 is locked, 0 is unlocked)
- SMM_BWP - System Management Mode BIOS Write Protection Bit (1 is locked, 0 is unlocked)
- PR(0-5) - SPI Protected Ranges which selectively prevent writing to the BIOS
All these variables are initially set during the driver execution environment phase. To verify these variables, I strongly recommend using the CHIPSEC kernel module provided by Intel. A guide describing how to install this tool is included in the resources section at the end of this blog.
To check the BIOS write protection bits once the CHIPSEC kernel driver is installed, run the following command in a root terminal:
chipsec_main.py -m common.bios_wp
If the PR ranges are all 0’s, they are not being utilized at all and should be set to protect sensitive memory regions within the BIOS.
How might an Attacker Infect UEFI Firmware?
There are many many ways an attacker might go about infecting firmware, but following is a list of the most common/obvious methods:
- Modify unsigned UEFI option ROMS which may not be verified based on configuration
- Add/Modify a DXE driver
- Replace/Modify the boot manager (Use fallback boot manager)
- Modify the fallback bootloader EFI/BOOT/bootx64.efi
- Add a secondary boot loader
- Bypass SPI Write Protection and set sensitive memory bits to disable protections
- From user space with root privileges, use a signing bypass to insert kernel code, use the Hardware Abstraction Layer interface to access System Management Mode. Then find a way to bypass SPI protections to write directly to one of the early boot phases listed above
Back to Secure Boot
There are 3 forms of secure boot.
OS Secure Boot
This form of secure boot occurs within the OS Boot Loader and only verifies the OS Kernel and Boot start Drivers.
UEFI Secure Boot
This secure boot is implemented within UEFI firmware. The verification itself takes place in the Driver Execution Environment phase while UEFI apps and drivers are being loaded. Infections can still take place during the PEI or SEC phase of the BIOS.
Additionally, if an attacker is able to compromise the platform image itself, they will be able to bypass this protection.
Platform Secure Boot — Utilizing a TPM
This form of secure boot verifies all platform initialization firmware and runs within a Trusted Platform Module.
Initially, Secure Boot Driver verification occurred in DXE, then in PEI, but now it should occur in either a TPM (Trusted Platform Module), or inside of field programmable fuses which are only available via Intel ME firmware. Test Steps: Important Key Locations
The signatures are stored within a database which resides either inside SPI flash or an NVRAM variable, depending on the implementation. There is also a separate Dbx Database, which contains a list of blacklisted public keys and hashes which will be explicitly denied.
These databases are protected by a platform key or the vendor key NVRAM variable (KEK). This NVRAM variable should be securely stored within the TPM and signed by the platform key. During a security engagement, it is crucial to verify that the platform and vendor key are only controlled by the appropriate parties. The list of approved signers in the database should be restricted to only the signers required for system operation. Ideally this would be limited to the project owner.
Additionally, the Dbx database should explicitly deny known bad signers.
Test Steps: Secure Boot Policies
The sections above detail how the system should behave in theory, but in practice it is dependent on the secure boot policy. This policy may specify that some media such as PCDOption Roms are trusted by default.
Run the following PowerShell command in an administrative terminal to check if Secure Boot is enabled for the system under test:
Confirm-SecureBootUEFI
Run the following PowerShell command in an administrative terminal to check if the production Secure Boot Policy is enabled for the system under test.
Get-SecureBootPolicy
The command will return a value of {77FA9ABD-0359-4D32-BD60-28F4E78F784B} if it is running using a production policy. Any other value indicates a debug or manufacturers policy is in use and should be investigated further.
On non-windows machines, operating system kernel image-specific methods will need to be used to check the secure boot policy in use. In Rootkits and Bootkits, the authors found that the Intel EDK2 source code had several policy values which did not verify images located on removable media or option ROMS.
These implementation details are where attackers with a strong knowledge of system internals may be able to subvert an otherwise secure system.
Virtualization Based Security:
Starting with Windows 10, the code integrity mechanisms have been moved outside of the system kernel with the Virtual Secure Mode and Device Guard features. These two techniques take advantage of hardware assisted memory isolation to run the operating system and critical system drivers in hypervisor protected containers. The goal is to ensure that even if the runtime kernel is infected, the firmware and operating system are safe from further exploitation.
Virtual Secure Mode eliminates the threat of a legitimate kernel module having an RCE vulnerability which compromises the entire system as attackers cannot escalate their privileges outside of the secure container.
Device Guard builds on this technology by combining Virtual Secure Mode with platform and UEFI secure boot. The objective is to enforce device integrity from the start of the boot process and prevent bootkits from having any infection point. Platform and UEFI secure boot happens as described above. Still, once the boot manager transfers control to the operating system kernel, device guard wraps sensitive system components such as the running kernel in a protective hypervisor virtual container.
The trade-off for gaining these fantastic security characteristics is that all drivers developed for device guard must follow additional rules as described below:
- Drivers can only allocate non-paged memory from the no executable pool.
- Drivers cannot have writable and executable sections
- Drivers cannot have dynamic or self-modifying code
- Drivers cannot load any data as executable
Verified and Measured Boot
Modern TPMs provide techniques which enable a system to verify that it is in a known safe state before unsealing secrets which have been sealed inside the TPM. This technique verifies that the platform image has not been altered.
Measured Boot works by storing hashes of boot components inside the TPM PCRS (Platform Config Registries) and checking them at runtime.
TPM Attestation is a method to prove the identity of a system. It proves that a TPM is holding a certain key without revealing that key. It’s often used to restrict an endpoint to communicating with only a certain known number of devices.
Intel Boot Guard – a Platform Secure Boot implementationIntel Boot Guard is an implementation of verified and measured boot. It’s important to note that it has its own policy distinct from regular secure boot which should also be evaluated.
Boot Guard verifies the BIOS image to ensure that it hasn’t been infected by a bootkit. It uses the hardware root of trust (either TPM or fuses) to save a hash of the correct BIOS content and TPM verification code.
This method reduces the previous reliance on the integrity of SPI flash memory and moves all trust directly into hardware, hardened for this purpose.
Afterword
Early boot systems are often neglected during evaluations of hardware devices. In threat models that involve customers with isolated access to the target device, it is crucial to ensure that attack vectors involving firmware implants are mitigated. Use your new BIOS superpowers to drop some Ring-2 kits and secure some hardware!
If this guide was helpful to you, or if you have comments about this article, please feel free to reach out. I want to hear what you think! If you want to see more content like this, view the archive, subscribe to my newsletter or support me on Ko-Fi.
Further Reading and Resources:
Notes on Secure Boot and attacks
https://elinux.org/images/9/97/Protecting_your_system.pdf
https://i.blackhat.com/asia-19/Fri-March-29/bh-asia-Matrosov-Modern-Secure-Boot-Attacks.pdf
http://blog.frizk.net/2017/08/attacking-uefi.html
https://medium.com/@matrosov/uefi-vulnerabilities-classification-4897596e60af
http://www.c7zero.info/stuff/DEFCON22-BIOSAttacks.pdf
https://www.blackhat.com/presentations/bh-usa-07/Heasman/Presentation/bh-usa-07-heasman.pdf
https://habr.com/en/post/446238/https://github.com/ValdikSS/Super-UEFIinSecureBoot-Disk
https://github.com/theopolis/uefi-firmware-parser
https://github.com/LongSoft/UEFITool/releases/tag/0.27.0
https://modexp.wordpress.com/2019/08/12/windows-process-injection-knowndlls/
TPM specific attacks (attestation bypass, etc.)
https://github.com/kkamagui/napper-for-tpm/#6-test-results
https://github.com/nccgroup/TPMGenie
PXE Specific attacks
https://blog.netspi.com/attacks-against-windows-pxe-boot-images/
https://www.youtube.com/watch?v=HQcDtEnu8NY
Misc BIOS Things:
https://github.com/pinczakko/BIOS-Disassembly-Ninjutsu-Uncovered
https://github.com/bootkitsbook/
https://01.org/linux-uefi-validation
https://threatvector.cylance.com/en_us/home/gigabyte-brix-systems-vulnerabilities.html
https://www.youtube.com/watch?v=nyW3eTobXAI
Tools