Exploiting a vulnerability in HTC One bootloader and bruteforcing the PIN/password

Wed 23 July 2014 by cedric


This article deals with the presence of the "read_mmc" command in the HTC One phone. Our target phone had Android 4.2.2 and HBOOT 1.54.0000. This vulnerability has been reported to HTC in February 2014 and has been fixed with the Kit Kat (4.4.2) upgrade released in March 2014. Since then, HTC has told us it will be addressed into operators ROMs. We are happy to say that it has been patched in all of them except one. As a consequence, we have decided to release the information about it.

The "read_emmc" command had already been disclosed in a previous article for the HTC Desire Z, released in 2011.

This command allows an attacker with physical access to read the flash memory of the phone, and possibly get sensitive information such as SMS messages, contacts and so on.


Furthermore, this command allows an attacker to bruteforce the PIN/passcode in an automatic way that would not be possible without it. It opens an additional breach against users that define easily-guessable PIN/passcodes (such as 4-digit PIN). It is often the case because this same PIN/passcode is also used to unlock the phone on a daily basis.

Finally, the attack presented in this article also applies to HTC One devices where Full Disk Encryption (FDE) is enabled, i.e. when the phone is protected with Android encryption.

The “read_mmc” command appears to be a debug function that is not on every HTC phone. In our opinion, this command should not appear in any released phone.

This articles details the strong security mechanisms (AES encryption, correct key size, salt) used in Android FDE for the HTC One and the problematic context: the « read_mmc » debug command and a weak PIN/password allow an attacker to bruteforce it "offline" (from a computer) and access user protected data.

Accessing the flash memory

The HTC One is powered down and plugged to our computer. Then it is put in fastboot mode. This can be done by holding VOL DOWN + POWER buttons then releasing POWER while holding VOL DOWN. Then, we can switch from HBOOT to fastboot mode.


From there, we can use the “fastboot” binary from Android SDK to read the flash memory. The command has the following format:

command format:
read_mmc [emmc/sd] [start] [#blocks] [#blocks/read] [show]

The arguments are defined as such:

  • first parameter tells where to read from. “emmc” to read the flash. “sd” to read the sdcard
  • start: offset (in blocks i.e. 512-byte units) in the raw flash memory
  • #blocks: number of blocks to read
  • #blocks/read: number of blocks to read at a time
  • show: set to 1 to display the result
  • An advised user may have noticed it is called "read_mmc" here instead of the older "read_emmc" command but its purpose is the same.

To read the first sector, one can use the following command:

$ fastboot oem read_mmc emmc 0 1 1 1
(bootloader) reading sector 0 ~ 0
(bootloader) 0
(bootloader) 0
(bootloader) DF
(bootloader) FF
(bootloader) 3
(bootloader) 0
(bootloader) 20
(bootloader) E0
(bootloader) 9F
(bootloader) 3
(bootloader) 55
(bootloader) AA
(bootloader) read sector done average = 172
OKAY [  0.310s]
finished. total time: 0.311s

We can see it has lots of zeros at the beginning (more than 400 bytes) and it ends with the “55 AA” magic bytes, being the magic for a partition table.

Using an ADB shell on the device, we see the userdata partition is the “mmcblk0p37” block device and starts at the 6422528th sector. It corresponds to the “ext4” mounted partition under Android.

shell@android# cat /proc/emmc
dev:        size     erasesize name
mmcblk0p37: 680000000 00000200 "userdata"

shell@android:# cat /sys/block/mmcblk0/mmcblk0p37/start

shell@android:# mount
/dev/block/mmcblk0p37 /data ext4 rw,nosuid,nodev,noatime,discard,noauto_da_alloc,data=ordered 0 0

Consequently, an attacker can use the “read_mmc” command and the previous offset (6422528 and after) in the flash memory to read any sector within the userdata partition even if the user defined a PIN/passcode to protect his phone.

The “2F 64 61 74 61” sequence of bytes is the “/data” ascii string that is located at the beginning of the userdata partition.

As we already detailed with the previous article, the first idea we got was to realize a dump of the whole userdata partition from the flash memory. However, it is really slow and it would take several days or even months. As a side note, the HTC One phone does not discharge when in HBOOT/fastboot modes and plugged to a computer. So it is theoretically “easier” to realize a whole dump as it was with the HTC Desire Z.

Another approach is to use FUSE (Filesystem in Userspace) to mount the userdata partition remotely (over USB) from a computer. Mounting the partition only requires reading a few sectors and is significantly faster. We can then access any file. Indeed, this also works for the HTC One.


Bypassing the Android Full Disk Encryption (FDE)

When working on the HTC Desire Z, there was no “Full Disk Encryption” (FDE) option available because it was Android 2.x at that time and encryption is not supported before Android 4.x for mobile phones. We decided to analyze if there was a way to bypass FDE using the “read_mmc” vulnerability.

Thomas Cannon has published back in 2012 at Defcon his excellent slides showing how FDE is working for default Android (based on Android source code, a.k.a AOSP) and scripts to both bruteforce the PIN/passcode and decrypt userdata sectors. At that time, he has been working on the Google Nexus S, which is a phone built by Google itself. Consequently, it uses the default Android sources and has not been modified by any manufacturer. This is different with our HTC One since this is HTC who built it from its own version of modified AOSP and hardware.

We decided to encrypt the device by enabling it in “Storage > Phone storage encryption”. After dumping all the partitions and diffing them with a dump we made before encryption, we easily notice the “extra” partition is the FDE header used to store the encrypted master key. As detailed in Thomas slides, the PIN/passcode defined by the user is used in conjunction with the encrypted master key (between {...} below) and salt (between [...] below) to derive the decrypted master key. This decrypted master key is then used to decrypt each sector of the userdata partition. We can also infer from the header the algorithm used for the /data sector decryption (aes-cbc-essiv:sha256).

$ hexdump -C extra
00000000  c4 b1 b5 d0 01 00 00 00  68 00 00 00 00 00 00 00  |........h.......|
00000010  20 00 00 00 00 00 00 00  00 00 40 03 00 00 00 00  | .........@.....|
00000020  00 00 00 00 61 65 73 2d  63 62 63 2d 65 73 73 69  |....aes-cbc-essi|
00000030  76 3a 73 68 61 32 35 36  00 00 00 00 00 00 00 00  |v:sha256........|
00000040  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000060  00 00 00 00 00 00 00 00 {15 d2 9c 16 1c 54 40 1c  |.............T@.|
00000070  b4 c1 e4 91 69 10 4b 55  2e 47 64 31 13 52 ad 2d  |....i.KU.Gd1.R.-|
00000080  bd 8c 42 8e d6 c4 84 00} 00 00 00 00 00 00 00 00  |..B.............|
00000090  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000a0  00 00 00 00 00 00 00 00 [c7 1f 34 80 97 09 fd 39  |..........4....9|
000000b0  0b 4a 91 d9 d9 d8 00 cd] 00 00 00 00 00 00 00 00  |.J..............|
000000c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

Note: for further details on the master key derivation and data decryption internals, we will definitely advise you to have a look at Thomas’ slides.

Since we located where the encryption header is, we easily get the offset in the flash memory where it is stored.

shell@android# cat /proc/emmc
dev:        size     erasesize name
mmcblk0p27: 00010000 00000200 "extra"

shell@android:# cat /sys/block/mmcblk0/mmcblk0p27/start

Then, we can double-check that our userdata partition is encrypted, as the first bytes amusingly tell it: “This is an encrypted device:)”. This is some kind of addition made by HTC for the HTC One specifically. They can do so because the first bytes are not used in a default ext4 partition. Everything else is random bytes, as expected.

shell@android:# ./busybox hexdump -C /dev/block/mmcblk0p37 -n 64
00000000  54 68 69 73 20 69 73 20  61 6e 20 65 6e 63 72 79  |This is an encry|
00000010  70 74 65 64 20 64 65 76  69 63 65 3a 29 6f c3 a0  |pted device:)o..|
00000020  26 bc 76 ed a8 77 ef 6a  95 28 32 ab 24 ce 8d 58  |&.v..w.j.(2.$..X|
00000030  91 fe 8e 14 9e 81 05 a4  28 65 64 3c 1b e2 11 56  |........(ed<...V|

We can then check that we can access this header and the encrypted userdata partition from fastboot “read_mmc” command, which is indeed possible.

$ fastboot oem read_mmc emmc 586799 1 1 1

From this, we can build a small script that will read the FDE header (located in the “extra” partition) and the first sector of the “userdata” partition and bruteforce them locally from our computer.

# python bruteforce_htcone_over_reademmc.py
oem read_mmc emmc 6422528 1 1 1
oem read_mmc emmc 586799 1 1 1
Footer File    : extra
Magic          : 0xD0B5B1C4
Major Version  : 1
Minor Version  : 0
Footer Size    : 104 bytes
Flags          : 0x00000000
Key Size       : 256 bits
Failed Decrypts: 0
Crypto Type    : aes-cbc-essiv:sha256
Encrypted Key  : 0x15D29C161C54401CB4C1E49169104B552E4764311352AD2DBD8C428ED6C48400
Salt           : 0xC71F34809709FD390B4A91D9D9D800CD
Trying to Bruteforce Password... please wait
Found PIN!: 0000
Saving decrypted master key to 'keyfile'

We can easily bruteforce any 4-digit PIN in a matter of minutes with a regular PC. This takes a little bit of time since the master key derivation needs 2000 iterations, but it is definitely possible. Additionally, we save the decrypted master key for further analysis.

The PIN/passcode setup by the user is used for both:

  • decrypting the phone when it is switched on (1)
  • accessing the phone after a given delay during a regular day use (2)

Even if the user wants to protect his phone with a complex PIN/password for (1), he will definitely want to use a simple one for (2) because he will use it a lot to access his phone. Consequently, the scenario of bruteforcing the PIN/passcode assuming that it is a 4-digit PIN (and not a complex one such as having digits and letters) makes sense. Moreover, encrypting one phone using schemes instead of PIN/password is not supported in Android for now. We can add that it would not help against bruteforce since the scheme is stored as a sequence of numbers that do not repeat.

Mounting the userdata encrypted partition (remotely over USB)

Since an attacker is able to bruteforce the PIN/passcode easily using what we explained above, he is able to switch on the phone normally and write the found PIN/passcode to bypass the lock screen. Then, he is able to enable ADB and dump everything he wants.


We do not need to go further. However, as a need for completeness (and also because it is always interesting to know how to mount an encrypted userdata partition), we will detail how to do it. Basically, this consists of using cryptsetup (version >= 1.60 in order to support the plain type) specifying the “plain” type, the decryption algorithms (aes-cbc-essiv:sha256) and the “keyfile” holding our previously decrypted master key.

$ mkdir mnt
$ losetup /dev/loop0 userdata.img
$ cryptsetup –type plain open –c aes-cbc-essiv:sha256 –d keyfile /dev/loop0 userdata
$ mount /dev/mapper/userdata mnt

In our case, we "even" can do it over USB using the “read_mmc” command.

All the tools to replay these scenarios are released into our github repository.

Again, we would like to thank HTC security team for their support and by patching this vulnerability in Kit Kat upgrade.