Saturday, April 28, 2018

Revogi Smart Power Strip SOW323 , part three

The SOW323 is running a proprietary binary called "switch", which talks to the /dev/ttyS0 and the cloud mothership. In the previous article, this was disabled.

That said, the "switch" application generates some traffic on /dev/ttyS0 even if it is not connected to the internet. This exposes two possible commands:

Command to check which plugs are enabled:
CPU: 0F 04 05 00 00 06 FF FF
STM: 0F 04 05 00 00 06 FF FF
Command to check detailed information, likely used for wattage monitoring:
CPU: 0F 05 02 00 00 00 03 FF FF
But how does one control the sockets, how to turn them on/off ? For that, we need to trigger a socket switch remotely somehow. Luckily, there's no need for the cloud-based application, since the "switch" application running on the device also listens on local network for HTTP JSON requests. This interface has no security again, anyone on the network can operate it. Someone even wrote a python script [LINK] to toggle the sockets on/off via the JSON interface.

But to sniff the UART, there are two options, either attach a logic analyzer or do it using pure software. I opted for the second option because I closed the device again and didn't feel like reattaching the analyzer :-)

The trick here is using socat and qemu. On the device, use a custom busybox build with netcat to export /dev/ttyS0 over the network:
$ /tmp/busybox nc -l -p 6666 < /dev/ttyS0 > /dev/ttyS0
On the desktop, run qemu-system-mips with network connectivity. I got a mips32 debian system image to speed things up from [LINK], copied the dumped filesystem from the power strip to /revogi there, booted it with extra local port forwarded into it using:
$ qemu-system-mips -M malta \
-kernel vmlinux-3.2.0-4-4kc-malta \
-hda debian_wheezy_mips_standard.qcow2 \
-append "root=/dev/sda1 console=ttyS0" \
-nographic \
-net nic -net user,hostfwd=tcp::7777-:7777
Then I installed necessary tools, like socat, strace, chroot. The "switch" application has a few quirks, so I had to tweak the virtual machine a bit -- rename eth0 to br0, create /revogi/proc/, bind-mount /dev to /revogi/dev and /dev/pts to /revogi/dev/pts, create /revogi/proc/wlanled -- all this to confuse the application into believing it is running on the power plug.

Finally, to start this machinery, I started socat inside the qemu:
$ socat TCP-LISTEN:7777 PTY,link=/revogi/dev/ttyS0,raw,crnl &
and another instance to link the power strip and qemu together on the host:
$ socat -x tcp:10.0.0.300:6666 tcp:127.0.0.1:7777
Notice the -x option, which hexdumps the traffic between the two endpoints.

After starting the application in qemu:
$ cd /revogi ; chroot . bin/switch
there indeed is traffic between the application and the serial port. To force toggle of one socket, we can use wget to trigger the switch application from the virtual machine:
$ wget 'http://localhost/?cmd=200&json={"port":1,"state":1}'
And this boils down to the following commands sent on the UART:
# All port disable
 0f 04 03 00 00 04 ff ff

# Port 1 enable
 0f 04 03 00 01 05 ff ff
# Port 2 enable
 0f 04 03 00 02 06 ff ff
# Port 3 enable
 0f 04 03 00 04 08 ff ff
# Port 4 enable
 0f 04 03 00 08 0c ff ff
Update, port 5 and 6 are special. To toggle those, bitwise-or their socket mask with byte 4 and 5 after calculating the checksum:
# Port 5 enable
 0f 04 03 00 10 14 ff ff
# Port 6 enable
 0f 04 03 00 20 24 ff ff
There is always a reply if the command is valid, which is the same length as the command. Apparently, byte 4 is a bitmask indicating which sockets should be enabled. Byte 5 is checksum, calculated as sum of byte 0, 1, 2, 3, 4, 6, 7 modulo 16 , so a strong one as one would expect from an IoT device.

With this, I have a sufficient protocol knowledge to use the device for my own purposes.

Update, example code:
https://github.com/marex/reserial

No comments: