Bug 1218714 (CVE-2023-4001) - VUL-0: CVE-2023-4001: grub2: bypass the GRUB password protection feature
Summary: VUL-0: CVE-2023-4001: grub2: bypass the GRUB password protection feature
Status: NEW
Alias: CVE-2023-4001
Product: SUSE Security Incidents
Classification: Novell Products
Component: Incidents (show other bugs)
Version: unspecified
Hardware: Other Other
: P3 - Medium : Normal
Target Milestone: ---
Assignee: Bootloader Maintainers
QA Contact: Security Team bot
URL: https://smash.suse.de/issue/390669/
Whiteboard: CVSSv3.1:SUSE:CVE-2023-4001:5.6:(AV:P...
Keywords:
Depends on:
Blocks:
 
Reported: 2024-01-11 08:46 UTC by SMASH SMASH
Modified: 2024-01-16 09:25 UTC (History)
2 users (show)

See Also:
Found By: Security Response Team
Services Priority:
Business Priority:
Blocker: ---
Marketing QA Status: ---
IT Deployment: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description SMASH SMASH 2024-01-11 08:46:37 UTC
https://bugzilla.redhat.com/show_bug.cgi?id=2223437

The "/boot/efi/EFI/fedora/grub.cfg" configuration file allows an unprivileged user with physical access to a computer to bypass the GRUB password protection feature on many (but not all) UEFI-based systems.

References:
http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2023-4001
https://bugzilla.redhat.com/show_bug.cgi?id=2224951
Comment 1 Alexander Bergmann 2024-01-11 08:48:54 UTC
It is currently unclear what exactly is causing this issue. Waiting for details from Red Hat and upstream.
Comment 2 Marcus Meissner 2024-01-11 10:11:22 UTC
perhaps its a world readable file on fedora there.
Comment 3 Johannes Segitz 2024-01-16 09:25:42 UTC
Details (oss posting from Maxim Suhanov)

References:

https://dfir.ru/2024/01/15/cve-2023-4001-a-vulnerability-in-the-downstream-grub-boot-manager/
https://access.redhat.com/security/cve/cve-2023-4001

Plain-text details taken from the first reference:

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).

In theory, commands required to properly enable the password protection
feature (i.e., to create a user and to set a list of superusers) of the GRUB
boot manager can be stored in two locations: in the configuration file
embedded in the GRUB image (which is an EFI executable) and in the “external”
configuration file (which is most likely named “grub.cfg“).

In the UEFI Secure Boot world, GRUB images are signed, so they can’t contain
anything other than a hard-coded (vendor-defined) password or its hash (and,
hopefully, there are none). So, the corresponding commands have to be stored
in the “external” configuration file, “grub.cfg“.

Originally, on BIOS-based systems, this configuration was stored as a single
file in the same directory with the GRUB files.

But on UEFI computers this configuration became split between two files: the
first one in the EFI System Partition volume
(“/boot/efi/EFI/<vendor>/grub.cfg“; it’s usually a FAT12/16/32 file system)
and the second one in the “/boot” volume (“/boot/grub/grub.cfg” or
“/boot/grub2/grub.cfg“; it’s usually a file system not supported by the UEFI
firmware: e.g., Ext2/4 or XFS). The latter will called “the main configuration
file” here.

A thorough explanation of this new scheme can be found here:
https://fedoraproject.org/wiki/Changes/UnifyGrubConfig.

When the GRUB password is set (e.g., using the “grub2-set-password” tool),
it’s written to the main configuration file. And the first configuration file
is just a simple script to locate and execute the main configuration file (as
shown on the screenshot below).

<screenshot>

A configuration file found in the EFI System Partition (CentOS Stream 9)

If the password-related commands were stored in the first configuration file,
there would be no issue described in this post. But they are stored in the
main configuration file, which is found and then executed by the first
configuration file.

What if the main configuration file isn’t found? The GRUB boot manager will
spawn its shell.

Interestingly, we can force the main configuration file to “disappear” (at
least on some systems) when the first configuration file is executed. So,
there would be no password prompt (because no password-related commands are
ever executed after the power-on event) and the GRUB shell will be immediately
available to a physically-present user.

The UUID is the key! The main configuration file is located using a predefined
path: “<device>/grub2/grub.cfg” (as shown on the screenshot above). Here,
“<device>” is a volume found by its file system UUID using the “search”
command.

And duplicate file system UUIDs pose a security problem…

If there are two file systems sharing the same UUID, one of them is the real
“/boot” volume and another one is an empty volume, the GRUB boot manager
could, under some circumstances, pick a wrong device as containing the main
configuration file. And if there is no main configuration file stored (that
empty volume case), the GRUB shell is spawned.

Internally, the “search” command tries every partition on every block device
until a specified signature (a file system UUID in this case, but the command
also supports searching by a volume label and by a file) is found.

All block devices are tried in the same order as returned when enumerating
their EFI handles (“hd0”, “hd1”, “hd2” and so on, “hd0” corresponds to the
first EFI handle returned when enumerating EFI block devices). Some UEFI
implementations enumerate non-removable drives before removable ones, while
others do exactly the opposite (e.g., my Lenovo laptop exposed this behavior;
the UEFI implementation of VirtualBox with USB3 support enabled enumerates USB
sticks before internal drives too).

So, if an attached removable drive (like a USB stick) becomes “hd0” in the
GRUB boot manager (and the computer’s internal drive is “hd1” in that case),
it’s possible to bypass the GRUB password protection feature by placing an
empty file system with the same UUID as the real “/boot” volume onto that
removable drive and attaching it to the computer before the boot. During the
boot, the GRUB boot manager will simply spawn its shell, without even asking
for a password (and without changing the boot order, of course).

Unprivileged users can learn the UUID value of the “/boot” volume using the
“lsblk” tool (because file system UUIDs are exposed to unprivileged users).

Here is a video demonstrating the attack: https://drive.google.com/file/d/1mMlEIgfnUKIgaOEBNmtWuRo7RUAqjDrT/view?usp=sharing.

It should be noted that some Linux distributions provide enough debug output
in a separate console, so a necessary UUID can be obtained from there (and no
unprivileged access to the operating system is required in this case).

Timeline

 2023-04-03: the vulnerability was discovered by me.
 2023-07-17: the vulnerability was reported by me to Red Hat.
 2023-10-17: an initial fix is available for testing.
 2023-10-18: an issue was discovered by me in that fix (an attacker could
bypass an additional check implemented by the patch by attaching 10 removable
drives to the computer, if that number of removable drives is supported by the
firmware).
 2023-10-30: a new fix is available for testing.
 2023-10-31: two issues were discovered in that fix (one issue is a “huge”
heap overflow introduced when working with strings in the patched code,
another issue is a minor out-of-bounds write of a null byte).
 2023-10-31: a final fix is available.
 2023-11-23: the disclosure date is agreed upon — 2024-01-15.
 2024-01-12: the vulnerability is disclosed by Red Hat.
 2024-01-15: this post has arrived.

Fix

A fix proposed by Red Hat implements a new argument to the “search” command,
which restricts the UUID scan to the block device used to launch the GRUB boot
manager. This means that the “/boot” volume must reside on the same drive as
the EFI System Partition.

An alternative (but not implemented) approach would be to use something that
isn’t exposed to unprivileged users as a signature to locate the “/boot”
volume. This could be a file with a random name residing in a directory with
restricted permissions.