Breakdown of the DPT-RP1 rooting

Some time in December 2018, people on xda-developers managed to root the Sony DPT-RP1 e-reader. So I wanted to understand how they discovered it, and how the exploit works.

How the exploit works

The first step of the exploit is to flash the device with two (bogus) firmware updates. According to exploit instructions, we are supposed to use a Python program to flash two bogus firmware updates, which are supposed to fail.

It seems like a parsing vulnerability, How does that work, and how does it get past the firmware digest verification?

The DPT firmware update format

The DPT update package has the following format, reverse engineered from start_eufwupdater.sh

Offset (incl-incl) Purpose
0x00-0x03 “DPU8” (Digital Paper Update)
0x04-0x07 DATA_OFFSET (e.g. ” 568″)
0x08-0x0b BODY_SIZE (e.g. ” 232976″)
0x0c-0x0f ????
0x14-0x113 Signature (size: 256)
0x114-0x117 ENC_KEY_SIZE (4 bytes e.g. 256)
0x118-0x217 AES256_KEY
0x218-0x237 IV
0x238- Data content

Diffing FactoryReset.pkg vs JB.pkg

Let’s diff the two pkg files and see where the update script treats them differently. We’ll run through the dd commands in start_eufwupdater.sh, and see where the outputs start to differ.

$ DATA_OFFSET=`dd if=FactoryReset.pkg bs=4 skip=1 count=1 2>/dev/null | od -A n -t d4 -v`
$ echo "$DATA_OFFSET"
         568
$ DATA_OFFSET=`dd if=JB.pkg bs=4 skip=1 count=1 2>/dev/null | od -A n -t d4 -v`
$ echo "$DATA_OFFSET"
         568
$ BODY_SIZE=`dd if=FactoryReset.pkg bs=4 skip=2 count=1 2>/dev/null | od -A n -t d4 -v`
$ echo "$BODY_SIZE"
      232976
$ BODY_SIZE=`dd if=JB.pkg bs=4 skip=2 count=1 2>/dev/null | od -A n -t d4 -v`
$ echo "$BODY_SIZE"
      232976
$ SIG_SIZE=`dd if=FactoryReset.pkg bs=4 skip=4 count=1 2>/dev/null | od -A n -t d4 -v`
$ SIG_SIZE=`dd if=JB^Ckg bs=4 skip=4 count=1 2>/dev/null | od -A n -t d4 -v`
$ echo "$SIG_SIZE"
         256
$ SIG_SIZE=`dd if=JB.pkg bs=4 skip=4 count=1 2>/dev/null | od -A n -t d4 -v`
$ echo "$SIG_SIZE"
         256
$ dd if=FactoryReset.pkg bs=1 skip=20 count=$(($SIG_SIZE)) 2>/dev/null | md5sum
f89f0c9059c5f7e06357b33910a18af9  -
$ dd if=JB.pkg bs=1 skip=20 count=$(($SIG_SIZE)) 2>/dev/null | md5sum
f89f0c9059c5f7e06357b33910a18af9  -
$ dd if=FactoryReset.pkg bs=$(($DATA_OFFSET)) skip=1 2>/dev/null | head -c $(($BODY_SIZE)) | md5sum
a2d4d32d98f96242b83b8621616abfb1  -
$ dd if=JB.pkg bs=$(($DATA_OFFSET)) skip=1 2>/dev/null | head -c $(($BODY_SIZE)) | md5sum
a2d4d32d98f96242b83b8621616abfb1  -
$ ENC_KEY_SIZE=`dd if=FactoryReset.pkg bs=1 skip=${ENC_KEY_OFFSET} count=4 2>/dev/null | od -A n -t d4 -v`
$ echo "$ENC_KEY_SIZE"
         256
$ ENC_KEY_SIZE=`dd if=JB.pkg bs=1 skip=${ENC_KEY_OFFSET} count=4 2>/dev/null | od -A n -t d4 -v`
$ echo "$ENC_KEY_SIZE"
         256
$ dd if=FactoryReset.pkg bs=1 skip=${ENC_KEY_OFFSET} count=$(($ENC_KEY_SIZE)) 2>/dev/null | md5sum
cac05d9116db1420e21f379d88939274  -
$ dd if=JB.pkg bs=1 skip=${ENC_KEY_OFFSET} count=$(($ENC_KEY_SIZE)) 2>/dev/null | md5sum
f02f33824e15d65cfdaf208606793fc1  -

Here we see that the only difference between FactoryReset.pkg and JB.pkg is the encryption key.

The DPT update package embeds the symmetric encryption key for the firmware, and the embedded key is encrypted again with a static symmetric decryption key stored on the device. We can change the encryption key by encrypting the desired plaintext with the leaked static decryption key.

Shell injection vulnerability

To figure out why JB.pkg’s encryption key is special, I decrypted it, and found this:

00000000: ZGFlbW9uOng6MTox
00000010: OjovdXNyL3NiaW46
00000020: L2Jpbi9mYWxzZQpu
00000030: b2JvZH -k.6eDo2N
00000040: TUzNDo2NTUzNDo6L
00000050: 25vbmV4aXN0ZW50O
00000060: i9iaW4vZmFsc2UKc
00000070: m9vdDo -k.MSQxJE
00000080: FlZ2VZbTFRYWFUeW
00000090: QvMWZPaVhWZDA6MD
000000a0: owOjovcm9vdDovYm
000000b0: luL3NoCg== -none
000000c0:  -in /tmp/aes256
000000d0: .key -out /etc/p
000000e0: asswd -a

It’s obvious that this is a shell injection vulnerability.

Looking at the start_eufwupdater.sh:

openssl enc -d -aes-256-cbc -K `cat ${AES256_KEY}` -iv `cat ${IV}`

Because we have control of the AES256_KEY, and it’s never digest verified (only the firmware data is verified), we can inject any arguments we want.

How the exploit was discovered

Somehow acquire FactoryReset.pkg along with decryption keys

The very first sign of useful information seems to have come when someone acquired a Chinese-rooted DPT-RP1 device, and extracted the firmware update mechanism and published it.

It seems someone rooted a copy of the device using hardware methods, and extracted the FactoryReset.pkg along with keys used to verify and decrypt the package.

This shows the value of hardware hacking, even when trying to develop software exploits.

Reference

https://forum.xda-developers.com/showpost.php?p=78140924&postcount=68

https://github.com/octavianx/Unpack-and-rebuild-the-DPT-RP1-upgrade-firmware

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s