project zeus "You will not be informed of the meaning of Project Zeus until the time is right for you to know the meaning of Project Zeus."

Archives Current Posts April 2010 May 2010 August 2010 September 2012 February 2013 March 2013 April 2013 May 2013 June 2013 December 2013 March 2014 January 2015 Posts Exploiting Samsung Galaxy S4 Secure Boot Exploiting Samsung Galaxy S4 Secure Boot Launched in April 2013, the Samsung Galaxy S4 is expected to be one of the top-selling smartphones of the year, having sold 10 million units in its first month of sales. While the majority of released models include an unlocked bootloader, which allows users to flash custom kernels and make other modifications to the software on their own devices, AT&T and Verizon branded devices ship with a locked bootloader that prevents these types of modifications. In this post, I'll provide details on how Samsung implement this locking mechanism, and publish a vulnerability in the implementation that allows bypassing the signature checks to run custom unsigned kernels and recovery images.



boot and recovery partitions.



A quick glance at aboot (adopting the name of the partition on which this bootloader resides) revealed that it is nearly identical to the open source lk ("Little Kernel") project, which undoubtedly saved me many hours of tedious reverse engineering. By locating cross-references to strings found in both lk and aboot, I was able to quickly identify the functions that implement signature verification and booting of the Linux kernel.



The central logic to load, verify, and boot the Linux kernel and ramdisk contained in either the boot or recovery partitions is implemented in the boot_linux_from_mmc() function. First, the function determines whether it is booting the main boot partition, containing the Linux kernel and ramdisk used by the Android OS, or the recovery partition, which contains the kernel and ramdisk used by the Android recovery subsystem. Then, the first page of the appropriate partition is read into physical memory from the eMMC flash storage:



if (!boot_into_recovery) { index = partition_get_index("boot"); ptn = partition_get_offset(index); if (ptn == 0) { dprintf(CRITICAL, "ERROR: No boot partition found

"); return -1; } } else { index = partition_get_index("recovery"); ptn = partition_get_offset(index); if (ptn == 0) { dprintf(CRITICAL, "ERROR: No recovery partition found

"); return -1; } } if (mmc_read(ptn + offset, (unsigned int *) buf, page_size)) { dprintf(CRITICAL, "ERROR: Cannot read boot image header

"); return -1; } Launched in April 2013, the Samsung Galaxy S4 is expected to be one of the top-selling smartphones of the year, having sold 10 million units in its first month of sales. While the majority of released models include an unlocked bootloader, which allows users to flash custom kernels and make other modifications to the software on their own devices, AT&T and Verizon branded devices ship with a locked bootloader that prevents these types of modifications. In this post, I'll provide details on how Samsung implement this locking mechanism, and publish a vulnerability in the implementation that allows bypassing the signature checks to run custom unsigned kernels and recovery images. Both the AT&T (SGH-I337) and Verizon (SCH-I545) models utilize the Qualcomm APQ8064T chipset. As described in my previous blog post on Motorola's bootloader , Qualcomm leverages software-programmable fuses known as QFuses to implement a trusted boot sequence. In summary, each stage of the boot process cryptographically verifies the integrity of the subsequent stage, with the trust root originating in QFuse values. After the early boot stages bootstrap various hardware components, Samsung's APPSBL ("Application Secondary Bootloader") is loaded and run. This bootloader differs between "locked" and "unlocked" variants of the Galaxy S4 in its enforcement of signature checks on theandpartitions.A quick glance at(adopting the name of the partition on which this bootloader resides) revealed that it is nearly identical to the open source("Little Kernel") project, which undoubtedly saved me many hours of tedious reverse engineering. By locating cross-references to strings found in bothand, I was able to quickly identify the functions that implement signature verification and booting of the Linux kernel.The central logic to load, verify, and boot the Linux kernel and ramdisk contained in either theorpartitions is implemented in thefunction. First, the function determines whether it is booting the mainpartition, containing the Linux kernel and ramdisk used by the Android OS, or thepartition, which contains the kernel and ramdisk used by the Android recovery subsystem. Then, the first page of the appropriate partition is read into physical memory from the eMMC flash storage:

This code is straight out of lk's implementation. Next, after performing some sanity-checking of the boot image, which contains a custom header format, the function loads the kernel and ramdisk into memory at the addresses requested in the boot image header: hdr = (struct boot_img_hdr *)buf; image_addr = target_get_scratch_address(); kernel_actual = ROUND_TO_PAGE(hdr->kernel_size, page_mask); ramdisk_actual = ROUND_TO_PAGE(hdr->ramdisk_size, page_mask) + 0x200; imagesize_actual = (page_size + kernel_actual + ramdisk_actual); memcpy(image_addr, hdr, page_size); offset = page_size; /* Load kernel */ if (mmc_read(ptn + offset, (void *)hdr->kernel_addr, kernel_actual)) { dprintf(CRITICAL, "ERROR: Cannot read kernel image

"); return -1; } memcpy(image_addr + offset, hdr->kernel_addr, kernel_actual); offset += kernel_actual; /* Load ramdisk */ if (mmc_read(ptn + offset, (void *)hdr->ramdisk_addr, ramdisk_actual)) { dprintf(CRITICAL, "ERROR: Cannot read ramdisk image

"); return -1; } memcpy(image_addr + offset, hdr->ramdisk_addr, ramdisk_actual); offset += ramdisk_actual;

This is still essentially identical to lk's implementation, with the addition of code to copy the individual pieces of the boot image to the image_addr location. Finally, the function performs signature verification of the entire image. If signature verification succeeds, the kernel is booted; otherwise, a tampering warning is displayed and the device fails to boot:

if (check_sig(boot_into_recovery)) { if (!is_engineering_device()) { dprintf("kernel secure check fail.

"); print_console("SECURE FAIL: KERNEL"); while (1) { /* Display tampered screen and halt */ ... } } } /* Boot the Linux kernel */ ...

The is_engineering_device() function simply returns the value of a global variable that is set at an earlier stage in the boot process based on whether or not the chipset ID (an unchangeable hardware value) of the device indicates it is an engineering or production device.



Examining the check_sig() function in more detail revealed that aboot uses the open-source mincrypt implementation of RSA for signature validation. The bootloader uses an RSA-2048 public key contained in aboot to decrypt a signature contained in the boot image itself, and compares the resulting plaintext against the SHA1 hash of the boot image. Since any modifications to the boot image would result in a different SHA1 hash, it is not possible to generate a valid signed boot image without breaking RSA-2048, generating a specific SHA1 collision, or obtaining Samsung's private signing key.



The astute reader will have already noticed the design flaw present in the above program logic. Notice the order in which the steps are performed: first, aboot loads the kernel and ramdisk into memory at the addresses requested by the boot image header, and then signature validation is performed after this loading is complete. Because the boot image header is read straight from eMMC flash prior to any signature validation, it contains essentially untrusted data. As a result, it's possible to flash a maliciously crafted boot image whose header values cause aboot to read the kernel or ramdisk into physical memory directly on top of aboot itself!



Exploitation of this flaw proved to be fairly straightforward. I prepare a specially crafted boot image that specifies a ramdisk load address equal to the address of the check_sig() function in aboot physical memory. In my malicious boot image, I place shellcode where the ramdisk is expected to reside. I flash this image by leveraging root access in the Android operating system to write to the boot block device. When aboot reads the supposed ramdisk from eMMC flash, it actually overwrites the check_sig() function with my shellcode, and then invokes it. The shellcode simply patches up the boot image header to contain sane values, copies the actual kernel and ramdisk into appropriate locations in memory, and returns zero, indicating the signature verification succeeded. At this point, aboot continues the boot process and finally boots my unsigned kernel and ramdisk. Victory!



Thanks to ralekdev for the helpful exchange of ideas and suggestions. This is still essentially identical to's implementation, with the addition of code to copy the individual pieces of the boot image to thelocation. Finally, the function performs signature verification of the entire image. If signature verification succeeds, the kernel is booted; otherwise, a tampering warning is displayed and the device fails to boot:Thefunction simply returns the value of a global variable that is set at an earlier stage in the boot process based on whether or not the chipset ID (an unchangeable hardware value) of the device indicates it is an engineering or production device.Examining thefunction in more detail revealed thatuses the open-sourceimplementation of RSA for signature validation. The bootloader uses an RSA-2048 public key contained into decrypt a signature contained in the boot image itself, and compares the resulting plaintext against the SHA1 hash of the boot image. Since any modifications to the boot image would result in a different SHA1 hash, it is not possible to generate a valid signed boot image without breaking RSA-2048, generating a specific SHA1 collision, or obtaining Samsung's private signing key.The astute reader will have already noticed the design flaw present in the above program logic. Notice the order in which the steps are performed: first,loads the kernel and ramdisk into memory at the addresses requested by the boot image header, and then signature validation is performed after this loading is complete. Because the boot image header is read straight from eMMC flash prior to any signature validation, it contains essentially untrusted data. As a result, it's possible to flash a maliciously crafted boot image whose header values causeto read the kernel or ramdisk into physical memory directly on top ofitself!Exploitation of this flaw proved to be fairly straightforward. I prepare a specially crafted boot image that specifies a ramdisk load address equal to the address of thefunction inphysical memory. In my malicious boot image, I place shellcode where the ramdisk is expected to reside. I flash this image by leveraging root access in the Android operating system to write to the boot block device. Whenreads the supposed ramdisk from eMMC flash, it actually overwrites thefunction with my shellcode, and then invokes it. The shellcode simply patches up the boot image header to contain sane values, copies the actual kernel and ramdisk into appropriate locations in memory, and returns zero, indicating the signature verification succeeded. At this point,continues the boot process and finally boots my unsigned kernel and ramdisk. Victory!Thanks to ralekdev for the helpful exchange of ideas and suggestions. 56 comments: Subscribe to Post Comments [Atom] << Home