Blog: How Tos

Are your smart weighing scales lying to you? Quite possibly (part 2)

David Lodge 09 Jan 2015

smartscales

Following on from my previous post let’s look in some detail at what the Fitbit device communicates. As it communicates directly with the server, this means we need to do some trickery to intercept the traffic and hope that it isn’t encrypted.

Intercepting the Traffic

The easiest way for us to do this is to set up a fake wireless AP; then set up the scale to always talk through that AP. Then we can sniff the traffic whenever we want.

There are a couple of ways for us to do that; we could use a hardware solution, such as custom AP with altered firmware, such as OpenWRT or use a wi-fi pineapple or similar; or we could use a soft AP – i.e. a program running in software to act like an AP.

Due to not having appropriate hardware to use a hardware solution I ended up going down the software solution. To do this I needed dual connections – one dedicated wireless card to act as the hub’s NIC and another network connection to give Internet access.

The easiest was to do this was to use a wireless USB card, which the virtual machine had dedicated control over as the AP’s wireless access point and then a bridged interface which used my laptop’s normal wireless connection to provide Internet access.

In terms of software, after a lot of messing around I used hostapd instead of the usual airbase-ng simply because it worked! This does require some setting up to get it to work fully.

Firstly we need to provide a DHCP server so that when the client joins the network it can request a valid IP address. For this I’m going to use dnsmasq as it also provides a DNS server in case we need to do any form of DNS masquerading.

All of this is running on a base Kali install where I’ve installed dnsmasq, hostapd and supporting libraries through the apt-get interface. You will also want to stop NetworkManager, or stop it managing wlan0 as it will seriously mess with setting this up!

Intall dnsmasq and then set up a simple DHCP configuration:

root@asphodel:/# cat /etc/dnsmasq.conf
log-facility=/var/log/dnsmasq.log
interface=wlan0
dhcp-range=10.0.0.10,10.0.0.250,12h
dhcp-option=3,10.0.0.1
dhcp-option=6,10.0.0.1
log-queries
cache-size=20000

And start it up:

service dnsmasq start

This sets up a simple DHCP server to give an IP address in the 10.0.0.0/24 range and to use 10.0.0.1 as both the DNS server and the gateway. I found the log file essential for debugging when initially setting it all up.

We now have to set up the VM for IP forwarding, firstly we configure the network card with our valid IP address. In this case, my USB wireless card comes out as wlan0:

ifconfig wlan0 10.0.0.1/24

Set up Linux to perform IP forwarding:

echo 1 >/proc/sys/net/ipv4/ip_forward

And set up IP tables to perform the forward over the interface with the Internet connection, in my case eth0, (this may have to be customised depending on the IP tables configuration):

iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT

Finally we can set up hostapd to act as a virtual wireless access point, we’re setting the SSID in this case to the rather prosaic “private” and I’m not bothering with encryption to make life easier:

root@asphodel:/var/log# cat /etc/hostapd/hostapd.conf
interface=wlan0
driver=nl80211
ssid=private
channel=1

Now, if we start it up:

service hostapd start

Then we now have a wireless access point under my control, for which I can monitor all traffic that I see. The final step is to attach a network sniffer to wlan0 and then attempt a registration and a few weighs to see what the traffic is.

I used Wireshark, as I’m lazy and I like having the dissectors.

Registration

A registration shows me that the important communication are these two HTTP requests (they are redacted as I don’t want my Fitbit account to be hacked and my lardiness to be known):

Request 1:


GET /scale/register?serialNumber=20F85EA72CBA&token=2ZSHS2- XXXXXXXXX&ssid=private HTTP/1.1
Host: www.fitbit.com

 

HTTP/1.1 200 OK
Server: nginx
X-UA-Compatible: IE=edge,chrome=1
Set-Cookie: fhttps=””; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/ Expires: Thu, 01 Jan 1970 00:00:00 GMT
Cache-control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Type: text/plain;charset=UTF-8
Content-Language: en-GB
Content-Length: 0
Date: Fri, 26 Dec 2014 16:43:50 GMT
X-Frame-Options: SAMEORIGIN

 

Request 2:


GET /scale/validate?serialNumber=20F85EA72CBA&token=2ZSHS2-XXXXXXXXX HTTP/1.1 Host: www.fitbit.com

 


HTTP/1.1 200 OK
Server: nginx
X-UA-Compatible: IE=edge,chrome=1
Set-Cookie: fhttps=””; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Cache-control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Type: text/plain;charset=UTF-8
Content-Language: en-GB
Content-Length: 1
Date: Fri, 26 Dec 2014 16:43:51 GMT
X-Frame-Options: SAMEORIGIN
T

 

If we ignore all the extra bumf in the headers we can see a two-step process:

  • It registers the scale with the website, providing its serial number (actually the MAC address of the scale), the token we got from fitbit.com and the SSID it’s attached to
  • It then validates the connection; the “T” stands for true

We can use the validate call to replay in burp:

fitbit6

If any of the parameters are messed with then an F is returned. This does give a potential way of brute forcing an account to see whether a scale is registered and its code. We will need to work out:

  1. The serial number (MAC address), which we can probably guess as the first three or four octets are going to be the same.
  2. The token.

The token looks complex enough, but a quick hunt through my Burp Suite history of multiple logins and registrations shows a different story; here are some cookie values and the issued date (colours added for emphasis):

2ZSHS2-4V9XXBQ6S – 21 December
2ZSHS2-4V9XXZ6N3 – 21 December
2ZSHS2-4V9XYLY3T – 21 December
2ZSHS2-4VB2X9GZB – 22 December
2ZSHS2-4VB2XPRTG – 22 December
2ZSHS2-4VBMBNYXT – 26 December
2ZSHS2-4VBMKPWCR – 26 December
2ZSHS2-4VBMLBW28 – 26 December
2ZSHS2-4VBMM6VNT – 26 December
2ZSHS2-4VBMNDHBD – 26 December
2ZSHS2-4VBMPK6X2 – 26 December

 

A quick inspection shows us the coloured areas:

  • Red is static
  • Blue seems to vary depending on the date of issue
  • Black seems to increase with time

Without too much analysis, the token doesn’t seem to have too much entropy, being related to the time of issue (maybe as a counter). This is a poor design decision; something truly random, such as a UUID would’ve been a lot better.

Weighing

Before I start this; I spent an hour on the sofa “watching over” my sprogs whilst trying to decode the binary format, part way through this I found that a couple of people at the Bamberger Hackerspace had already had a go and our notes matched, there are some minor differences which I’ll detail below. I have dropped them an email to try and compare notes, and show them just how bad my German really is.

Let’s have a look at a weighing; these packets are set slightly differently, and are sent as a binary object in the body of an HTTP POST message; here’s one, with my personal details edited out.

fitbit7

This consists of two main data structures, a header and then a selection of data structures for each reading (if the scale can’t send to the server upon weighing it will queue up the reading and send it next time). All numbers are little endian (which initially threw me).

The data structure for the header is:

fitbit8

The data structure for the reading data is:

fitbit9

At the bottom there’s a two byte footer (0x48 0xa3) which look like a checksum value.

The response to this is passed in the HTTP response, also in binary format:

fitbit10

For each user there’s a user structure:

fitbit11

After the configured users there’s a footer consisting of 12 bytes of NULLs, followed by 0x00 0x66 0xaa 0xbb. It is unknown what this is.

I have not tried fuzzing these packets to avoid falling foul of the Computer Misuse Act.

Further experimentation would really require getting hold of a copy of the firmware to attempt to reverse engineer it. Fitbit don’t make this easily findable on their website, although as I was writing this sentence I managed to guess the URL:

https://www.fitbit.com/scale/firmware/35?serialNumber=20F85EA72CBA

Conclusion

These scales show the whole problem with the Internet of Things – you’re inviting a device into your network which has minimal possible configuration and talks to whatever it talks to.

The research done by Bamberg shows that initially there was minimal security, of which some (albeit with flaws) has been implemented. This isn’t really good enough, there needs to be more transparency from the IoT companies – making the firmware visible, or publishing the protocols would help.

What I’d like to do is to scrape the guts out of the scales and put in my own implant, then send it as a free gift to somebody; what a perfect way to get them to let me into their network.

I would not trust these on my personal network – so if you’re going to buy these, please set up a DMZ on your wireless network and place them in there!