CVE-2023-4001: a vulnerability in the (downstream) GRUB boot manager

One can set a password to protect the boot menu entries and the command-line shell of the GRUB boot manager (see the official manual and the Red Hat manual). This is an additional security measure to be used along with a BIOS/UEFI password (e.g., to protect corporate computers from unprivileged users trying to leverage their physical access to boot another operating system or to escalate the privileges in an installed operating system).

Under the hood, this feature is implemented as two GRUB commands: “password” and “password_pbkdf2“. When one of these commands is issued with a proper set of arguments, a user with a specified password (or its hash) is created. And only those users listed in the “superusers” environment variable (when it’s set by issuing the “set” command) are allowed to edit boot menu entries and execute commands in the GRUB shell. (A physically-present user is required to authenticate as a superuser when trying to edit a menu entry or trying to enter the GRUB shell.)

In most cases, commands to set the “superusers” variable and to create corresponding users are stored in the GRUB configuration file, “grub.cfg” (which is more like a script, not a pure configuration file).

There were some vulnerabilities affecting the GRUB password protection feature, like weak permissions for the GRUB configuration file that allowed unprivileged users to obtain plain-text passwords and/or password hashes (for example: CVE-2012-2314, CVE-2013-4577, and CVE-2021-3981), an integer underflow (CVE-2015-8370), and even an improper string comparison (CVE-2009-4128).

Now, there is one more: CVE-2023-4001.

This vulnerability allows unprivileged users with physical access to a computer to bypass the password protection feature of the GRUB boot manager on many (but not all) UEFI-based computers. In some uncommon setups, no unprivileged access is required (so, physical access without an ability to log in into an operating system is enough).

Continue reading “CVE-2023-4001: a vulnerability in the (downstream) GRUB boot manager”

Bringing unallocated data back: the FAT12/16/32 case

Modern operating systems provide a way to increase the size of a given file without writing to it.

In Unix-like operating systems, this is achieved through the truncate() and ftruncate() system calls. These calls allow programs to decrease or increase the file size.

If the file size is decreased, data beyond the new end-of-file position is discarded (it can survive as deleted data, but there is no way to bring these bytes back by restoring the original file size).

If the file size is increased, extra data (data after the old end-of-file position) is filled with null bytes. Internally, many modern file systems don’t write those extra null bytes to the drive, they make a sparse data range instead (so, if a program increases the file size by several gigabytes, there is no need to actually write that amount of null bytes to the drive).

Some file systems may reserve sectors to hold that amount of extra data and attach those sectors to the file, but their contents are left intact. This is useful to quickly preallocate some space to avoid fragmentation: a file system driver reserves the requested amount of sectors, but it doesn’t clear them (and an attempt to read from that extra space returns null bytes, despite the fact that these extra sectors may contain something different).

Treating the extra space as containing null bytes is essential for security, there is a POSIX requirement for that:

If the file size is increased, the extended area shall appear as if it were zero-filled.

https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html

It’s a vulnerability if deleted (or uninitialized) data is returned when reading that extra area (for example, see CVE-2021-4155).

Surprisingly, such vulnerabilities are still discovered in file system drivers.

Continue reading “Bringing unallocated data back: the FAT12/16/32 case”

CVE-2023-45897: a vulnerability in the Linux exFAT userspace tools

Some vulnerabilities tend to appear in independently written code. And CVE-2023-4273 isn’t an exception here…

A very similar vulnerability, CVE-2023-45897, has been discovered in the exfatprogs package: in particular, in the fsck tool. This vulnerability has exactly the same mechanics (even the same proof-of-concept file system image would work), but the overflow occurs in the heap memory, not in the stack.

Continue reading “CVE-2023-45897: a vulnerability in the Linux exFAT userspace tools”

CVE-2023-4692, CVE-2023-4693: vulnerabilities in the GRUB boot manager

The GRUB boot manager is more an operating system than a boot loader. For example, it has more than 20 file system types supported!

This is a really wide attack surface… And, currently, GRUB is the default choice in the Secure Boot implementation using Microsoft-signed shims (but things are moving forward).

Some time ago, I discovered two vulnerabilities (or three vulnerabilities, if we count a security issue which is almost unexploitable) in the NTFS driver of the GRUB boot manager. And here are some technical details…

Continue reading “CVE-2023-4692, CVE-2023-4693: vulnerabilities in the GRUB boot manager”

CVE-2023-4273: a vulnerability in the Linux exFAT driver

According to the exFAT file system specification, the maximum length of a file name is 255 characters (UTF-16LE):

The FileName field shall contain a Unicode string, which is a portion of the file name. In the order File Name directory entries exist in a File directory entry set, FileName fields concatenate to form the file name for the File directory entry set. Given the length of the FileName field, 15 characters, and the maximum number of File Name directory entries, 17, the maximum length of the final, concatenated file name is 255.

This limit wasn’t really enforced in the exFAT driver of the Linux kernel, so it could be possible to craft a File directory entry set containing more than 17 File Name directory entries resulting in a concatenated file name much longer than 255 characters. And all of these characters were copied into a stack-allocated array of 258 characters.

So, here comes a stack overflow. But how to weaponize it?

Continue reading “CVE-2023-4273: a vulnerability in the Linux exFAT driver”

Do researchers handle exFAT volumes correctly?

Let’s conduct a simple experiment. In the Ext4 file system, I create two files (“1.txt” and “2.txt”).

touch 1.txt 2.txt

Then, I gather file system metadata (including timestamps) for these files:

sudo debugfs -R 'stat /path_to/the_file/1.txt' /dev/block_device
sudo debugfs -R 'stat /path_to/the_file/2.txt' /dev/block_device

In my case, the output is:

For “1.txt”:

Inode: 23918802   Type: regular    Mode:  0644   Flags: 0x80000
Generation: 2882061095    Version: 0x00000000:00000001
User:  1000   Group:  1000   Project:     0   Size: 0
File ACL: 0
Links: 1   Blockcount: 0
Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x6399ee07:e1dbba28 -- Wed Dec 14 18:38:47 2022
 atime: 0x6399ee07:e1dbba28 -- Wed Dec 14 18:38:47 2022
 mtime: 0x6399ee07:e1dbba28 -- Wed Dec 14 18:38:47 2022
crtime: 0x6399ee07:e1dbba28 -- Wed Dec 14 18:38:47 2022
Size of extra inode fields: 32
Inode checksum: 0x9906b43e
EXTENTS:

For “2.txt”:

Inode: 23921678   Type: regular    Mode:  0644   Flags: 0x80000
Generation: 2369567438    Version: 0x00000000:00000001
User:  1000   Group:  1000   Project:     0   Size: 0
File ACL: 0
Links: 1   Blockcount: 0
Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x6399ee07:e1dbba28 -- Wed Dec 14 18:38:47 2022
 atime: 0x6399ee07:e1dbba28 -- Wed Dec 14 18:38:47 2022
 mtime: 0x6399ee07:e1dbba28 -- Wed Dec 14 18:38:47 2022
crtime: 0x6399ee07:e1dbba28 -- Wed Dec 14 18:38:47 2022
Size of extra inode fields: 32
Inode checksum: 0x9b052019
EXTENTS:

Now, I’m going to store something in these files. I will use the bash shell to append some text to the first file (using the output redirection syntax) and the gedit text editor to modify the second one.

echo 123 >> 1.txt
gedit 2.txt # In the gedit window, I will type "456" and hit Ctrl-S.

And let’s get the timestamps for these files again…

For “1.txt”:

Inode: 23918802   Type: regular    Mode:  0644   Flags: 0x80000
Generation: 2882061095    Version: 0x00000000:00000001
User:  1000   Group:  1000   Project:     0   Size: 4
File ACL: 0
Links: 1   Blockcount: 8
Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x6399eed2:68debfb8 -- Wed Dec 14 18:42:10 2022
 atime: 0x6399ee07:e1dbba28 -- Wed Dec 14 18:38:47 2022
 mtime: 0x6399eed2:68debfb8 -- Wed Dec 14 18:42:10 2022
crtime: 0x6399ee07:e1dbba28 -- Wed Dec 14 18:38:47 2022
Size of extra inode fields: 32
Inode checksum: 0x4a517d18
EXTENTS:
(0):95716043

For “2.txt”:

Inode: 23860507   Type: regular    Mode:  0644   Flags: 0x80000
Generation: 534549923    Version: 0x00000000:00000001
User:  1000   Group:  1000   Project:     0   Size: 4
File ACL: 0
Links: 1   Blockcount: 8
Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x6399eed8:16d4b85c -- Wed Dec 14 18:42:16 2022
 atime: 0x6399eed8:14ec7284 -- Wed Dec 14 18:42:16 2022
 mtime: 0x6399eed8:16d4b85c -- Wed Dec 14 18:42:16 2022
crtime: 0x6399eed8:14ec7284 -- Wed Dec 14 18:42:16 2022
Size of extra inode fields: 32
Inode checksum: 0x2b67e3c3
EXTENTS:
(0):96358507

Do you see anything unusual?

Continue reading “Do researchers handle exFAT volumes correctly?”

exFAT: orphan file name entries

The exFAT file system was designed with Unicode file names and optional vendor-specific extensions in mind. To keep things simple, the file system specification allows the usage of multiple directory entries to describe a single file (so, additional file metadata is described in additional directory entries). This solution is similar to the VFAT extension for the FAT12/16/32 file systems, which was designed as a hack to the original file system format (originally, only one directory entry was used to describe a single file, so long file names were implemented as additional directory entries, which are “invisible” to operating systems without the VFAT support).

In the exFAT file system, a typical file consists of these entries (in this order, with no other entries between):

  • one file entry,
  • one stream extension entry,
  • one or more file name entries (as needed to store the file name),
  • zero, one or more vendor-specific entries (which can be ignored if not supported).

The first two entries describe all file metadata (its attributes, timestamps, data size, first cluster, etc.), while the file name entries contain strings to form the file name (each file name entry stores no more than 15 Unicode characters and the file name is no longer than 255 characters). Together, these entries are called a directory entry set (and it must contain at least three entries).

When a file is deleted, its directory entry set is marked as free. This process is very similar to what happens to a deleted file in the FAT12/16/32 file systems: the first byte of a directory entry is changed to mark it as free.

And, of course, it is possible to recover a deleted file when its directory set and data clusters are not overwritten. If the directory entry set is partially overwritten (with new directory entries), the following can be observed:

Continue reading “exFAT: orphan file name entries”

macOS & FAT directories

Previously, I wrote about things you probably didn’t know about FAT. Now, let’s continue the story!

In FAT12/16/32 file systems, each directory (except the root directory) contains two special entries:

  • dot (“.”);
  • dot-dot (“..”).

The first one (dot) refers to the directory itself, while the second one (dot-dot) refers to the parent directory. Apparently, these entries were introduced to keep file system implementations simple, so there is no need to generate those entries on the fly (this is what happens to file systems not wasting their space to store dot and dot-dot entries in every directory).

Since two special entries are regular 8.3 directory entries, they contain timestamps (Created, Modified, Last Accessed). According to Microsoft, these timestamps should be set like this:

[…] and all of the date and time fields in both of these entries are set to the same values as they were in the directory entry for the directory that you just created.

FATGEN, 1.03 (DOC)

So, the timestamps in the dot-dot directory entry have no connection to the parent directory of that directory (they aren’t copied from the corresponding timestamp fields of the parent directory). Both special entries have their timestamps set to the same values as in the directory itself.

For example, all these entries are expected to share the same timestamps:

  • E:\test
  • E:\test\.
  • E:\test\..

But are these timestamps always synchronized?

Continue reading “macOS & FAT directories”