Wednesday, August 30, 2017

Attacking UEFI

Unlike macs many PCs are likely to be vulnerable to pre-boot Direct Memory Access (DMA) attacks against UEFI. If an attack is successful on a system configured with secure boot - then the chain of trust is broken and secure boot becomes insecure boot.

If code execution is gained before the operating system is started further compromise of the not yet loaded operating system may be possible. As an example it may be possible to compromise a Windows 10 system running Virtualization Based Security (VBS) with Device Guard. This have already been researched by Dmytro Oleksiuk.

This post will focus on attacking UEFI over DMA and not potential further compromises of the system.

What is UEFI?
UEFI is short for Unified Extensible Firmware Interface. It is the firmware that is running on the computer before the operating system is booted. UEFI is responsible for detecting memory, disks and other hardware required to boot the operating system. UEFI is a small operating system in itself. It's also sometimes a bit sloppily called the BIOS.

The Targets
A brand new Intel NUC i3 "Kaby Lake" purchased in June. 8GB RAM, Win10 1703 with Secure Boot, Bitlocker+TPM, Virtualization Based Security (VBS) Device Guard is enabled. BIOS revision: BNKBL357.86A.0036.2017.0105.1112. DMA access via internal M.2 slot.

An older Lenovo T430, 8GB RAM, Win10 1703 with Secure Boot, Bitlocker+TPM, Virtualization Based Security (VBS) Device Guard is enabled. DMA access via ExpressCard slot.

T430 to the left, NUC to the right.
The Problem
The root problem is that many UEFIs still do not protect themselves against DMA attacks, despite the hardware (VT-d/IOMMU) to do so being included in all CPUs for many years. The screenshot below shows PCILeech first searching the memory of a target computer over DMA trying to find where to hook into UEFI. Once inside it's easy to dump memory (also shown) and do other evilness - such as executing arbitrary code despite secure boot being enabled.

Loading a PCILeech module into UEFI, dumping the memory and unloading the module.
The Attack
Taking control is a simple matter of finding the correct memory structures and overwriting them if DMA access is allowed. This process is automated with PCILeech. It's possible to automatically search for the memory address of the EFI system table "IBI SYST" - or even better specify it directly to PCILeech. The EFI System Table contains the location of the EFI boot services table "BOOTSERV" which contains many useful function pointers. The boot services functions are useful for both hooking and also calling into from our implanted module.

In the example below the boot services function SignalEvent() is hooked. Once the PCILeech "kernel" module for UEFI is inserted it's possible to use it to dump memory and execute code - just as any normal PCILeech kernel module. In the example below the PCILeech UEFI implant uefi_textout is called multiple times. The output is printed on the screen of the victim computer.

The text HELLO FROM EVIL PCILEECH IMPLANT !!! is printed multiple times after the PCILeech module for UEFI have been inserted.
Once the attack was completed the kmdexit command was issued to PCILeech and the UEFI implant was unloaded. In this case Windows will start booting as shown below. If targeting the operating system loaded it's better to hook ExitBootServices() - which is called by the EFI based operating system loader when the operating system is taking over control of the computer from UEFI. At this point in time it will be possible for malicious code to modify the operating system loader.

Windows is booting normally once the PCILeech UEFI module is unloaded.
Can I try it myself?
Absolutely! The code is available as a part of the open source PCILeech Direct Memory Access Attack Toolkit on Github.

UEFI DMA attacking with PCILeech is now public, inexpensive and easy to perform. DMA attacks agaunst UEFI are no longer theoretical.

Vendors should enable VT-d to protect against DMA attacks.

Further compromise of the operating system may be possible. It may not be possible to rely on Virtualization Based Security if having a vulnerable UEFI.

Wednesday, January 11, 2017

Attacking UEFI Runtime Services and Linux

Attackers with physical access are able to attack the firmware on many fully patched computers with DMA - Direct Memory Access. Once code execution is gained in UEFI/EFI Runtime Services it is possible to use this foothold to take control of a running Linux system.

The Linux 4.8 kernel fully randomizes the physical memory location of the kernel. There is a high likelyhood that the kernel will be randomized above 4GB on computers with sufficient memory. This means that DMA attack hardware only capable of 32-bit addressing (4GB), such as PCILeech, cannot reach the Linux kernel directly.

Since the EFI Runtime Services are usually located below 4GB they offer a way into Linux on high memory EFI booting systems.

Please see the video below for an example of how an attack may look like.

What are the EFI Runtime Services?
UEFI on PCs, EFI on macs, is the modern day BIOS. UEFI is short for Unified Extensible Firmware Interface. UEFI is responsible for detecting hardware and configuring devices so that the control can be handed over to the operating system that should be loaded.

Two main components of UEFI are the Boot Services and the Runtime Services. Very early on the operating system calls ExitBootServices. After this Boot Services are no longer in use.

The EFI Runtime Services lives on even after the operating system is loaded and running though. They provide various functionality that the operating system can call into. The UEFI specification specifies a fixed set of functions that the Runtime Services should provide to the operating system, as seen below.
The UEFI Runtime Services according to the UEFI specification.
Initially the location of the Runtime Services functionality is communicated to the operating system via the Runtime Services table. The physical address for each function is 64-bit/8-byte long and is stored in memory as little endian. The memory addresses are however in the 32-bit range on all systems looked at so far. The physical memory addresses also seems to be completely static, i.e. no randomization occurs between reboots.

Linux later on maps these addresses into virtual address space and overwrites the initial addresses in the table with the corresponding virtual addresses. An example of the initial table and the table altered by Linux is shown side-by-side below.

The EFI Runtime services table, original to the left, modified by Linux to the right.
The Attack
What if we overwrite the EFI Runtime Services with our own code by using DMA? Or even better what if we overwrite function pointers in the EFI Runtime Services table to point to previously inserted attack code?

Code execution is gained on the target system when the operating system calls into EFI Runtime Services - for example whenever it's reading an EFI variable. Code execution is gained in a special context, in which pages in lower memory are mapped 1:1 between virtual and physical addresses. The Linux kernel is reachable at its normal virtual addresses. Execution is gained in ring0 / supervisor mode.

It is however not possible to call into all functions in the Linux kernel. Some functions will fail due to the special EFI context Linux have set up for Runtime Services to execute in. The way around this is to patch a "random" hook function in the Linux kernel. When a "normal" kernel thread hits that hook "normal" kernel code execution is gained...

The target system running Ubuntu 16.10 with the PCILeech attack hardware connected (to the left). Detailed view of PCILeech (to the right).

The Targets
This have been tested on a Lenovo T430 with 8GB memory and on an Intel NUC Skull Canyon with 32GB memory. The ExpressCard slot was used to gain DMA access on the T430 On the NUC the Thunderbolt mode was set to "Legacy" in the "BIOS" settings - enabling DMA access via Thunderbolt3/USB-C.

The T430 is very straight forward. Just insert the PCILeech device and issue the pcileech.exe kmdload -kmd linux_x64_efi command. PCILeech will search for the EFI Runtime Services table and hook it. The user will be asked to do something resulting in a call to the Runtime Services - triggering the hook.

The NUC is different. PCILeech will encounter unreadable memory before the target is found and will fail. Luckily the location of the Runtime Services table is static and won't change between reboots. This goes for all tested systems. The easiest way to find out the location is by USB-booting a live Linux in EFI mode on the same system, or on a similar system. Once booted issue the command cat /sys/firmware/efi/runtime to see the physical address of the Runtime Services table. Once the address is known as 0x3b294e18 we may issue the command pcileech.exe kmdload -kmd linux_x64_efi -min 0x3b294000 -max 0x3b295000 .
The NUC setup. Displaying the NUC EFI Runtime Services table on the Surface attack computer.

To try this out yourself please have a look at PCILeech at Github.

The attack is not 100% stable in the sense that the exploit always works. Sometimes the search for the Runtime Services table will fail and sometimes it's hard to trigger a call into the Runtime Services. Target system crashes are rare though.

Linux 4.8 based operating systems, such as Ubuntu 16.10, are no longer completely secure from PCILeech.

Even though your laptop may not have an ExpressCard slot chances are that it will have a mini-PCIe or M.2 slot for a WiFi card if the back cover is unscrewed ...

Operating systems cannot protect themselves from DMA attacks by putting everything of interest in memory above the 32-bit / 4GB address limit. 32-bit hardware such as PCILeech may attack firmware code and data residing below 4GB. Other malicious hardware may also reach into 64-bit address space.

Operating systems should protect both themselves and firmware, such as the Runtime Services, from malicious devices by enabling VT-d.