This vulnerability was discovered by Rafal Wojtczuk and Corey Kallenberg, check original white paper.
Around one month ago, at 31-st Chaos Communication Congress, Rafal Wojtczuk and Corey Kallenberg presented an excellent research: “Attacks on UEFI security, inspired by Darth Venamis’s misery and Speed Racer” (video, white paper 1,white paper 2). The main goal of UEFI vulnerabilities discovered by researchers — it’s relatively easy way to bypass different platform security measures (BIOS write protection, SMM protection) on wide range of modern motherboards and laptops that available at the market. Usually, such vulnerabilities might be useful at post exploitation phase for infecting a target machine with stealth and persistent BIOS backdoor that can survive operating system reinstallation. Also, disclosed boot script table vulnerability (CERT VU #976132) is very interesting because at this moment it’s one of the best publicly known vulnerabilities that allows to get access to the SMM (a high-privileged CPU mode that might be even more powerful, that ring0 or hardware hypervisor).
However, Rafal and Corey haven’t released their PoC code which is needed to check your system for UEFI boot script table vulnerability, so, I decided to write a blog post with step by step work log of it’s exploitation on my test hardware: Intel DQ77KB motherboard with 7 series Q77 chipset. In theory, all reverse engineering and exploitation steps are also reproducible on any other UEFI compatible motherboard, so you can modify exploit code to add other models support. As for the BIOS_CNTL race condition vulnerability (CERT VU #766164), my motherboard is not vulnerable because it’s properly uses SMM_BWP bit.
Also, while reading this post you should remember, that under BIOS I usually mean “PC firmware in general”, but not a legacy (pre-UEFI) BIOS. Described attack is irrelevant to legacy BIOS, because in most of the cases it doesn’t have appropriate platform security mechanisms at all.
UEFI boot script table is a data structure that used to save platform state during ACPI S3 sleep, when the most of platform components are powered off. Usually this structure located at special nonvolatile storage (NVS) memory region. UEFI code constructs boot script table during normal boot, and interprets it’s entries during S3 resume when platform is waking up from sleep. Attacker, which is able to modify current boot script table contents from the kernel mode of operating system and trigger S3 suspend-resume cycle, can achieve arbitrary code execution at early platform initialisation stage, when some of security features are not initialised or not locked yet. If you haven’t seen Rafal and Corey talk — it’s a good time to do that.
Official Intel documentation (Intel® Platform Innovation Framework for EFI) is the best starting point to get some information about UEFI S3 resume architecture:
- S3 Resume Boot Path Specification
- Boot Script Specification
A lot of things from documents above has reference implementation in EDK2 source code . In practice many manufacturers uses they own code, but nevertheless, EDK2 is a great information source which might be helpful for better understanding of some unclear aspects.
Following scheme shows a platform boot path during normal boot, and during S3 resume:
Firmware reverse engineering is required to exploit this vulnerability because boot script table location and format are vendor-specific. Boot Script Specification defines a set of operations that must be implemented by interpreter, but not a boot script binary format itself:
#define EFI_BOOT_SCRIPT_IO_WRITE_OPCODE 0x00
#define EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE 0x01
#define EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE 0x02
#define EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE 0x03
#define EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE 0x04
#define EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE 0x05
#define EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE 0x06
#define EFI_BOOT_SCRIPT_STALL_OPCODE 0x07
#define EFI_BOOT_SCRIPT_DISPATCH_OPCODE 0x08
A real implementation of S3 resume also may have some custom opcodes in addition. Obviously, they are not described in any specs.
Acquiring and unpacking firmware image
First of all, for reverse engineering of boot script table interpreter, we need to obtain a firmware image for target platform. It’s possible to download firmware updates from vendor web-site and unpack them, but if you don’t wan’t to mess with firmware updates format (which may be proprietary/undocumented) it’s better to dump actual flash image contents from SPI flash chip that located on the motherboard. In most of the cases, for dumping flash you just might to use aflashrom utility directly from environment of operating system that running on the target platform (software way). If your chipset/motherboard is not supported by flashrom like my DQ77KB, you can use other computer to read flash chip contents with SPI programmer device (it should work even without chip de-soldering).
Intel DQ77KB has two different SPI flash chips:
More detailed exploit description: http://blog.cr4.sh/2015/02/exploiting-uefi-boot-script-table.html USAGE: 1) Download and install CHIPSEC (https://github.com/chipsec/chipsec). 2) Download and install Capstone engine incl. Python bindings (http://www.capstone-engine.org). 3) Install nasm (apt-get install nasm). 4) Copy boot_script_table.py into the chipsec/source/tool/chipsec/modules. 5) Run module: # cd chipsec/source/tool/chipsec # python chipsec_main.py –module boot_script_table ADDITIONAL TOOLS: * dma_expl.py is a proof of concept code for Linux operating system that uses software DMA attack to read or write SMRAM contents. * patch_smi_entry.py program uses DMA attack to defeat BIOS_CNTL flash write protection with SMI entries patching. To learn more about these two programs please read my other blog post:http://blog.cr4.sh/2015/09/breaking-uefi-security-with-software.html
WARNING: Exploitation of this vulnerability is very hardware-specific because it depends on boot script table format and location. Exploit was tested with following hardware: * Intel DQ77KB motherboard (Q77 chipset) * Apple MacBook Pro 10,2 (late 2012, QM77 chipset) Running this code on any other hardware may lead to unexpected problems. TODO: * Windows support (current implementation uses rtcwake Linux shell command). * More decent boot script table decoding and dumping (incl. vendor-specific opcodes). * SPI protected ranges dumping and checking.