Wear's the MITM?
Roman Faynberg - Wed, 19 Oct 2016

Recently, we needed to man-in-the-middle TLS traffic coming from an Android Wear application. On a regular Android app, this would be an easy thing to do, but we started to run into trouble pretty quickly on the only Android watch that we had at our disposal, the 1st generation LG Watch Urbane. What made the task harder was that the Google deities weren't helping greatly -- has no one ever had this problem before?

In this post, we would like to fill that gap and describe the steps we took to make MiTM-ing the watch rather easy.

So, there is an Android Wear watch, an app on the watch, and a companion app that communicates with it from the phone's side. Where does an attacker begin to intercept TLS traffic that goes to the outside world? That's an interesting question because the traffic can come from both the phone app and the watch. To perform MiTM an attacker must intercept traffic from both apps. Doing this on a regular Android device is well understood: it's a standard procedure to get a MiTM certificate into the Android credentials store, and the ways to bypass pinning, if it's there, are also plenty (for example: Xposed's SSLUnpinning module). However, the same techniques are more complex on an Android Wear watch. Repackaging the APK with one of our certificates added in broke signature verification, which caused the app to fail spectacularly. It's also messy repackaging both the companion and the watch APKs. There is no way to directly import a trusted CA certificate (e.g. a cert from Burp or Mallory) into the watch the way there is on a regular phone (we tried).

In theory, this is easy: root the watch, mount /system read/write, push the certificate and voila. The big problem is, even if you are root, you can't mount /system to be writeable. On tiny devices, such as the watch, /system is a SquashFS partition that's read-only by definition, and once it's mounted, you just can't write to it.

After thinking through various avenues of attack, we decided that, given the time constraints, the most reasonable way out would be to try something less typical: to grab the stock /system image for the watch and modify it to have Mallory's certificate (our tool of choice for MiTM-ing device traffic). Luckily, LG was very kind to leave the bootloader open on the watch, which allowed us to flash arbitrary images onto boot, recovery, and system partitions. We decided to focus our efforts on the system partition with the goal of pushing Mallory's certificate into the /system/etc/security/cacerts/ folder.

We got a Marshmallow-based LG Watch Urbane /system image from XDA and extracted it onto the file system (note: we used a Kali VM for all SquashFS operations):

unsquashfs MM-system.img

Now, we can go into the resulting squashfs-root/, go down to /etc/security/cacerts and drop our Mallory cert there. We just need to remember two important steps:

1) In order for Android to pick up the certificate from the trust store, its file name needs to match the hash of the certificate (CACert.org instructions)

2) To ensure that this file gets picked up with SELinux set to "Enforcing", you'll need to make sure that the newly created file with the certificate also carries proper SELinux context attributes.

Let's generate the hash of the Mallory certificate first:

root@kali:~/mallory/src/ca# openssl x509 -inform PEM -subject_hash_old -in ca.cer | head -1
66cb9958

Next, we need to cat our Mallory certificate into a file called "66cb9958" with ".0" at the end. So, the final file would be etc/security/cacerts/66cb9958.0. Moving on: let's align the SELinux context to ensure that the system will be able to pick up the file. To make this easier, we can just copy the attributes from another file in the same directory, using the chcon's "--reference" switch:

chcon --reference=someothercert.0 66cb9958.0

Now that the certificate is ready, we can repackage our system partition in that currently resides in squashfs-root/:

mksquashfs squashfs-root/ altered-niko-system.img

And finally, it's time to cross our fingers (hoping that nothing blows up or turns into a rectangular block of clay. But hey! If it does, we still have our stock images, don't we?) and flash the image using fastboot:

$ fastboot flash system altered-niko-system.img

And it works! Now the traffic flowing from the watch is very nicely intercepted. In this particular instance, we ended up changing our setup a bit and instead of using Mallory in a VM, we imported Mallory's certificate into Burp on our host machine and sent all the traffic to it. Regarding MiTM setups and routing: getting the interception setup up and running in an easy and elegant configuration will be covered in future blog post.