Measured Boot and Malware Signatures: exploring two vulnerabilities found in the Windows loader

Introduction to Boot Security

There are two major concepts for boot security: verified boot and measured boot.

Early Launch Anti-Malware

Before moving to the vulnerabilities, let us take a look at an early anti-malware interface provided by the Windows kernel (ntoskrnl.exe).

  • This driver is unknown (not identified as good or bad);
  • This driver is good (not malicious);
  • This driver is bad (malicious);
  • This driver is bad (malicious) but critical for the boot process (the operating system won’t boot without this driver).
Table 1. ELAM scores (ranks)
  • All drivers are allowed;
  • Only good, unknown, and bad but critical drivers are allowed (by default);
  • Only good and unknown drivers are allowed;
  • Only good drivers are allowed.
  • The path to the driver file;
  • The registry path to a corresponding service entry;
  • Certificate information for the driver (a publisher, an issuer, and a thumbprint);
  • The image (file) hash.
  1. An ELAM driver is given a limited time to check a single boot-start driver;
  2. An ELAM driver is given a limited time to check all boot-start drivers;
  3. An ELAM driver is given a limited amount of memory for its code and configuration data;
  4. An ELAM driver must store its signatures in an ELAM registry hive (C:\Windows\System32\config\ELAM), under a specific registry key (named after an anti-malware vendor);
  5. An ELAM driver must validate its signatures;
  6. An ELAM driver must handle invalid signatures (in this case, it should treat all boot-start drivers as unknown);
  7. An ELAM driver should revoke the attestation (invalidate the measured boot state) when a malicious boot-start driver (or another policy violation) is identified.

ELAM and Measured Signatures

During measured boot, ELAM signatures are read and then measured by the Windows loader [11]. This puts ELAM signatures into the chain of trust, so missing or downgraded signatures can be detected and reported during the attestation.

Table 2. Signature data stored by Trend Micro and Microsoft (respectively), measured values marked with bold

Real-World ELAM Drivers

In February 2021, I reverse-engineered ELAM drivers shipped with popular anti-malware products (those without ELAM drivers were out of scope). In total 26 products having 25 unique ELAM drivers (two products share exactly the same ELAM driver), with 24 installed in the default configuration (one product writes its ELAM driver to a system volume, but no corresponding registry entry is created, the reason is unclear).

ELAM Hive

The ELAM hive is stored at this location: C:\Windows\System32\config\ELAM.

  1. A key node (a binary structure used to describe a single registry key) can point to a subkeys list (which is a list of offsets to key nodes describing subkeys of this registry key);
  2. Similarly, a key node can point to a values list (a list of offsets to key values, each key value describes a single registry value belonging to this registry key);
  3. An offset equal to 0xFFFFFFFF does not point anywhere (this value is used to express “nil”);
  4. Such offsets are not absolute, one needs to add 4096 bytes to get an offset from the beginning of a registry file (and each structure is preceded with the four-byte size field, it is a cell header, and cell data is a structure itself);
  5. A key node and a key value store a name of this registry key and a name of this registry value respectively, this could be either an extended ASCII (Latin-1) string or an UTF-16LE string (name strings that can be stored as extended ASCII strings are compressed into this form);
  6. A subkeys list must be sorted by an uppercase name of a subkey (the lexicographical order) in order to enable case-insensitive binary search across subkeys;
  7. On the other hand, a values list is not required to be sorted;
  8. A key value records the data type of this registry value (for example, REG_BINARY) and points to value data;
  9. Value data not larger than four bytes is stored directly in a key value;
  10. Value data larger than four bytes is stored at a different offset, this offset is recorded in a key value;
  11. Value data larger than 16344 bytes is stored in segments of 16344 bytes or less (for the last segment of value data), offsets to these segments are referenced in a list, an offset to this list is stored in a big data record, an offset to this record is stored in a key value (this applies to the hive format versions 1.4, 1.5, and 1.6, previous versions store value data as described previously, without using segments).
Fig. 1. A root key node of the ELAM hive (shown as selected): green — the number of subkeys (2), red — the offset to a subkeys list (0x3328, the absolute offset is 0x3328+4096=0x4328), yellow — the key name (“ROOT”, it’s an ASCII string)
Fig. 2. A subkeys list for a root key (shown as selected): yellow — the number of elements in this list (2), red — the offsets to two subkeys (0x3188 and 0x0120; in this type of subkeys list, four bytes after each offset contain a name hash used to speed up lookups), note that elements are stored in the sorted order (0x3188 corresponds to a key node called “Trend Micro”, 0x0120 corresponds to a key node called “Windows Defender”)
Fig. 3. A key node called “Windows Defender” (shown as selected): red — the number of values (1), yellow — the offset to a values list (0x3180)
Fig. 4. A values list (shown as selected): the only item is 0x0230
Fig. 5. A key value (shown as selected): yellow — the value data size (0x215C, or 8540 bytes), red — the value data offset (0x1020; this field would store value data directly if it is four bytes or less), blue — the value type (3 or REG_BINARY), green — the value name (“Measured”, it’s an ASCII string)
Fig. 6. Value data (shown as selected)
Fig. 7. When value data is larger than 16344 bytes and the hive format version is not less than 1.4, the offset field underlined in red in Fig. 5 points to this structure (shown as selected), it is called “big data”: red — the number of value data segments (2), yellow — the offset to a list of segments (0x3188)
Fig. 8. A list of value data segments (shown as selected): red — two offsets (0x4020 and 0x8020)
Fig. 9. A segment (shown as selected), the first one contains 16344 bytes, the last one contains remaining value data (there are two segments only as shown in Fig. 8)
  1. When a registry hive is mounted (loaded), it is checked for format violations. When a format violation is detected, an attempt is made to correct it or to delete a related registry structure, including references to this structure (this decision is based on what exactly is wrong);
  2. In particular, the lexicographical order of elements in all subkeys lists is checked. If a comparison of two subkeys, the current key and the preceding one in a given list, reveals that they are in the wrong order, the current key is deleted;
  3. Usually, when a hive is mounted, usermode applications can not write to its underlying file because it is locked. When an operating system has finished the boot, the ELAM hive is kept unmounted. This is for performance reasons;
  4. The ELAM hive is using the format version 1.5. So, big data records can be encountered in this hive;
  5. During the early boot, the Windows loader reads the ELAM hive into a single chunk of memory.

Measured Boot Vulnerabilities

In late 2020 and early 2021, I discovered and reported two vulnerabilities that allow a malicious program running with administrator privileges to corrupt, downgrade, or delete ELAM signatures without affecting the measured boot process.

Table 3. Vulnerabilities discovered with their corresponding CVE IDs

CVE-2021–28447

This vulnerability is pretty straightforward.

Fig. 10. A decompiled function used to get value data for measurements

Root cause

Apparently, this vulnerability was caused by legacy code lacking support for the big data record case. Previously, there was no need to read such registry values in the Windows loader.

Fix

Microsoft fixed the vulnerability by implementing the support for the big data record case in the Windows loader. This vulnerability does not affect ELAM drivers evaluated — their ELAM blobs do not reach the threshold of 16344 bytes.

Original vulnerability report

# SummaryWhen an ELAM driver stores a binary larger than 16344 bytes in one of three measured values (called "Measured", "Policy", or "Config") within the ELAM hive ("C:\Windows\System32\config\ELAM"), this binary isn't measured correctly by the Windows loader (winload.exe or winload.efi).Under specific conditions, a modification made to an ELAM blob won't result in different PCR values, thus not affecting the measured boot (since PCR values are equal to the expected ones).# Description## Steps to reproduce(Screenshots attached.)1. Mount the ELAM hive using a registry editor.2. Add a new key under the root of the ELAM hive. Assign a new value to this key (in this report, the value will be called "Measured").3. Write more than 16344 bytes of data to that value (see: "01-elam-blob.png").4. Unmount the ELAM hive.5. Reboot the system.6. During the boot, the Windows loader measures data starting from the beginning of the CM_BIG_DATA structure as pointed by the CM_KEY_VALUE structure describing the "Measured" value (see: "02-elam-blob-measured.png"). Since the expected data length is larger than the CM_BIG_DATA structure, subsequent bytes of the hive file (actually, from the memory region used to store the hive file loaded) are included into the measurement (instead of actual value data).7. After the boot, change (using a registry editor) several bytes within the value data, without altering the data size (see: "03-elam-blob-altered.png").8. Reboot the system.9. During the boot, the Windows loader will see the same CM_BIG_DATA structure and subsequent bytes as value data (see: "04-elam-blob-altered-measured.png").## Root causeThe Windows loader doesn't support parsing value data stored using the CM_BIG_DATA structure. This structure is used when the hive format version is 1.4 or newer and value data to be stored is larger than 16344 bytes.The ELAM hive uses the format version 1.5. Thus, the CM_BIG_DATA structure is supported in the NT kernel, but not in the Windows loader.The OslGetBinaryValue routine (in the Windows loader) provides back a pointer to cell data containing the CM_BIG_DATA structure instead of parsing this and related structures and then providing a pointer to consolidated data segments.## Attack scenariosFirst, ELAM blobs larger than 16344 bytes aren't measured correctly. This is a serious security issue by itself.Finally, if an ELAM driver uses existing measured ELAM blobs larger than 16344 bytes, a malicious usermode program could alter (corrupt or downgrade) these blobs without affecting the measured boot.Such an attack is possible when:
* a list of cells containing value data segments is stored before the CM_BIG_DATA structure, or
* such value data segments are stored before the CM_BIG_DATA structure, or
* a list of cells containing value data segments and such value data segments are all stored after the CM_BIG_DATA structure, but there is a large gap after the CM_BIG_DATA structure (which isn't smaller than the defined value data size, so the hash calculation won't reach the actual value data, or it's smaller than that, but the hash calculation doesn't reach the modified bytes of actual value data).
Under any specific condition defined above, changing offsets to value data segments or changing value data segments respectively won't be noticed during the measurement. (Since the hash is calculated over the internals of the hive file, but not over the actual value data.)Since the ELAM hive isn't loaded after the boot, a malicious usermode program can open it and alter its data in any way possible (this is not limited to registry functions exposed by the Advapi32 library, the hive file can be opened and edited in a HEX editor), thus exploiting any pre-existing condition defined above.## Possible solutionHandle the CM_BIG_DATA structure when parsing a registry value using the Windows loader.
01-elam-blob.png
02-elam-blob-measured.png
03-elam-blob-altered.png
04-elam-blob-altered-measured.png

CVE-2021–27094

This vulnerability is slightly more complicated.

  1. Key: Windows Defender
    · Value: Measured
  2. Key: zz
    · No values
  1. Key: zz
    · No values
  2. Key: Windows Defender
    · Value: Measured

Root cause

This vulnerability is caused by an absent check for the lexicographical order of elements in a subkeys list. Apparently, this check has been deliberately removed from the Windows loader because Unicode key names are allowed and there is no way to do case-insensitive comparisons without a proper uppercase table (a table used to convert characters into their corresponding uppercase versions).

Fix

Microsoft fixed the vulnerability by introducing the lexicographical order check in the Windows loader. Since the Unicode uppercase table is not used by the Windows loader, this fix is limited to key names using ASCII characters only. Currently, no ELAM drivers are known for using non-ASCII characters in key names.

Fig. 11. A decompiled function used to compare Unicode strings
  1. я1
  2. Я2

Original vulnerability report

# SummaryA malicious usermode program can modify the ELAM hive ("C:\Windows\System32\config\ELAM"), so its blobs (registry values called "Measured", "Policy", and "Config") are correctly measured on the next boot, but the ELAM driver won't see them because registry keys containing these blobs are deleted by the NT kernel (even before the BOOT_DRIVER_CALLBACK_FUNCTION callback is registered). This results in proper (expected) PCR values but registry values (the ones previously measured) are absent when the ELAM driver tries to read them. So, the system will boot without proper ELAM signatures and this won't affect the measured boot.# Description## Steps to reproduce(Screenshots attached.)1. Mount the ELAM hive using a registry editor.2. Add the "zz" key under the root key of the ELAM hive, don't assign any values to this key (see: "01-regedit.png").3. Unmount the ELAM hive.4. Open the ELAM hive file in a HEX editor (you can open it because it's not loaded), locate the subkeys list (subkeys of the root key), move the "zz" key to the first position on that list. (A key that was the first one before the move should now occupy the second position on the list. If there are three subkeys, just exchange the first and last keys on the list.)The idea is to break the lexicographical order of subkeys. So, "1 2" becomes "2 1" and "1 2 3" becomes "3 2 1" (see: "02-hexeditor-intact.png" and "03-hexeditor-modified.png" for "before" and "after" states of the hive file respectively).5. Reboot the system.6. When the Windows loader (winload.exe or winload.efi) reads the ELAM hive, it doesn't check the lexicographical order of subkeys (see: "04-leaf-as-loaded-by-winload.png"). It's okay for the Windows loader if subkeys are stored in a wrong order.7. When the Windows loader measures the ELAM hive (in the OslpMeasureEarlyLaunchHive routine), it reads subkeys one-by-one and measures their values (called "Measured", "Policy", and "Config").8. If you manage to break the lexicographical order of subkeys by inserting empty keys and keeping real (non-empty) keys in the same order (relative to each other, not counting the empty keys), then the Windows loader will measure the usual (expected) data. This can be easily demonstrated with one key – "Windows Defender". If you insert the "zz" key using a registry editor, it goes to the end of the subkeys list. Like this:- Windows Defender
- zz
If you move the "zz" key to the top (using a HEX editor), the lexicographical order is broken, but since the "zz" key has no values, it doesn't get measured. And the "Windows Defender" is measured as usual.9. When the NT kernel starts, it takes hives attached to the loader parameter block and validates them. At this point, the validation routine checks the lexicographical order. If a subkeys list isn't sorted, offending keys are removed from the list (see: "05-leaf-as-loaded-by-kernel.png", "06-leaf-as-loaded-by-kernel.png", and "07-leaf-after-check-by-kernel.png"). This means that the "Windows Defender" key from the example above is removed.10. When the ELAM driver tries to locate its signatures, they are gone – they were removed by the NT kernel because of the hive format violation (see: "08-leaf-as-seen-by-elam.png").## Possible solutionsEither check the lexicographical order of subkeys in the Windows loader (which requires you to pick the NLS tables first) or measure empty keys together with non-empty ones.
01-regedit.png
02-hexeditor-intact.png
03-hexeditor-modified.png
04-leaf-as-loaded-by-winload.png
05-leaf-as-loaded-by-kernel.png
06-leaf-as-loaded-by-kernel.png
07-leaf-after-check-by-kernel.png
08-leaf-as-seen-by-elam.png

References

  1. URL: https://edk2-docs.gitbook.io/understanding-the-uefi-secure-boot-chain/overview
  2. URL: https://docs.microsoft.com/en-us/windows/security/information-protection/secure-the-windows-10-boot-process
  3. URL: http://thinkinghard.com/secureinternetbanking/index.html
  4. URL: https://dfir.ru/2018/07/21/a-live-forensic-distribution-executing-malicious-code-from-a-suspect-drive/
  5. URL: https://source.android.com/security/verifiedboot/verified-boot
  6. URL: https://dfir.ru/2018/10/07/hiding-data-in-the-registry/
  7. URL: https://docs.microsoft.com/en-us/windows-hardware/drivers/install/early-launch-antimalware
  8. URL: https://docs.microsoft.com/en-us/windows/win32/services/protecting-anti-malware-services-
  9. URL: https://www.microsoft.com/security/blog/2020/09/01/force-firmware-code-to-be-measured-and-attested-by-secure-launch-on-windows-10/
  10. URL: https://www.welivesecurity.com/2012/12/27/win32gapz-new-bootkit-technique/
  11. URL: https://docs.microsoft.com/en-us/windows-hardware/drivers/install/elam-driver-requirements#malware-signatures
  12. URL: https://github.com/msuhanov/regf/blob/master/Windows%20registry%20file%20format%20specification.md

Appendix I. Reply from Sophos

From: Sophos.
Date: 2021–02–27. My report: 2021–02–04.
Hi,Thanks for the interesting report. Driver issues are obviously very important and I was happy to investigate this. I’ve talked with our ELAM driver team and an internal security team. We don’t think this is security concern, but this is not a final decision, if you disagree with the following reasoning, please let me know. There are two sensible reasons why we’re marking files as KnownGoodImage.Firstly, these files have been checked / scanned. Systems using our ELAM driver should have Sophos endpoint protection installed, which includes on-access scanning of all driver files when they’re written to disk. If they were found to be malicious, we would prevent the driver installation (probably by deleting the file). Since driver files can’t be active until the next boot, any driver files our ELAM driver sees have been judged clean by the endpoint protection component. They are “known good” to the best of our knowledge, so marking them as such seems appropriate.Secondly, if a system is configured with the GPO set to only allow files marked KnownGoodImage, when legitimate drivers are updated there is a significant chance they change state to Unknown, and this can trigger a BSOD. We have had multiple customers report this on real machines. There is what I believe is a reference to this in the ELAM documentation, see section “Boot Failures”:https://docs.microsoft.com/en-us/windows-hardware/drivers/install/elam-driver-requirementsIs that description clear? Can you see any weaknesses in the approach, or describe a scenario where an attacker could cause harm due to our behaviour?Regarding disclosure of problems, we greatly prefer coordinated disclosure, so that if a problem is identified, a fix is available from us before disclosure occurs. Currently, I don’t think a problem has been identified. We take driver level issues very seriously and if we can find a valid attack, we will want to fix this with high priority.Thanks again for the report

--

--

BI.ZONE: an expert in digital risks management. We help organizations around the world to develop their businesses safely in the digital age

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
BI.ZONE

BI.ZONE

BI.ZONE: an expert in digital risks management. We help organizations around the world to develop their businesses safely in the digital age