CVE-2025-21210 aka CrashXTS: a practical randomization attack against BitLocker

Please, refer to this Wikipedia article if you need some theory… My paper is here.

Background: attacks on AES-CBC

Do you remember code execution attacks against full-disk encryption implementations using AES-CBC? Like that one described in the “Code Execution In Spite Of BitLocker” article or another one detailed in the “Practical malleability attack against CBC-Encrypted LUKS partitions” post.

In these attacks, physically-present adversaries manipulate ciphertext blocks to flip specific bits in the decrypted form, thus constructing code execution payloads to be executed on the next boot. This is not a direct payload injection, since the attackers don’t actually write their “raw” code into the encrypted volumes, but rather flip the bits belonging to existing executables in order to transform their code.

Such an attack consists of two stages:

  • finding the exact position of bits to flip;
  • flipping these bits (in a way that turns original code into attacker-chosen code).

The nature of AES-CBC makes it easy to flip bits in the decrypted form, because each block of plaintext is XORed with the previous ciphertext block before being encrypted:

In other words, the attacker can flip arbitrary bits in one block at the cost of randomizing the previous block.

(Source.)

The hardest part here is finding the exact blocks of ciphertext to manipulate. In order to inject custom code, the attacker must know what code to modify (i.e., its plaintext bytes) and its precise location on the disk. Otherwise, flipped bits won’t produce meaningful plaintext changes (since Attacker-chosen code = Original code XOR Delta, the attacker must know Original code and then produce Delta to obtain Attacker-chosen code).

Currently, the demonstrated bit-flipping attacks rely on predictable locations of executables. The attacker installs the same operating system version on similar media to learn the disk offsets required (this is based on one assumption: two operating system installations on similar media write at least some executables to the same disk offsets). According to the “Code Execution In Spite Of BitLocker” article:

In our testing, two installations of Windows 8 onto the same format of machine put the system DLLs in identical locations. This behavior is far from guarenteed, but if we do know where a file is expected to be, perhaps through educated guesswork and installing the OS on the same physical hardware, then we will know the location, the ciphertext, and the plaintext.

Obviously, this won’t work with operating system installations that are not “fresh”… Months (or even years) of operating system updates, their installation order, and many housekeeping activities are likely to move executables to unpredictable offsets, undermining the idea of predictable locations.

Thus, the most important part of the attack – finding the exact location of bits to flip – is extremely hard to complete in reality.

Concerns: attacks on AES-XTS

Bit flips through ciphertext manipulations are impossible with AES-XTS (and this is why this mode is preferred over AES-CBC when encrypting storage devices).

In this mode, any change to a ciphertext block will turn its decrypted form into garbage and won’t affect any preceding or subsequent blocks.

More than 15 years ago, Niels Ferguson and Vijay Bharadwaj argued that code execution payloads are still possible with AES-XTS:

The attacker now replaces the first few bytes of the ciphertext block and hopes that the randomized plaintext decrypts to a value such that the first instruction executed in the block is a jump instruction to the epilog code. On the x86 a relative jump instruction is 2 bytes long and can jump up to 128 bytes forward. The probability of getting the right plaintext is one in 2^16; high enough for a practical attack.

(Source.)

In other words, attackers can get specific byte values even through unpredictable (random) ciphertext manipulations.

Practical attack: CVE-2025-21210 vs. BitLocker & AES-XTS

The idea is to force the Windows operating system to write some sensitive data to the underlying drive without encrypting it first (i.e., to leak data in the plaintext form).

The XTS mode sets the bar high for “precise” ciphertext manipulations, so code execution or anything better than “pure randomization” isn’t even considered here. And this is how I defined the problem:

  • Is it possible to leak the encryption key or some parts of encrypted data by corrupting (thus, randomizing the decrypted form of) a specific, attacker-chosen ciphertext block?
  • Is it possible to determine the exact location of that ciphertext block by observing changes to encrypted data in the “seamless” boot scenario?

Both answers are “yes”… And my paper with detailed explanations is here.

In short, it’s possible to block the BitLocker crash dump filter driver (dumpfve.sys) from being loaded by corrupting a single field within one registry key (HKLM\System\ControlSet001\Control\CrashControl) – in particular, the value list offset must be corrupted (randomized), so all values belonging to this key are removed (and our target is the DumpFilters value, which references the dumpfve.sys driver).

After this, the Windows kernel will write unencrypted hibernation images to the disk (because the kernel uses “the crash dump way” to write hibernation images, instead of the usual filter driver called fvevol.sys, and this way now excludes the BitLocker crash dump filter driver, dumpfve.sys).

And the exact location of that field (the value list of the registry key mentioned above) can be deduced (with a very low false-positive rate) by observing four states of the encrypted disk (but one of them requires triggering the blue screen).

By observing ciphertext changes in three states, it’s possible to reliably determine the beginning of the SYSTEM hive file (this file has modification patterns that are “visible through” the XTS mode). Using one more state which involves a blue screen, it’s possible to determine the location of the structure describing the CrashControl key.

Obviously, a real-world attacker is unlikely to steal (and then covertly return) one computer multiple times, so four states of one encrypted disk can be observed in BitLocker configurations that allow “seamless” boot up to the Windows login screen (in these configurations, one-time access is enough to collect multiple states of the encrypted disk).

These configurations include the TPM-only protector and one of the most secure (in my opinion) BitLocker configurations – TPM plus network key.

In the latter case, when a computer is connected to a trusted wired network, it can boot up to the Windows login screen without prompting for a password, because the encryption key is protected with two layers: the TPM and the Windows Deployment Server (both are required to obtain the key, otherwise the system falls back to the TPM plus PIN protector).

Also, it seems that scenarios involving full-disk encryption enabled to protect against low-privileged users trying to bypass existing NTFS access control restrictions are within a defendable security boundary (compare this to an unauthorized attacker having physical access). In these scenarios, users can log into the Windows operating system (and access files while honoring existing NTFS permissions), but can’t access the encrypted data directly (by rebooting into another operating system or attaching the disk to another computer) – they don’t have the TPM-bound encryption key (or a BitLocker recovery key, which is stored in the Active Directory).

Providing an unencrypted hibernation image to such users is also a vulnerability.

Timeline

  • On 2024-08-28, I sent the vulnerability report to Microsoft.
  • On 2024-08-29, I sent additional disk images to reproduce the behavior.
  • On 2024-09-12, Microsoft confirmed the vulnerability.
  • On 2025-01-14, Microsoft released a fixed version of the fvevol.sys driver.

Fix

The fixed driver checks if the dumpfve.sys driver is listed in the DumpFilters registry value. If it’s not, the operating system crashes immediately. (And two undocumented registry settings were introduced to disable this check and the crash, respectively.)

The check is implemented in the FveDiscoverVolume() function:

Possible solutions: wide-block ciphers

It seems that wide-block ciphers alone aren’t enough to protect against randomization attacks.

The second part of my paper describes an attack against a LUKS-encrypted volume that randomizes 16 MiB of data at a predefined location to trigger a condition leading to code execution from attacker-controlled media (the operating system is Fedora Workstation 40, the cipher is Adiantum, its block size is 512 bytes).

The first issue allows a physically-present attacker to destroy (randomize) the superblock of the Btrfs file system, making it unrecognizable by the operating system (without touching the LUKS metadata, so the LUKS volume remains “openable”, but the file system inside isn’t mountable).

The second issue allows a physically-present attacker to introduce an attacker-controlled unencrypted volume (containing the same file system UUID as that destroyed Btrfs file system), which is then selected as the root file system to continue the boot process (similar to that old live boot case).

These two issues, when exploited, allow attacker-supplied code to run after the LUKS-encrypted volume is unlocked.

4 thoughts on “CVE-2025-21210 aka CrashXTS: a practical randomization attack against BitLocker

Leave a comment