The Xiaomi robot vacuumĀ joined my household last night. It wasn't too complex to switch the voice pack over to English (it has ~50 Chinese voices, but only 1 English, and you have to be able to read Chinese to find it).

Once setup (the app has every permission possible on Android!), dirt patrol began. It uses an ultrasonic/radar/laser dome to map out your house, and you can see this map grow in real time. My cat kept a close watch the entire time!

Now, on to the network security. Of course this was put on the IoT SSID. it has a fair bit of chatter to the internet (hadoop on amazon is the biggest). A little bit of hacking, and its token was yielded, allowing it to integrate with homeassistant.io.

Interestingly, it has no open ports on the unit (it does maintain persistent outbound connections to the cloud). Have to do a bit more research. But for sure its sharing a map of my house, and when I'm home, w/ the cloud.

You know how when you order a gadget from china and it can take forever to reach your house, and you've forgotten what madness caused you to order a wifi-enabled hairbrush?

Well, sometimes that lottery works out. See below, i've just been delivered a shiny new robot vacuum w/ radar and (chinese) voice activation!

so who is in for the first in pool for me being murdered in my sleep by an IoT-enabled 2-day(!) delivered china robot?

And, check the cam, cat wants in, and its there!

Tagged with: , ,

Purists say that IoT should be things too small to really be IP, that they should have a gateway.

One late night trip to aliexpress, one credit card, and some months later, its all over my desk. A Xiaomi Smart Home Multifunctional Gateway. And, to make my life simple, it walks you through the enrollment process. By voice. In mandarin chinese. Well, a couple of hours later, and some considerable google translate, we are hooked up to the 'evil' segment of my house (it will get promoted to the IoT one in a bit after I understand more about it).

So the way this works, the zigbee sensors (motion/clicker/door) communicate with the hub, and the hub communicates with 'the internet' (in this case, my HomeAssistant, you'd be crazy to think i would have this on the Internet and on my home network together!).

Zigbee gives tremendous battery life, those sensors should last a few years on a cell.

Its got 'party' mode (the ring of light can be many colours, pulsing, just what i want!).

Its got 'radio mode' (only chinese radio stations tho).

Its got 'alarm' mode (very helpful, when the door opens a police siren sounds at a very loud volume). Probably going to look to turn that off.

Helpfully it has a mainland china 3-pin plug, So, uh, twisty šŸ™‚

And, it has answered the question: can any more 2.4GHz radiation fit inside my house? Answer: YES!

So i'm upgrading a few of the lights from 'hack-mode' IP-enablement to MQTT. The 'hack-mode' was a small json cgi running on them, below. This allowedĀ HomeAssistantĀ to set/read their state. It reads their state by polling. So far so good right?

But the problem is scaling this out. What if they have more to say than light on/off? What if other things want to know? What if i want a faster reaction to them being manually turned on?

Turns out there is an answer.Ā MQTT. Its a publish/subscribe message bus, and u run a broker (mosquitto, purposely mispelled to get the second 't'). OK, great. So now your lights 'publish' to a topic their state changes, and listen to a topic for commands. Perfect, lower latency, better automation.

OK, so how do I secure this? The username/password is in the clear! Well, TLS is the answer. But some of these devices are very tiny. Lets look @ theĀ sonoff. $5 gets u a wifi-enabled relay, very simple to reprogram. You can install 'atom' and 'platform.io'Ā and you then do a git clone of 'Sonoff-Tasmota'. Connect your usb-serial widget to the board, and jam some software in. Its that easy. Since we are using TLS, we would not dream of self-signed certs right? I mean, "Let's Encrypt" has made this so simple Pauly Shore can get a cert. But, hold that thought.

Turns out the ESP8266 in here is a super-powerful SoC for the $1 price point. But, it would struggle to do a realĀ CRLĀ etc. So to save ram, they put the certificate hash in the compiled code. This works great if you have a permanent certificate (this is for the widget to certify the server, not the username/password). However, Let's Encrypt is going to give me a 90-day cert. So every 90 days I recompile and reinstall my lights? Hmmm.

Another option, this code supports Over-The-Air updates. On boot it will look for a magic URL and, if found, fetch + install the firmware there. Great, sounds like my answer right? Well, lets go back to theĀ sous-vide. Turns out that just find+fetch a file is not that secure a means. I mean, its kind of like lettingĀ a strange woman in a lake distributing swords form a basis of government.

So... What do i do? Do i not use TLS? Do I use TLS and let the widgets OTA new firmware with new SHA? Do i yank them out and serial-port update them quarterly? Hmmm... Suggestions?

Oh yeah, the 'hack-mode'. Well, its below. Ā Its running on the more mighty switches (which use the atheros AR9330). This is running Linux, and cost $10. Moving to the ESP8266 necessitates this problem.

root@office-smartplug-1:/# cat /www/cgi-bin/json.cgi
#!/bin/sh
VERSION=0.0.3
RELAY_CTRL=/sys/class/leds/tp-link:blue:relay/brightness
IP_ADDRESS=`ifconfig wlan0 | sed ':a;N;$!ba;s/\n/","/g' | grep -E -o '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -n 1`
TZ=`cat /etc/TZ`
SSID=`iw dev wlan0 link | grep SSID | awk '{ print $2 }'`
WIFI_SIGNAL=`iw dev wlan0 link | grep signal | awk '{ print $2 }'`
WIFI_CHANNEL=`iw dev wlan0 info | grep channel | awk '{ print $2 }'`
MACADDR=`iw dev wlan0 info | grep addr | awk '{ print $2 }'`
UPTIME=`uptime | awk -F , '{ print $1 }'`
LWRAPPER=""
RWRAPPER=""
CURRENT_STATE=`cat $RELAY_CTRL`

get=$(echo "$QUERY_STRING" | sed -n 's/^.*get=\([^&]*\).*$/\1/p' | sed "s/%20/ /g")
set=$(echo "$QUERY_STRING" | sed -n 's/^.*set=\([^&]*\).*$/\1/p' | sed "s/%20/ /g")
mins=$(echo "$QUERY_STRING" | sed -n 's/^.*mins=\([^&]*\).*$/\1/p' | sed "s/%20/ /g")
canceljob=$(echo "$QUERY_STRING" | sed -n 's/^.*canceljob=\([^&]*\).*$/\1/p' | sed "s/%20/ /g")

callback=$(echo "$QUERY_STRING" | sed -n 's/^.*callback=\([^&]*\).*$/\1/p' | sed "s/%20/ /g")

if [ ! -z $callback ]; then
 LWRAPPER="("
 RWRAPPER=")"
fi

if [ ! -z $callback ]; then
 echo "Content-Type: application/javascript"
else
 echo "Content-Type: application/json"
fi
echo "Cache-Control: no-cache, must-revalidate"
echo "Expires: Sat, 26 Jul 1997 05:00:00 GMT"
echo

case "$get" in
 state)
 case "$CURRENT_STATE" in
 0) echo "$callback$LWRAPPER{\"state\":\"off\"}$RWRAPPER"
 ;;
 1) echo "$callback$LWRAPPER{\"state\":\"on\"}$RWRAPPER"
 ;;
 esac
 ;;
 jobs) # list all the scheduled jobs
 i=0
 echo "$callback$LWRAPPER{\"jobs\":["
 atq | while read line; do
 job_id=$(echo $line | awk '{ print $1 }')
 job_date=$(echo $line | awk '{ print $5, $2, $3, $4, $6 }')
 job_queue=$(echo $line | awk '{ print $7 }')
 joblist="{\"jobid\":$job_id,\"queue\":\"$job_queue\",\"date\":\"$job_date\"}"
 if [ $i -ne 0 ]; then
 echo ",";
 fi
 i=1
 echo "$joblist"
 done
 echo "]}$RWRAPPER"
 ;;
esac

case "$set" in
 on)
 if [ ! -z $mins ]; then
 echo "echo 1 > $RELAY_CTRL" | at now + $mins minute -M -q b
 else
 echo 1 > $RELAY_CTRL
 fi
 echo "$callback$LWRAPPER{\"ok\":true}$RWRAPPER"
 ;;
 off)
 if [ ! -z $mins ]; then
 echo "echo 0 > $RELAY_CTRL" | at now + $mins minute -M -q c
 else
 echo 0 > $RELAY_CTRL
 fi
 echo "$callback$LWRAPPER{\"ok\":true}$RWRAPPER"
 ;;
 toggle)
 case "$CURRENT_STATE" in
 0)
 if [ ! -z $mins ]; then
 echo "echo 1 > $RELAY_CTRL" | at now + $mins minute -M -q d
 else
 echo 1 > $RELAY_CTRL
 fi
 ;;
 1)
 if [ ! -z $mins ]; then
 echo "echo 0 > $RELAY_CTRL" | at now + $mins minute -M -q d
 else
 echo 0 > $RELAY_CTRL
 fi
 ;;
 esac
 echo "$callback$LWRAPPER{\"ok\":true}$RWRAPPER"
 ;;
esac


if [ "$canceljob" -ge 0 ] 2> /dev/null; then
 atrm "$canceljob"
 echo "$callback$LWRAPPER{\"ok\":true}$RWRAPPER"
fi

if [ -z "$get" ] && [ -z "$set" ]; then
 echo "$callback$LWRAPPER{\"info\":{\"name\":\"kankun-json\",\"version\":\"$VERSION\",\"ipAddress\":\"$IP_ADDRESS\",\"macaddr\":\"$MACADDR\",\"ssid\":\"$SSID\",\"channel\":\"$WIFI_CHANNEL\",\"signal\":\"$WIFI_SIGNAL\",\"timezone\":\"$TZ\",\"uptime\":\"$UPTIME\"},\"links\":{\"meta\":{\"state\":\"http://$IP_ADDRESS/cgi-bin/json.cgi?get=state\"},\"actions\":{\"on\":\"http://$IP_ADDRESS/cgi-bin/json.cgi?set=on\",\"ondelay\":\"http://$IP_ADDRESS/cgi-bin/json.cgi?set=on&mins=60\",\"off\":\"http://$IP_ADDRESS/cgi-bin/json.cgi?set=off\",\"offdelay\":\"http://$IP_ADDRESS/cgi-bin/json.cgi?set=off&mins=60\"}}}$RWRAPPER"
fi

d

So on last nights security scan of my home, I found a new and interesting thing. Specifically, aĀ TFTP serverĀ running. Huh. That is normally something I bring up to rescue some widget that is old-school almost-bricked.

Now, where is it. Its on the ring1. (ring0 is the hard-wire between my 3 larger servers, doesn't go anywhere. ring1 is the things my wife and I use, ring2 is the guests who come over, and ring3 is theĀ evil crap that got bought in a moment of weakness).

Hmm, ok. What is it? Its an asustek tablet. One of the nexus 7's. My nexus 7 is semi-retired and currently in hard-off state, so must be Sonya's. But its pretty unlikely she has purposely installed TFTP server, right? Turns out this is indeed correct. One of the apps she has installed has gone rogue... Someone lost control of their account, or sold it, or whatever, and an update was pushed, and the update has some means of trying to get control of my network. The TFTP server would be how they get some new firmware to a device if they can crash it. And there are still some devices that can be crashed (previous hardening runsĀ have improved my lot, but there are still a good chunk of devices that i'm not sure what to do with).

OK, so what should I do? Well, i reflashed her tablet and yanked the offending app. I could demote her tablet to ring2 or ring3 (but then it can't drive the chromecasts, sonos, remote, plex, ...). Hmm.

I could make some more complex firewall rules, a ring 1.5 maybe, but ugh. So much work. ThatĀ mudĀ thing, well, its just not there.

Suggestions? Maybe its theĀ sorceror's apprentice syndrome?