baton drop (CVE-2022-21894): Secure Boot Security Feature Bypass Vulnerability
Windows Boot Applications allow the truncatememory
setting to remove blocks of memory containing "persistent" ranges of serialised data from the memory map, leading to Secure Boot bypass.
- The
truncatememory
BCD element will remove all memory above a specified physical address from the memory map. - This is performed for each boot application during initialisation, before the serialised Secure Boot policy is read from memory.
- Therefore, such an element can be used to remove the serialised Secure Boot policy from the memory map.
- This will allow dangerous settings to be used in a boot application (
bootdebug
,testsigning
,nointegritychecks
), thus breaking Secure Boot.
This issue was fixed by two different changes:
- After attempting to load a serialised Secure Boot policy, if no policy was loaded, and Secure Boot is enabled, and the boot application was not loaded directly by UEFI firmware, and the boot application is not
bootmgr
, boot application initialisation fails. - When loading a boot application, if it has a
VERSIONINFO
resource containing anOriginalFilename
, if that filename is included in a blocklist (containingbootmgr.exe
andhvloader.exe
; in Nickel,hvloader.efi
was added but this did not get backported), the load fails.- In Windows 8 and Windows 8.1,
hvloader.exe
is not included inwinload
's blocklist - it originally was, which broke Hyper-V loading! - Since Windows 10 version 1809, if a certain flags bit is set (used with
flightedbootmgr
element to loadbootmgr
from disk), theOriginalFilename
is required to bebootmgr.exe
.
- In Windows 8 and Windows 8.1,
Exploitation
The attacker needs to ensure the serialised Secure Boot Policy is allocated above a known physical address.
- By default, it is allocated at the lowest possible address.
- Originally, the serialised Secure Boot Policy gets allocated after it is loaded, before using any configuration loaded from the BCD.
- Since RS1, the serialised Secure Boot Policy gets allocated when loading a boot application.
- Since RS2, any existing serialised Secure Boot Policy gets freed when serialising a Secure Boot Policy.
- The serialised Secure Boot Policy gets reallocated if, when loading a boot application, the BCD entry's
osdevice
is a BitLocker-encrypted partition where the VMK was derived using the TPM.- This can be faked by setting bit 0 of the key flags after successful TPM unsealing; this bit can be set manually in the BitLocker metadata, with additional metadata added to specify Secure Boot being used for integrity validation.
The avoidlowmemory
element can be used to ensure all allocations of physical memory are above a specified physical address:
- Since Windows 10, this element is disallowed if VBS is enabled, but as it is used during boot application initialisation, before the serialised Secure Boot policy is read from memory, loading
bootmgr
and specifying a custom BCD path (usingbcdfilepath
element akacustom:22000023
) can be used to bypass this. - If BitLocker is present on the OS volume, or the target system is running TH1 or TH2, then this method will fail; it is therefore also possible to run the attack once with a Windows 8.x
bootmgr
to disable VBS and then swap back to the original bootloader.- Windows 10 changed boot application initialisation to cap all TPM PCRs once, so a Windows 8.x
bootmgr
will fail to unseal the VMK on a Windows 10+ system.
- Windows 10 changed boot application initialisation to cap all TPM PCRs once, so a Windows 8.x
hvloader.efi
can be loaded with the nointegritychecks
element to load a self-signed mcupdate.dll
, whose entry point will be called before ExitBootServices
.
Alternatively, on non-AMD64 systems, winload.efi
before TH2 can be used with the testsigning
element; this allows self-signed binaries with the szOID_NT5_CRYPTO
EKU in the certificate.
On ARMv7 systems, loading a patched self-signed hal.dll
with an import to mcupdate.dll
will be necessary to get code execution.
On x86 and AMD64 systems, the file loaded as mcupdate.dll
must be named mcupdate_*.dll
, where *
is the CPUID manufacturer string (GenuineIntel
, AuthenticAMD
etc).
On ARM64 systems, this technique cannot be used due to the earliest available production signed build being a WinPE of RS2; thus currently only tethered code execution can be performed (using bootdebug
).
Included files
This repository includes the following files:
- Source code for a simple payload is provided. This payload just waits for an interrupt infinitely, as without finding interesting functions and variables in the calling boot application, it is impossible to do anything else.
- Because
mcupdate.dll
runs at a virtual address with paging enabled, it is impossible to call EFI functions directly (paging needs to be disabled to call EFI functions, returning to a virtual address with paging off does not lead to a good time). - To call EFI functions, a payload would need to call
BlImgLoadPEImageEx
orBlImgLoadPEImageFromSourceBuffer
with bit 0 set in the flags to load an additional payload at a 1:1 physical address-virtual address mapping.- Alternatively, it can call
BlImgAllocateImageBuffer
with the same bit set to allocate memory at a 1:1 physical address-virtual address mapping; then load a payload itself (or remap itself there).
- Alternatively, it can call
- Because
- An ISO that exploits this issue on AMD64 using the
bootmgfw
from Windows 8 RTM and thehvloader
from TH1 RTM.- The payload used here prints a message to the screen by using a function from
hvloader
obtained by offset and then infinite loops.
- The payload used here prints a message to the screen by using a function from
- An ISO that exploits this issue on AMD64 using
bootmgr
from RS1 and thehvloader
from TH1 RTM. - An ISO that exploits this issue on AMD64 using
bootmgr
version 19041.1081 and thehvloader
from TH1 RTM.
Postscript
This issue can be used to dump BitLocker keys (where Secure Boot is used for integrity validation).
- Although it is possible, the exact method of getting code execution with derived BitLocker keys for an arbitrary volume in memory will not be disclosed.
The fix for this issue also fixed another issue which has no CVE.
bootmgr
ignores any BitLocker keytable already in memory and allocates a new one, without wiping the old one.- Therefore, an attacker could load RS2+
bootmgr
frombootmgr
(specifying an arbitraryosdevice
where Secure Boot is used for integrity validation), boot to WinPE, load a known vulnerable driver, and use it to search for and dump the existing BitLocker keytable in physical memory.
- Therefore, an attacker could load RS2+
No known vulnerable boot application has been revoked yet.
- Until revocation happens, an attacker can just bring their own vulnerable bootloader(s).
- Revocation would cause all existing Windows installation/recovery media, and old backups, to fail to boot.
- Boot failure would occur even with Secure Boot disabled due to
bootmgr
checking its own signature.
- Boot failure would occur even with Secure Boot disabled due to
Update (2023-05-10)
An incomplete revocation occured, and another CVE (CVE-2023-24932). There's still vulnerable bootmgfw
s that were not revoked, as well as additional patches only fixing the case where bootmgr
loads bootmgr
. It only took a pasted bootkit to get MS to act ;)
If you're creative enough you'll find a way to work around the revocation of over 2000 bootmgfw
files ;)