Reverse Engineering & Exploitation of a “Connected Alarm Clock”


I received the Aura, a device advertised as a “Connected Alarm Clock”. This device in itself is quite cool and uses different sounds and color patterns to help the user fall asleep and wake him up during light stages of his sleep cycles.

The Aura

The Aura

Soon I was interested in doing some reverse engineering on it because:

  • It was fun
  • I wanted to really own the device, I wanted to be able to run my own code on it

This article describes my journey into the Aura, from firmware image grabbing to remote buffer overflow exploitation.

The manufacturer has been contacted about the issues exposed in this article.

They already knew some of the vulnerabilities and quickly worked on fixing the others. Since March 2017, the firmware are not vulnerable to these flaws anymore.

No firmware images, complete binary files or complete scripts will be released in this article. This article serves a purely educational purpose.


First Analysis

I first needed to know more about the hardware of the Aura. As it’s not exactly cheap, I wanted to avoid cracking the device open yet. I just had a glance at the publicly available documents from the FCC certification report available here: https://fccid.io/XNAWSD01

The (blurry) internal photos revealed the Aura was powered by a Freescale (now NXP) processor and everything you need to run an embedded Linux operating system.

Internal picture from FCC documents

Internal picture from FCC documents

This assumption was confirmed after I ran nmap against the device who is always connected to the WiFi hotspot it has been configured for.

Port 22 appeared as filtered, but a SSH server was responding. Of course, without as valid password or SSH key, this wasn’t really useful yet.

On the Bluetooth side the Aura is discoverable. A SDP server is running and let us know the following services are running.


Firmware Grabbing

To go further, I needed to grab the firmware of the device. As explained before, cracking it open was not an option yet.

Instead I set up a MITM configuration to sniff the communication flowing between the Aura and its servers during a firmware upgrade procedure.

It quickly appeared that what looked liked a firmware image was downloaded using HTTP.


Firmware Image Analysis

Filesystem extraction

It was not a surprised, but the downloaded Image first appeared to be something custom, with something that looked like a header at the beginning. We will further refer to this file format as a FPKG file.

Nevertheless, as always in this kind of situation using binwalk can quickly reveal where the interesting bits are.

The downloaded blob was containing a UBIFS image at offset 0x1C (probably just after what was looking like a header).

Extracting the files from the UBIFS image was rather easy thanks to the scripts from https://github.com/jrspruitt/ubi_reader

All the files from the from the embedded Linux were now accessible! The first thing I did was of course to check the content of the /etc/shadow file. I launched a the john password cracker against it, but gave up after a couple of minutes. The password was probably to complicated for this. Entering the device thanks to a simple brute force attack would have disappointing anyway.

The FPKG file format

Now that all the files were available, it was possible to understand the FPKG structure.

The functions linked to firmware updates and the FPKG files were available in the two shared libraries libfpkg.so and libufw.so. After some disassembly and guesswork, I came up with the following structure.

A ksy file describing this structure (http://kaitai.io/) is available here.

Applying this structure to the file I obtained before gave me:

The file was signed, so it was not possible to update my own firmware yet.


Getting a Root SSH Access

After having obtained the firmware, the next step was to obtain an SSH access. I started looking at the binaries running on the board and tried to find some vulnerabilities.

Directory Traversal Attack On Seqmand

One of the daemon called seqmand caught my attention. seqmand is responsible for automatically downloading audio files from remote servers. It is working in the following way:

  • At boot, seqmand downloads a csv file.
  • A typical aura_seq_list.csv looks like the following listing.
  • For each row of the csv, seqmand will download the corresponding file to a temporary folder. For instance, by using the previous csv file, seqmand will do the following.
  • The temporary files are finally moved to the /usr/share/sequences folder.

I redirected the HTTP requests of seqmand to my own rogue HTTP server and served custom aura_seq_list.csv files. I quickly noticed a directory traversal attack was possible.

For instance, if I used the following csv and served a test file with a valid MD5:

seqmand was doing the following:

I emulated the daemon on my laptop using a statically compiled qemu. The /test file was created.

I won’t spend too much time explaining how to compile and use qemu. Others articles already did that. See for instance this.

My first plan was of course to overwrite the /etc/shadow file with my own password.

Just like before, this was working just fine when I emulated the attack on my laptop using qemu. Nevertheless, the attack was failing on the Aura. Thanks to another trick, I was able to understand why.

Log Files Grabbing

While browsing through the files available on the filesystem, I bumped into the /usr/bin/usb_hd_hotplug script. It’s automatically launched as soon as a USB drive is plugged in one the Aura’s ports.

This script does the following:

  • mount the USB drive
  • check for a signed script, and run it if it’s valid
  • run a flash_from_usb function
  • run a copy_logs function

The signed script cannot be used. The flash_from_usb requires a signed FPKG image. Nevertheless, the copy_logs function just searches for a file called withings-options containing the line copy_logs=1. If this file is present on the USB drive, the script will copy log files on it.

A Working Directory Traversal Exploit

Thanks to the logs, I realized most of the operating system was running on read-only partitions (which was not that big of a surprise). Nevertheless, some parts were still writable.

The following piece of code comes from the /etc/init.d/prepare_services script.

It means a collection of runsv processes folders (see http://smarden.org/runit/runsv.8.html and http://smarden.org/runit/runsvdir.8.html for reference) are launched from the writable /var/service directory.

For instance, at runtime the content of /var/service/sshd/ is the following.

The file run is the startup script that will be executed when the service is launched while everything in the supervise/ folder can be used to interact with the process.

I decided to overwrite the /var/service/sshd/run script. Unfortunately, this was not enough. This script was only launched once at boot time and long before I can overwrite it. I needed a way to force a restart of the ssh daemon.

That’s why I also used the /var/service/sshd/supervise/control named pipe. According to the man page of runsv, it is possible to kill or relauch the service by writing into it. For instance, doing

will kill and relaunch the sshd service and execute the run script again.

I then used the following csv file.

My server was serving the following run file:

And replied with a k at the first hit of the control file, and with a u at the second hit.

The attack was a success, I had a root SSH access. The (quite dirty) scripts I used are available here.

Installing gdbserver

Having a SSH access allowed me to get a better understanding of how the Aura’s internals were working. Further, a lot of cool binaries and scripts let me play with the peripherals of the Aura. I was able to play with the 7-segments display, to turn lights on and off, …

To go even further, I decided to cross compile a gdbserver. I went the lazy way and built it thanks to Buildroot. The Buildroot configuration I used is available here.

For those unfamiliar with Buildroot, all you need to do is to copy my defconfig file into the configs/ folder of a freshly cloned buildroot repo, and run the following commands:

The gdbserver binary will be available in output/target/usr/bin/.

For whatever reason, the resulting gdbserver was not working perfectly. It was sometimes crashing. But it was enough to put a breakpoint and explore the memory.


Bluetooth RCE

Thanks to the SSH access and the gdbserver, I have been able to discover and exploit a buffer overflow vulnerability in the Bluetooth protocol of the Aura.

Bluetooth Communications Reverse Engineering

To understand the way smartphone App communicates with the Aura, I started by using the “Bluetooth HCI snoop log” developper feature of my Android phone. It let me sniff all the Bluetooth communication between my phone and the device.

The App is using RFCOMM on channel 9 to communicate with the device. This service is one of the two advertised by the SDP server (see the “First analysis” section).

As a first step, I tried replaying some of the packets I saw when I was playing with the clock display brightness. I sent the following payloads:

By using this small python script:

It worked as expected.

I next tried to understand the structure of the packets I sent. Helped by the disassembly of a shared library called libpairing.so and nm, the binary responsible of Bluetooth and WiFi communications, I was able to figure out the following.

A ksy file describing this structure (http://kaitai.io/) is available here.

Applying this structure against one of the brightness control payload we used before gives:

I didn’t try to understand what was the first byte of the argument_data, but the second was obviously a value representing the brightness.

An harcoded array in the nm binary makes a link between the command IDs and the corresponding functions. Some of these commands were probably not aimed at being used by the smartphone App. The command 0x205, called cmd_perso was especially interesting.

The cmd_perso Command

The command cmd_perso can be used to read and write configuration data from the board. This data can for instance be:

  • The unique manufacturing id of the device
  • The hostname of a some server
  • A “secret” (I’m not sure of what this secret is actually doing and I didn’t really try to unsderstand. I guess it may be used during an authentification process or something like that)

The command can also be used to read and write Uboot environment variables. It can finally be used to reset user settings. No need to say this is a quite dangerous command. Furthermore, the parsing of this command suffers from a buffer overflow vulnerability.

To understand where the vulnerability is, let’s first have a look at the argument of the cmd_perso. It has the following structure.

The action_id allows to select an action: write or read a variable, or reset the user settings. The fields are used to put the names and values of those variables.

A ksy file describing this structure (http://kaitai.io/) is available here.

Let’s now have a look at the beginning of the function called when a cmd_perso is received.

The problem lies in the parsing of the argument of the RFCOMM packet (see the previous section for to understand the entire packet structure). The parsing is done by the function wpp_unpack_arg called at line 28.

The wpp_unpack_arg is supposed to fill a 262 bytes structure initialized by the wpp_init_perso function (line 18). It’s a very generic function who takes as argument a pointer to a more specific function able to parse the payload of a cmd_perso packet: wpp_unpack_perso (line 23).

The wpp_unpack_perso calls the memcpy function multiple times and fills the 262 bytes long structure without boundaries checking. The fields of the cmd_perso packet argument are copied into it. A buffer overflow can occur, it is possible to overwrite the saved fp and lr registers saved on the stack.

Buffer Overflow Exploitation

To exploit this buffer overflow, I choose to use well known ROP techniques. I encountered two main difficulties:

  • I didn’t find that many ROP gadgets on the code
  • The size of each field is limited to a length of 0xff

Because of these two points, it was not possible to build a long and complex ROP chain. That’s the reason why I decided to build the exploit in the following way:

  • Build a chain able to write a couple of bytes of data (to keep things small) to a known writable address. Obviously, the execution has to start normally after the execution of this payload.
  • Build another chain to call the system() function with this writable address as argument.

To build the first chain, I used the following gadget:

  • The “Set R3” gadget (starts at 0x0000e840):
  • The “Set R4” gadget:
  • And finally, the “Write memory byte” gadget:

To let the execution of the program resume normally, I added a

at the very end of the chain end to pop a valid fp and pc from the stack.

Considering the limited length of buffer and the necessity of stopping the chain just before a valid fp and pc, I successfully built a chain able to write three bytes at a time. Using this payload multiple times was enough to write an arbitrary shell command to a known address.

The chain aimed at calling system() was easier to build. I just used the following gadget and took care of calculating the right value for fp.

 
The following demo shows the result once everything is put together


Conclusion

From the firmware obtained thanks to the cleartext HTTP traffic, it has been possible to root the Aura and detect two vulnerabilities.

The first of them was possible to exploit thanks to MITM. I exploited it to get a SSH root access and run my own code.

The other was more serious. An attacker could possibly exploit it to run his own code on the device using a Bluetooth RFCOMM link.

As explained before, all these flaws are currently fixed.

9 thoughts on “Reverse Engineering & Exploitation of a “Connected Alarm Clock””

    1. Hi,
      As explained in the article, I did contact the manufacturer. All my findings were fixed with an automatically deployed firmware update. No more plain-text HTTP, buffer overflow, …
      I’m doing this as a simple hobby and not for a living. I don’t really care about receiving a reward or not. This topic hasn’t even been discussed with the manufacturer.

  1. Impressive bit of investigation. Just curious, are you still looking to find another way in? After all, you were trying to put your own software on there.

    1. Hi, thanks for the comment. I’ve checked a little but I haven’t found other ways to get in, everything I’ve discovered is already in the article.

Leave a Reply

Your email address will not be published.