I’m still the enemy in the Internet of Things security, but I now have more reasons

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


Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *