MA 10880 Switches with Homekit aka. Reverse Engineering a Binary API

Tobias Larscheid
6 min readDec 13, 2018

I recently got my hands on a technoline MA 10880 “smart switch”. With a little reverse engineering, I managed to integrate it nicely with my existing homebridge and therefore my Homekit setup.

Unboxing

This is the keypad we are talking about (image credit: www.conrad.de)

In order to be used, the keypad requires a base station — the manufacturer calls this the gateway. Keypad and gateway communicate over 866 mhz, a typical radio frequency used by e.g. home weather stations. The gateway has an ethernet port to connect it to the network. So far everything looks straightforward, so I start my analysis by downloading the advertised mobile app. I do as directed and connect my keypad to the gateway.

The placeholder in my draft said “picture of glorious dashboard”. Found this one instead.

It shows up and I can see the keypresses I do listed in a kind of log in the app. Unfortunately there does not seem to be an option to forward the keypresses to a target of my liking. Also, how does the gateway talk to my app? Its time to dig a little deeper.

Reverse Engineering: OSI Layer 5-7

Alright, so how does this app know what buttons I pressed? When fiddling around with the app I noticed that it can— among other network settings — set a proxy for the gateway to use. That sounds promising! I fire up mitmproxy on my mac and direct my iPhone (don’t forget to set up CA Cert!) as well as the gateway to it. Immediately, traffic starts flowing! First learning: The gateway does not seem to use TLS, as it accepts my proxy as a man in the middle without complaining. Nice, I guess?

Looking at the traffic, I see a lot of calls to the URL www.data199.com, from my iPhone as well as from the gateway. My first question is answered: The iPhone App gets the log of button clicks from a remote server living at data199.com. The server answers with a json containing “measurements”, probably a tribute to the weather station history of this manufacturer.

“Measurements” represent button presses

The next thing I want to understand is how these measurements get to “the cloud” — surely the gateway sends them. I press some buttons on the keypad, the gateway’s LED starts flashing and mitmproxy shows me some PUT requests to data199.com. Looking at the requests, I experience the first setback:

64 bytes of beautiful binary data

Coming from corporate IT, all I really know is super verbose (pseudo) REST APIs. The gateway talks binary to the server! This will be fun. I copy over all the requests I triggered to vscode and try to spot patterns just with my eyes. Here is what I found:

  1. Every button press triggers two requests, only differing in the very last byte. It increases by one or two between calls.
  2. All requests seem to start with CE — no idea what this means.
  3. Bytes 7-12 (blackened in the picture) are exactly what is printed on the back of my keypad as a device id.
  4. Bytes 1–5 are interesting: 5C 0F is the same for all requests I observed, what follows is changing with every request, in a somewhat increasing manner. Being inspired by the json seen earlier I google for hex timestamp and sure enough this is exactly what I see — standard unix epoch format encoded as hex. Simple!
  5. The 15th byte is important: The first four bits signal the button that was pressed (1–4) and the second four bits signal the type of press, i.e. single, double or long click (0–3).

The remainder of the requests looks pretty random to me, but if everything I made up from the binary is true, I already know more than enough. To test my hypotheses I decide to move on in a more interactive fashion: Let’s fire some requests against data199.com and check the app as an oracle to understand what our requests did. I use a tool called iHex to create binary files based on the captured requests and then curl to send these to the server.

curl \
-i \
-X PUT \
-H "Content-Type:application/octet-stream" \
-H "HTTP_IDENTIFY:80XXXXXXXXXXXXXXXXXXXXC0" \
--data-binary @buttonpress \
http://www.data199.com/gateway/put

Indeed, the timestamp idea confirms pretty quick: Replaying the requests with a different timestamp yields a new button press for the respective time in my log. Changing some of the other bytes gives mixed results: While all requests are responded with a status code 200 (and different binary bodies that I do not feel like looking at), some never trigger an entry in the app. The last byte can indeed be changed relatively free, as long as it increases between the two calls for one click. Modifying the 15th byte alone (the one signalling which button was pressed) does unfortunately not create valid requests — maybe some kind of checksum is applied here. At this point, playing around interactively does not give me new ideas. But I still have one more thing to understand.

Reverse Engineering: OSI Layer 4

The configuration process did not show up in my mitm logs and I am not sure how its done. How does the iPhone App send the proxy settings to the gateway? How does the restart button do it’s job? Most likely not through http, otherwise I would have caught it. Time to leave the comfort zone! Let’s fire up wireshark to inspect the packets flowing between iPhone and gateway. With wireshark running, I change the gateway’s config from the app and restart it. So what does my iPhone send to the gateway?

This is what an empty result looks like.

Oops! Not that simple once again. But what does the iPhone send anyway?

At least something.

UDP is the name of the game! And the packets don’t go to the gateway directly, but instead to a broadcast address. When you think about it, this makes sense: The app allows setting network config like the IP address of the gateway, so directly sending these to the gateway might not even be possible. So what do the packets contain? iHex is gonna tell!

Error Code 1337: hex skillz not found

Almost to simple! By coincidence (= clicking around in my wifi box to figure out the IP of the gateway) I discovered that the gateway actually hosts a web page displaying it’s config. That means we have a request to play around with and an oracle to tell us what we did. Showtime! I fiddle around with the gateway name, data199 url and proxy IP through my hex editor and send it of.

echo -n '00..FD' | xxd -r -p | nc -u 10.10.10.91 8003

Two things I learned here:

  1. xxd is a pretty handy tool to create and reverse hex dumps.
  2. netcat can send udp packets with the -u option.

Sending the forged payload worked flawlessly, the gateway indeed reports the config I handcrafted. The only thing worth mentioning is that when changing the data199 url the new value needs to be zero padded to the exact same length it was before.

Putting it all together

Exploration is done, now we can build! After understanding the different bits and pieces, the target architecture is clear: I will reconfigure the gateway to proxy all requests through a plugin I build for my homebridge. In theory, I could just change the data url directly without using a proxy, but I did not find a way to change the port as well — that means my homebridge plugin would have to run on port 80, which I consider inconvenient. The plugin itself then really only needs to look at the 15th byte it receives to figure out which button was pressed, every second request should be ignored as every button press triggers two requests. Regarding running a http server in a homebridge plugin I found great inspiration in the homebridge-http-webhooks plugin. The resulting code of the plugin can be found here!

--

--