Hijacking Your Home IoT Appliance, part 2

On part 1 of this article, we described how IoT devices communicate, we talked about the MQTT protocol, and particularly, how our IoT appliance connects to its manufacturer’s servers to get commands.

In this part, we will try to set up a fake MQTT server which will hijack our appliance and start receiving orders from it.

Setting Up the Bait

Rogue MQTT Server

On a Raspberry Pi I installed a MQTT server called Mosquitto, which works great for IoT devices. Remember the Raspberry Pi has the IP: 192.168.1.17.

$ sudo apt-get install mosquitto

This gets our Raspberry Pi listening for pub/sub connections through MQTT on port 1883. No further configuration will be done to MQTT in this exercise.

Subscribing and Publishing

Before continuing, it would be good to test at this point that the MQTT server is running properly.

Subscribe to the MQTT server by issuing on one terminal window the following command:

$ mosquitto_sub -d -h 192.168.1.17 -t sampletopic
Client mosqsub/2683-MacBook-Pr sending CONNECT
Client mosqsub/2683-MacBook-Pr received CONNACK
Client mosqsub/2683-MacBook-Pr sending SUBSCRIBE (Mid: 1, Topic: sampletopic, QoS: 0)
Client mosqsub/2683-MacBook-Pr received SUBACK
Subscribed (mid: 1): 0

And on a new a window execute a Publishing command as follows:

$ mosquitto_pub -d -h 192.168.1.17 -t sampletopic -m “Hello World”
Client mosqpub/2691-MacBook-Pr sending CONNECT
Client mosqpub/2691-MacBook-Pr received CONNACK
Client mosqpub/2691-MacBook-Pr sending PUBLISH (d0, q0, r0, m1, ‘sampletopic’, … (11 bytes))
Client mosqpub/2691-MacBook-Pr sending DISCONNECT

What the previous command does is to connect to the MQTT server and on the topic sampletopic, publish the message “Hello World”.

Finally, on the first terminal window you will see the message sent.

Client mosqsub/2683-MacBook-Pr received PUBLISH (d0, q0, r0, m0, ‘sampletopic’, … (11 bytes))
Hello World

Rogue DNS Server

If you were able to follow me correctly, what we are trying to do is to make the heater resolve to the Raspberry IP address, instead of the real manufacturer’s IoT server in the cloud. For this purpose we are going to force a local DNS server to resolve the host mq.gw.tuyaus.com (the real manufacturer’s server, as seen in part 1) to our rogue IoT server at: 192.168.1.17.

Instead of setting up a full fletched DNS server, we will use dnsmasq instead, which takes requests as a DNS server and resolves them in a very simple manner. You can do this on your Linux machine, Raspberry Pi, or like I did, on a DD-WRT router.

Configuration on a DD-WRT Wifi Router

The option that you need to add on your dnsmasq configuration is:

address=/gw.tuyaus.com/192.168.1.17

This means that any connection going to the domain gw.tuyaus.com will be resolved to the fixed IP address 192.168.1.17 of our Raspberry Pi instead.

Checking that it all works

Now, let’s see if we can fool our IoT appliance to connect to our rogue MQTT server.

DNS Resolving to the Rogue IP

Before we set dnsmasq, we could have seen that a simple dig command gets this:

$ dig mq.gw.tuyaus.com
; <<>> DiG 9.8.3-P1 <<>> mq.gw.tuyaus.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 38703
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;mq.gw.tuyaus.com. IN A
;; ANSWER SECTION:
mq.gw.tuyaus.com. 7 IN A 54.68.252.52
mq.gw.tuyaus.com. 7 IN A 54.187.46.221
mq.gw.tuyaus.com. 7 IN A 54.69.209.57
;; Query time: 72 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Wed May 10 22:06:38 2017
;; MSG SIZE rcvd: 82

Check above, that the DNS resolves to the real MQTT server at IP 54.68.252.52 (and alternatively others)

Now, After setting dnsmasq we get:

$ dig mq.gw.tuyaus.com
; <<>> DiG 9.8.3-P1 <<>> mq.gw.tuyaus.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1243
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;mq.gw.tuyaus.com. IN A
;; ANSWER SECTION:
mq.gw.tuyaus.com. 0 IN A 192.168.1.17
;; Query time: 35 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Wed May 10 22:08:39 2017
;; MSG SIZE rcvd: 50

This is great ! When we try to reach the manufacturer’s MQTT server, we get the IP 192.168.1.17 of our local MQTT server on our Raspberry Pi.

Subscribing to the Topic and Listening

Now, it’s when we should put in practice everything we learned when dissecting the original connections in part 1 of this article. If our analysis were correct, we should be able to talk to the heater in a language it understands, just as if we were the real manufacturer’s IoT server in the cloud.

At this point we should know what Client Id to use, username and password to connect. And also, we should know exactly to what topic to subscribe. If your analysis was thorough enough, you should have also learned the commands to turn on and off the heater, plus doing other things as changing the temperature, etc.

Before publishing the fake messages through the topic channel, on a different terminal we can subscribe to the topic and start listening for published messages. For this we will use the command mosquitto_sub, which is part of the mosquitto package installed before.

Note: because this MQTT server is our own, we won’t pass the client id, nor the user or password, not required. But we do need to pass the correct topic name, because is through that topic that the heater will try and listen
$ mosquitto_sub -d -h 192.168.1.17 -t smart/gw/0020000800545******
Client 00200800545***** sending CONNECT
Client 00200800545***** received CONNACK
Client 00200800545***** sending SUBSCRIBE (Mid: 9, Topic: smart/gw/0020000800545******, QoS: 0)
Client 00200800545***** received SUBACK

Publishing a message with a command to turn on the heater

We will use the command mosquitto_pub to publish a message to the topic. We will play with all the commands learned earlier, and see if we can actually control our appliance.

$ mosquitto_pub -d -h 192.168.1.17 -t smart/gw/002000080054590008a1 -m ‘{“protocol”:5,”type”:null,”gwId”:null,”data”:{“gwId”:”0020000800545*****”,”devId”:”0020000800545****,”dps”:{“6”:true}},”pv”:”1.0",”t”:1494370849,”sign”:null}’
Awesome !!! it worked !!! This just turned on the heater, while sending the command: dps: 6: true

Now I send the command dps: 6: false and the heater actually turns off.

$ mosquitto_pub -d -h 192.168.1.17 -t smart/gw/002000080054***** -m ‘{“protocol”:5,”type”:null,”gwId”:null,”data”:{“gwId”:”002000080054****”,”devId”:”002000080054****”,”dps”:{“6”:false}},”pv”:”1.0",”t”:1494370849,”sign”:null}’
This is great, by now we have complete control over our IoT appliance.

We can start playing with all the commands learned in part 1 of this article, and start thinking of what’s coming next. As you could imagine, we want to control our heater based on external variables, such as outside temperature, if there are people in the house or not, etc. We will talk about this in a following article.

I hope you found this article interesting.

Alex Harasic
CTO and Head of Business Intelligence
Operatio SpA
Email: aharasic@operatio.cl