Lose Your Head: Attempting To Boot From LUKS Without A Header

Building a secure and private Linux FDE system with minimal exposure.

Tl;dr

Most Linux Full Disk Encryption (FDE) setups using LUKS expose the boot process, kernel and LUKS header. These are potential attack vectors, so the aim is to reduce the opportunity for a threat agent to compromise the system. Using a detached LUKS header, GRUB cryptodisk, and a USB drive, it is possible to boot Linux from an encrypted volume on an external disk, whilst storing only ciphertext on an internal disk.

From: https://pixabay.com/get/e837b20b2df4093ed1584d05fb0938c9bd22ffd41cb1174590f0c371a6/keys-1234508_1280.jpg

Contents

  • Introduction
  • The Concept
  • Silver Solution
  • Gold Solution
  • Reality
  • Evaluation
  • Future Work

Introduction

This is an attempt to detail some experiments in reducing the exposure, and increasing the deniability, of a system making use of Full Disk Encryption (FDE).

The use case and threat model would involve a portable device (e.g. a laptop) that could be stolen or modified to get access to its data. It might also apply to network infrastructure or servers that are not always guaranteed to be physically secured, but contain data and run services that require protection.

Linux systems can use LUKS for encrypting the root volume, though normally the boot volume is unencrypted. This exposes the boot loader, kernel image and initramfs to potential compromise.

The boot process handles gaining access to the encrypted volume — using a passphrase (‘something you know’) or perhaps a keyfile (‘something you have’) — to get the system running. This might involve a prompt built into the initramfs stage, though this is not ideal for unattended reboots.

Crucially, the LUKS encrypted volume has a header that contains the metadata necessary for accessing the plaintext data within. The header includes the algorithms in use and the key slots used to hold the actual encryption ‘master’ key.

A physical analogy is to imagine a room whose door is secured with a key, and where the key is then stored in a safe next to the door. The safe has a combination lock, so to gain access to the room one first needs to know a correct code to open the safe, then use the key to open the door. The safe is the metadata/header and the room is the data.

Figure 1.: Typical FDE setup.

The above can be exploited in several ways, including those laid out below.

Attack Vectors

  • Access to the encrypted root volume (via theft or imaging): Decryption via prior knowledge of the key, passphrase guessing, or implementation/cryptographic weaknesses.
  • Access to the unencrypted boot loader/volume: Modification to the boot loader, kernel and/or boot process to obtain a passphrase.
  • Physical modification to the hardware/firmware: Interception of a passphrase.
  • Low level malware or side channel: Access to the key in memory once unlocked.

The aim is to reduce the likelihood of a compromise by using more encryption and separating the root volume from the boot process as much as possible. Not all the attack vectors above can be realistically mitigated, but removing several opportunities available to a threat agent can reduce the risk.

The Concept

The main system disk (e.g. /dev/sda) should contain only the encrypted data — nothing more. This means using LUKS’s detached header option when formatting and opening the volume.

An external USB drive should contain the kernel image, initramfs and the system disk’s LUKS header.

The idea is to keep the USB drive separated, perhaps by locking it up or always storing it on the owner’s person. This raises the bar for a threat actor if the main system is stolen or accessed whilst powered down without the USB drive. Any copies of the USB drive should be similarly secured separately.

Figure 2.: Concept of separating and minimising exposure.

The more sophisticated attack vectors involving physical tampering or low level mechanisms will still apply, of course. However, an attacker in possession of the system disk should have only ciphertext.

There are different ways to achieve this metadata minimisation concept, which are explored below. The Silver version merely separates the boot and root volumes. The Gold version builds on the Silver by using GRUB, an encrypted boot volume, and a keyfile.

Silver Solution

This method is the simplest realisation of the concept. An external USB disk (ideally a type that is difficult to damage) and an internal system disk are required.

The boot volume (mounted as /boot) remains unencrypted but stores the root volume’s LUKS header file, in addition to the kernel image and initramfs. The boot loader is installed on the USB drive — Master Boot Record (MBR) or BIOS Boot partition (ef02) or EFI System Partition (ESP / ef00) — where the particular boot loader used is not important.

The root LUKS volume would be protected by a passphrase, which requires a prompt during the boot process (e.g. provided by the init functionality within the initramfs). The USB drive needs to be connected to boot the system, when a kernel/initramfs update needs to be performed, and when the LUKS passphrase is changed.

Possession of the USB drive (‘something you have’) would give access to the LUKS metadata, and allow modification to the boot process and/or kernel, but the passphrase (‘something you know’) remains unknown.

Figure 3.: Silver bootstrap process.

A keyfile could be used instead — stored on the unencrypted boot volume — which would facilitate unattended reboots. However, this variation would involve leaving the external drive connected to the main system and defeats the protection provided by keeping them separate. In this case, possession of the USB drive would give complete access to an attacker.

Using the fundamental concepts of detaching the LUKS header from the root volume and keeping the initial boot process on a separate external drive, this solution is a decent step forward — though not as ideal as the Gold.

Gold Solution

A n extension of Silver, this solution goes further by encrypting the boot volume in order to protect the kernel, the initramfs and the system volume’s header file. The boot volume would be a standard LUKS setup with a passphrase protecting the master key and the header stored as normal alongside the ciphertext.

This is made possible by using GRUB’s cryptodisk functionality, which prompts for a passphrase to access the boot LUKS volume so it can load the boot menu, etc. Obviously, the choice of boot loader is more specific, though most distributions use GRUB by default.

To minimise the passphrase prompts and to make use of the protected boot volume, the root volume’s master key would be accessed using a keyfile. Therefore, the only passphrase entered would be at GRUB’s prompt, then the boot process handles opening the root volume using its detached header and its keyfile — both of which would be held on the (encrypted) boot volume, as files and perhaps included in the initramfs.

Figure 4.: Gold bootstrap process.

The boot loader — MBR or BIOS Boot partition or ESP — remain vulnerable to tampering, though issues around secure boot are out of the current scope. The boot LUKS volume protection depends on passphrase and cryptographic strength, as normal for LUKS volumes. Also, unattended reboots would not possible, unless (from the initramfs) network connectivity is enabled and an SSH server is started for remote passphrase acquisition.

Though not a completely perfect solution, as the boot loader is a significant attack surface to a more capable attacker, the exposure is reduced and the bar is raised for successful compromise. Implementing these solutions, however, is another matter.

Reality

Several experiments were carried out to explore whether the above was possible with some current Linux distributions. Three were tested: Funtoo (with bliss-initramfs), Alpine (with mkinitfs), and Void (with dracut). They are detailed below.

No wizard installers were used, only manual installation. The detailed steps — including partitioning, creating the LUKS volumes, creating filesystems, installing the system files, and most configuring — are not included.

Funtoo

Funtoo Linux (based on Gentoo) has several options available for boot loading and initramfs creation. GRUB can be used as the boot loader and bliss-initramfs (v7.1.0) used to create the initramfs.

The configuration of bliss-initramfs requires some changes to the Python LUKS hook and some parameters passed to the kernel via the boot loader. However, this setup has been made to succeed.

/etc/default/grub

GRUB_ENABLE_CRYPTODISK=y
GRUB_CMDLINE_LINUX=”enc_drives=/dev/sda enc_type=key enc_options=--header=/etc/header”

/opt/bliss-initramfs/pkg/hooks/Luks.py

_use_keyfile = 1
_keyfile_path = “/boot/system_keyfile”
_use_detached_header = 1
_detached_header_path = “/boot/system_header”

Alpine

Alpine Linux uses Syslinux/Extlinux by default and uses mkinitfs (v3.1.0) to create its initramfs. Therefore, GRUB needs to be installed instead to be able to use the encrypted boot volume.

The initramfs is more problematic using Alpine’s own mkinitfs. Within the initramfs, the LUKS volume access is carried out by a C program (nlplug-findfs) that manually calls cryptsetup library routines. Tests could not find — including through manual code inspection — a viable way to use a detached header and a keyfile to open a root LUKS volume. There seems to be support for detached headers but not for keyfiles. Documentation for mkinitfs was limited or at least well hidden.

Tests could not get bliss-initramfs to work with Alpine, as it is primarily focused on Gentoo systems. Alpine’s use of Musl libc and many Gentoo specifics within bliss-initramfs means more significant changes need to be made to succeed.

Void

Void Linux uses GRUB by default and uses dracut (v046) to create its initramfs. Dracut is much more complex than mkinitramfs and bliss-initramfs, but is written purely in shell scripts.

However, dracut makes certain (understandable) assumptions about how it accesses volumes; namely, that each usable volume has a UUID. A LUKS volume with a detached header, at least using udev/blkid, does not have a UUID. If no partitioning (GPT/MBR) is used on the system disk, then there is no PARTUUID either. The only viable reference is the disk’s serial number, which is used in udev’s construction of the /dev/disk/by-id/ symlinks.

Additionally, the processing of /etc/crypttab assumes a usable LUKS volume has a udev attribute ‘ID_FS_TYPE’ equal to ‘crypto_LUKS’. Again, a LUKS volume with a detached header is not identified as such so it is not included in the generated crypttab stored in the initramfs.

Udev can be used to artificially add the LUKS attribute to the system volume. The serial number ‘ID_SERIAL_SHORT’ can be found using udevadm info -q all -n /dev/sda. This should also be possible with NVMe drives.

/lib/udev/rules.d/61-luks.rules

KERNEL==”sd?”, SUBSYSTEM==”block”, ENV{ID_SERIAL_SHORT}==”<insert serial number>”, ENV{ID_FS_TYPE}=”crypto_LUKS”

Some significant changes to dracut’s crypt module are required. Firstly, using a disk serial number or ID as a reference to the root LUKS volume. Secondly, ensuring crypttab contains the root LUKS volume. Alternatively, using a kernel cmdline parameter to specify the header file and keyfile. Once these changes are made, this setup has been shown to succeed.

Evalution

The concept of reducing the exposure of a FDE system by separating the root volume from both its metadata and the boot process is worthwhile and possible. Enhancing this further by encrypting the boot volume increases the protection and raises the bar for a threat agent.

However, this more specialised setup is not widely supported. Gentoo based systems work well, Alpine’s mkinitfs needs keyfile functionality enhancements, and dracut requires modifications to work around the lack of a UUID.

Future Work

The dracut modifications should be merged to allow others to use this setup. It should be investigated whether mkinitfs can be enhanced to include keyfile support.

There are more boot loader, EFI and ESP related issues to explore, as well as secure boot.

BSD variants also have an FDE option using GELI. However, it seems there is no built in metadata detachment option which means the separation of system and boot is not immediately possible. This could be a feature enhancement.

Sources