How does one go from being root on the host to gaining access to data in a Virtual Machine running with full disk encryption. This is the exact question that arose from an internal discussion we had at Appsecco to which we wanted answers.
I came across many ways to the break full disk encryption, but the easiest way was to take a memory dump of the running VM and extracting the encryption key from there. The steps we took are listed below.
- Setup a Ubuntu 16.04 VM with Full Disk Encryption
- Dump the Virtualbox VM’s memory when the disk is unlocked
- Extract the master key from memory dump using findaes tool
- Use the key to decrypt the encrypted partition from the VM’s disk file
- Mount the partition and access the data
We setup an Ubuntu 16.04 desktop VM with full disk encryption in Virtualbox to try this out.
We used the default “Full disk encryption with LVM” option during installation which uses dm-crypt/LUKS. The default cryptsetup configuration used is aes-xts-plain64:sha256 which uses a 512 bit encryption key.
Once the installation was complete, we booted into the VM by entering the encryption passphrase we had configured
Dumping the VM’s memory
We start by getting the memory dump for the VM when the disk is in unlocked state. The VM must be in either running/paused state for us to be able to extract the memory dump to a file.
VirtualBox exposes a feature rich debugger that among other things allow us to dump the VM’s memory.
VBoxManage debugvm <vm-name> dumpvmcore --filename=<filename.raw>
This will give us the memory dump in a raw file format. This may take a while to complete.
Extracting the key from the memory dump
We then extract the encryption key from the memory dump using any tool that can identify AES strings from a file. We chose to use findaes for this purpose.
We can download findaes from https://sourceforge.net/projects/findaes/. This file is an archive of the source for findaes and must be compiled before we can use it.
Lets extract the downloaded zip file
cd findaes-1.2 ; make
Lets run findaes against our memory dump file and see if we are able to extract any keys
As we can see, there are a lot of keys that have been identified from the memory dump. The AES algorithm generates round keys from the master encryption key which are also stored in the memory. Even if the master key was not available for some reason, we can still compute the master key from the round keys. So what we see is a mix of master key, round keys and any other AES keys that findaes was able to identify. You can refer to cryptsetup documentation to learn more about how it implements Full Disk Encryption.
We could write a script to try all the keys to decrypt the partition. But, since we know that we are looking for a 512 bit key, and the extracted keys are all 256 bit, we can narrow our search to two 256 bit keys that are consecutive in the memory.
We find the two keys that match our requirement. We get the master key by combining the two keys at 0x34dfcf88 and 0x34dfcd98. Since Intel x86–64 uses little-endian scheme, we must combine the keys in reverse order.
We now have a potential master key which we will try to decrypt the encrypted partition with.
Decrypting a LUKS encrypted drive using master key
We will use dmsetup tool and the recovered master key to try decrypting the encrypted partition.
To decrypt the partition, we first need to mount the disk. To do this, we first make a copy of the VM’s disk and attach it to a new Virtualbox VM where we will use a live Ubuntu environment to mount the disk and decrypt the partition. Once that is done and we boot into the new VM with the Ubuntu Live environment.
To manually use a master-key to decrypt an encrypted partition, we need the size of the partition and the exact encryption scheme that was used. We know that the default encryption scheme used by dmcrypt is aes-xts-plain64:sha256 from the cryptsetup FAQ.
We need to find the disk and list its partitions from our live environment. We can use fdisk to do that
sudo fdisk -l
We find the size of our encrypted partition /dev/sda5 using blockdev
sudo blockdev --getsz /dev/sda5
The syntax for the command to unlock and decrypt the partition is as follows
echo "0 <size> crypt aes-xts-plain64 <key> 0 </dev/drive> 4096" | sudo dmsetup create luks-volume
If there were no errors, then the decryption was successful.
Accessing the data
We use lsblk to view the LVM volumes that are now available after decryption
We can now see an LVM volume which is the root partition from the decrypted partition. Lets mount that and see if we are able to find anything interesting
sudo mount /dev/mapper/ubuntu--vg-root /mnt
Lets list the contents of the home folder of the root user
We’ve now managed to successfully extract the encryption key from a memory dump and read the files from a VM’s disk which used full disk encryption.