CVE-2016-4484: Cryptsetup Initrd root Shell

Enter 93 times to shell



Description

A vulnerability in Cryptsetup, concretely in the scripts that unlock the system partition when the partition is ciphered using LUKS (Linux Unified Key Setup). The disclosure of this vulnerability was presented as part of our talk "Abusing LUKS to Hack the System" in the DeepSec 2016 security conference, Vienna.

This vulnerability allows to obtain a root initramfs shell on affected systems. The vulnerability is very reliable because it doesn't depend on specific systems or configurations. Attackers can copy, modify or destroy the hard disc as well as set up the network to exflitrate data. This vulnerability is specially serious in environments like libraries, ATMs, airport machines, labs, etc, where the whole boot process is protect (password in BIOS and GRUB) and we only have a keyboard or/and a mouse.

Note that in cloud environments it is also possible to remotely exploit this vulnerability without having "physical access."

UPDATE 17/11/2016 The bug is in the initrd scripts used for decrypting a system volume. Initrd contains stripts from multiple services, and the affected one is an script file from the cryptsetup Debian package. Regarding physical access In general when the attackers have "physical access" then it is "game over". But there are different degrees "physical access". It is not the same to attack a system with only a small-reduced keyboard (entertainment airplane) than a system where the attacker can access to the USB or other ports; or there may be a huge difference between having access to a keyboard with or without the [ESC] key. Remotely exploitable in cloud environments According to CVSSv3 "remotely exploitable" (or network attack vector) means that the vulnerable component is bound to the network stack. But we also believe that cloud is changing the rules of everything, from the hardware to the operating systems. In general when the attackers have "physical access" then it is "game over". But there are different degrees "physical access". It is not the same to attack a system with only a small-reduced keyboard (entertainment airplane) than a system where the attacker can access to the USB or other ports; or there may be a huge difference between having access to a keyboard with or without the [ESC] key.According to CVSSv3 "remotely exploitable" (or network attack vector) means that the vulnerable component is bound to the network stack. But we also believe that cloud is changing the rules of everything, from the hardware to the operating systems. The CVSS v3 standard (an admirable normalization effort) defines 4 coarse-grain levels of attack vectors: Network, Adjacent, Local and Physical. But as far as we know, there are some cloud environments that provide full console access over the network. We tried to reflect that cloud environments are not 100% safe, and they should not ignore this vulnerability. Depending on the service offered by some cloud providers they could be vulnerable, and so, it is not clear in which attack vector fits better. Security is still a young field which tries to adapt to the continuous changes of the technology. Cloud computing is redefining many computing concepts. Please, read the "Discussion: About physical access" at the end of this blog. Other systems affected by a similar (or the same) issue Systems that use Dracut instead of initramfs are also vulnerable. (tested on Fedora 24 x86_64). Note that if the grub password is setted at installation time on Fedora the rd.shell is set to zero preventing this attack. Thanks to Lubomir for reporting this.

instead of initramfs are also vulnerable. (tested on Fedora 24 x86_64). Note that if the grub password is setted at installation time on Fedora the is set to zero preventing this attack. Thanks to Lubomir for reporting this. The kinitram simple and powerful initram system is also vulnerable. Thanks to Klondike for letting us know. Please, read the "Discussion: About physical access" at the end of this blog.

Am I vulnerable ?

If you use Debian or Ubuntu/ (probably many derived distributions are also vulnerable, but we have not tested), and you have encrypted the system partition, then your systems is vulnerable.

During the installation of Ubuntu, one of the first steps is to prepare the target partition (make partitions if needed, and/or format them). At this stage, the user is asked to " Encrypt the new (LXK)ubuntu installation for security ". Nowadays, there is very little performance penalty working with an encrypted disk and it is an effective solution to protect data when the computer is not running. It is advisable to enable this feature.

If you didn't installed the system, the you can figure out the organization by running the blkid command.

Checking if the root partition is encrypted $ blkid /dev/sda1: UUID="db96cdf9-99c3-4239-95f2-6af2651ef3ac" TYPE="ext2" /dev/sda5 : UUID="d491bf52-a9ea-466f-be9b-3a5df954699e" TYPE=" crypto_LUKS " /dev/mapper/ sda5_crypt : UUID="30xz0y-4LeG-LwuL-QHI9-pWWi-BxHf-F3udoC" TYPE=" LVM2_member " /dev/mapper/lubuntu--vg-root : UUID="53f95bd1-9e1c-4e23-9ff3-990d90c5cc92" TYPE="ext4" /dev/mapper/lubuntu--vg-swap_1 : UUID="9eac532c-1b54-4cac-9995-b4b921222422" TYPE="swap" /dev/zram0: UUID="c2929c6e-2432-40ee-99a5-deadbeefa53e" TYPE="swap" /dev/zram1: UUID="d1bf1e22-dead-beef-9c49-e6462449d6e2" TYPE="swap" /dev/zram2: UUID="12a9232d-c62e-0df6-93ea-22ac3600bdf0" TYPE="swap" /dev/zram3: UUID="bf777ad3-13fc-4ad5-914b-002e67262939" TYPE="swap"

This is the classic structure where the partition " /dev/sda5 " is encrypted and then used as a physical_volume in the " lubuntu-vg " volume_group which contains two logical_volumes: lubuntu--vg-root and lubuntu--vg-swap_1 . As a result, the system and the swap partitions are encrypted by LUKS and protected by a single password. This system is vulnerable.

Impact

An attacker with access to the console of the computer and with the ability to reboot the computer can launch a shell (with root permissions) when he/she is prompted for the password to unlock the system partition. The shell is executed in the initrd environment. Obviously, the system partition is encrypted and it is not possible to decrypt it (AFAWK). But other partitions may be not encrypted, and so accessible. Just to mention some exploitation strategies:

Elevation of privilege: Since the boot partition is typically not encrypted: It can be used to store an executable file with the bit SetUID enabled. Which can later be used to escalate privileges by a local user. If the boot is not secured, then it would be possible to replace the kernel and the initrd image.

Since the boot partition is typically not encrypted: Information disclosure: It is possible to access all the disks. Although the system partition is encrypted it can be copied to an external device, where it can be later be brute forced. Obviously, it is possible to access to non-encrypted information in other devices.

It is possible to access all the disks. Although the system partition is encrypted it can be copied to an external device, where it can be later be brute forced. Obviously, it is possible to access to non-encrypted information in other devices. Denial of service: The attacker can delete the information on all the disks.

The Vulnerability

The fault is caused by an incorrect handling of the password check in the script file /scripts/local-top/cryptroot . When the user exceeds the maximum number of password tries (by default 3), then boot sequence continues normally.

initrd.img:/script/local-top/cryptroot 0 sh . . . 171 setup_mapping () 172 { . . . 273 274 count =0 275 while [ $ crypttries -le 0 ] || [ $ count -lt $ crypttries ]; do 276 export CRYPTTAB_TRIED = "$count" 277 count =$(( $ count + 1 )) . . . 298 if [ ! -e "$NEWROOT" ]; then 299 if ! crypttarget = "$crypttarget" cryptsource = "$cryptsource" \ 300 $ cryptkeyscript "$cryptkey" | $ cryptopen ; then 301 message "cryptsetup: cryptsetup failed, bad password or options?" 302 continue 303 fi 304 fi 305 . . . 342 if [ -z "$FSTYPE" ]; then 344 message "cryptsetup: unknown fstype, bad password or options?" 345 udev_settle 346 $ cryptremove 347 continue 348 fi 349 350 message "cryptsetup: $crypttarget set up successfully" 351 break 352 done 353 354 if [ $ crypttries -gt 0 ] && [ $ count -gt $ crypttries ]; then 355 message "cryptsetup: maximum number of tries exceeded for $crypttarget" 356 return 1 357 fi 358 359 udev_settle 360 return 0 361 } . . . 402 if [ -r /conf/conf.d/cryptroot ]; then 404 while read mapping <&3; do 405 setup_mapping "$mapping" 3<&- 406 done 3< /conf/conf.d/cryptroot 407 fi 408 409 exit 0

The calling script, /scripts/local , handles the error as if it were caused by a slow device that needs more time to warm-up.

The booting scripts then tries to recover/mount the "failing" device, in the function local_deveice_setup() , multiple times (up to 30 times on an x86 system, and 150 on a powerpc machine). Every time the top level script tries to mount the encrypted partition (line 99 in /script/local ), the user is allowed to try 3 more LUKS passwords. This gives a total of 93 password trials (on x86).

initrd.img:/script/local . . . 43 local_device_setup () 44 { . . . 76 if ! real_dev =$( resolve_device "${dev_id}" ) || 81 ! get_fstype "${real_dev}" >/dev/null; then 82 log_begin_msg "Waiting for ${name} file system" 83 84 case $ DPKG_ARCH in 86 powerpc|ppc64|ppc64el) 87 slumber =180 88 ;; 89 *) 90 slumber =30 91 ;; 92 esac 93 if [ ${ ROOTDELAY :-0} -gt $ slumber ]; then 94 slumber =$ ROOTDELAY 95 fi 96 97 while true; do 98 sleep 1 99 local_block "${dev_id}" 100 if real_dev =$( resolve_device "${dev_id}" ) && 101 get_fstype "${real_dev}" >/dev/null; then 102 wait_for_udev 10 103 log_end_msg 0 104 break 105 fi 106 slumber =$(( ${ slumber } - 1 )) 107 if [ ${ slumber } -eq 0 ]; then 108 log_end_msg 1 || true 109 break 110 fi 111 done 112 fi 113 114 while ! real_dev =$( resolve_device "${dev_id}" ) || 116 ! get_fstype "${real_dev}" >/dev/null; do 117 echo "Gave up waiting for ${name} device. Common problems:" 118 echo " - Boot args (cat /proc/cmdline)" 119 echo " - Check rootdelay= (did the system wait long enough?)" 120 if [ "${name}" = root ]; then 121 echo " - Check root= (did the system wait for the right device?)" 122 fi 123 echo " - Missing modules (cat /proc/modules; ls /dev)" 124 panic "ALERT! ${dev_id} does not exist. Dropping to a shell!" 125 done 126 127 DEV = "${real_dev}" 128 } . . .

But the real problem happens when the maximum number of trials for transient hardware faults is reached (30 times for non ppc systems), line 114 at function local_device_setup() . In this case, the top level script is not aware of the root cause of the fault and drops a shell (busybox) to the user, line 124. The panic() function (see below) tries to insert additional drivers and runs a shell.

The Exploit (PoC)

The attacker just have to press and keep pressing the [Enter] key at the LUKS password prompt until a shell appears, which occurs after 70 seconds approx.

The fix

The issue can be easily fixed by stopping the boot sequence when the number of password guesses has been exhausted. The following patch suspends the execution forever. The only way to exit is by rebooting the computer.

cryptsetup_fix_CVE-2016-4484.patch --- a/scripts/local-top/cryptroot 2016-07-29 10:56:12.299794095 +0200 +++ b/scripts/local-top/cryptroot 2016-07-29 11:00:57.287794370 +0200 @@ -273,6 +273,7 @@ # Try to get a satisfactory password $crypttries times count=0 + success=0 while [ $crypttries -le 0 ] || [ $count -lt $crypttries ]; do export CRYPTTAB_TRIED="$count" count=$(( $count + 1 )) @@ -349,12 +350,15 @@ fi message "cryptsetup: $crypttarget set up successfully" + success=1 break done - if [ $crypttries -gt 0 ] && [ $count -gt $crypttries ]; then - message "cryptsetup: maximum number of tries exceeded for $crypttarget" - return 1 + if [ $success -eq 0 ]; then + message "cryptsetup: Maximum number of tries exceeded. Please reboot." + while true; do + sleep 100 + done fi udev_settle

Workaround

The panic function, which is the one that launches the shell, can prevent console access if the kernel is booted with the " panic " parameter.

initram:/scripts/functions 69 panic () 70 { 71 if command -v chvt >/dev/null 2>&1; then 72 chvt 1 73 fi 74 75 echo "$@" 76 if [ -n "${panic}" ]; then 78 echo "Rebooting automatically due to panic= boot argument" 79 sleep ${ panic } 80 reboot 81 exit fi 83 modprobe -v i8042 || true 84 modprobe -v atkbd || true 85 modprobe -v ehci-pci || true 86 modprobe -v ehci-orion || true 87 modprobe -v ehci-hcd || true 88 modprobe -v uhci-hcd || true 89 modprobe -v ohci-hcd || true 90 modprobe -v usbhid || true 91 92 run_scripts /scripts/panic 93 94 REASON = "$@" PS1 = '(initramfs) ' /bin/sh -i </dev/console >/dev/console 2>&1 95 }

Therefore, adding the "panic" parameter to the kernel entry in the grub configuration will prevent a shell.

Adding "panic" to the Linux command line. # sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="/GRUB_CMDLINE_LINUX_DEFAULT="panic=5 /' /etc/default/grub # grub-install

Discussion

The direct cause of this vulnerability is the improper checking of the maximum number of passwords, but the bug was (probably) introduced by the addition of new features (in this case security features). It is well known that "Complexity is the worst enemy of security". A system with more features requires more code and has more interactions between sub-systems, which results in harder to test systems and so more bugs.

Security is a non-functional requirement which must be analyzed globally. In this case, the "recovery" actions taken in the case of system errors should be revised and updated to match the security requirements.

About physical access

There are many "levels" of physical access. Just to mention a few:

Access to the internal parts of the computer. The attacker can remove or replace the disk, ram, insert new devices, etc. For example, your own computer.

Access to all the interfaces. The attacker can plug a USB, Ethernet, HDML or Firewire device. For example, the computers used to provide network access in public facilities.

Access to the front interfaces. Typically, the USB and the keyboard. For example, Some systems to print your photos.

Access to the keyboard and mouse/touchpad. For example, tourist information points, or the electronic check-in services in the airports.

Access to a limited keyboard or other simple user interface. Like a smart doorbell.

These are some of the scenarios where we can find a Linux system, but the IoT will increase the diversity further.

In order to protect the computer in these scenarios: the BIOS/UEFI has one or two passwords to protect the booting or the configuration menu; the GRUB also has the possibility to use multiple passwords to protect unauthorized operations.

About default configuration

In general, the GNU/Linux ecosystem (kernel, system apps, distros, ...) has been designed by developers for developers. Therefore, in the case of a fault, the recovery action is very "developer friendly", which is very convenient while developing or in controlled environments. But then Linux is used in more hostile environments, this helpful (but naive) recovery services shall not be the default option.

UEFI and GRUB contain two complete and very powerful shell facilities. Initrd system has powerful busybox with complete access to the network.

May be all this "just in case" functionality shall be remove, or seriously reconsidered, for the sake of security.