Sunday, April 29, 2018

Revogi Smart Power Strip SOW323 , howto

Here is a small howto on making the device usable without the cloud service. The result is a device controllable only via ethernet, with WiFi disabled, running custom simple remote control application. This howto probably voids the warranty, so use at your own risk.

First of all, replace the proprietary power controller with a simpler custom one. Sources for the controller and a convenience binary are at [LINK]. TFTP the binary to /bin/serial and chmod a+x it:

$ tftp -g -r /srv/tftp/serial -l /bin/serial 10.0.0.300
$ chmod a+x /bin/serial
# ls -la /bin/serial   
-rwxr-xr-x 1 root root 79481 Jan  1 01:23 /bin/serial
Next, replace the proprietary application with the open source one:
$ vi /etc/inittab
Locate the line
::respawn:/bin/switch
and replace it with 
::respawn:/bin/serial -l 6666
or whatever port you desire. The setting used above is 6666. To control the strip through this interface, use ie. netcat. The message format is "t:mmmmmm:vvvvvv", where "t" stands for "toggle", "m" is a mask of which sockets to toggle and "v" is the value to set on the sockets which had m=1. Both "m" and "v" values are either "0" or "1". Example:
$ echo "t:011000:101000" | nc 10.0.0.300 6666

Finally, albeit optional, disable the WiFi and start DHCP client on the wired ethernet port instead:
$ vi /etc/init.d/rcS
Locate the line
$ cfg init &
and replace it with 
mac=`grep -ri "^DEV_MAC" /etc/ | cut -d "=" -f 2`
mac1=`echo "$mac" | grep -o "............$" | grep -o "^.."`
mac2=`echo "$mac" | grep -o "..........$" | grep -o "^.."`
mac3=`echo "$mac" | grep -o "........$" | grep -o "^.."`
mac4=`echo "$mac" | grep -o "......$" | grep -o "^.."`
mac5=`echo "$mac" | grep -o "....$" | grep -o "^.."`
mac6=`echo "$mac" | grep -o "..$" | grep -o "^.."`
ifconfig eth0 hw ether ${mac1}:${mac2}:${mac3}:${mac4}:${mac5}:${mac6}
udhcpc -i eth0 -p /var/run/udhcpc.pid -s /etc/udhcpc.script

Indeed, the MAC address is stored in a configuration file within the filesystem and is configured into the ethernet interface by this "cfg" tool. This can be supplemented by
$ ifconfig eth0 hw ether MA:CA:DD:RR:EE:SS
The reason for the arcane MAC address parsing is because the system on the power strip doesn't have sed or any other useful tool to transform the MAC and the format of the MAC address entry in the configuration file is DEV_MAC=ABCDEF012345.

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

Revogi Smart Power Strip SOW323 , part two

After messing with the telnet interface for a bit, I managed to brick the device to the point it couldn't connect to the WiFi. Since I previously dumped the content of the SPI NOR, the obvious solution was to crack the device open and see what's inside.

It turns out there's no UART, no usable USB (the port is charge-only), no JTAG. But the SPI NOR is a nice SOIC8 chip, so let's pull it out. To make further experimentation possible, I wirebonded a DIP8 socket onto where the SOIC8 was and placed the SPI NOR itself onto a protoboard with DIP8 compatible footprint.

By using a SPI NOR programmer, I was able to reprogram the flash back with a working system image and the device boots again, great!

But looking at the cables coming out of the mainboard, there are two 4pin connectors on the board, white and black. You can see them between the USB port and the yellow transformer brick.

Poking at them with a scope turns, it turns out the top one is UART and the bottom one is just some power sequencing for something.

The UART is routed to a STMicro ARM chip controlling the relays and probably also the touch strip. The UART connector pinout is, top to bottom, CPU-to-STM data, STM-to-CPU data, GND, 3V3.

Using logic analyzer, it is easy to see the protocol. The CPU seems to be polling the STM all the time for what looks like the status of the sockets.

The polling protocol looks really trivial:
CPU sends:
0F 04 05 00 00 06 FF FF
STM replies (sockets off):
0F 04 05 00 00 06 FF FF
0F 04 05 00 00 06 FF FF
CPU sends:
0F 04 05 00 00 06 FF FF
STM replies (socket 1 on):
0F 04 05 00 01 07 FF FF
0F 04 05 00 01 07 FF FF


So presumably, byte 4 indicates socket status. Since byte 0, 0x0f, is in all frames, this is likely some preamble. Same for trailing byte 6 and 7, 0xff, is likely some end of frame indicator. Bytes 1, 2, 3 are likely some command field, while byte 5 might be a checksum of sorts.

Now, to make fiddling with the system easier, I figured how to stop the "switch" process which is hogging the ttyS0. Just replace /bin/switch with /bin/sh in /etc/inittab. I'm not convinced this is the right solution, but it does it's job. After a reboot, /dev/ttyS0 is available, so let's try sending the same poll command:

# /tmp/busybox stty -F /dev/ttyS0
speed 4800 baud; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = ; eol2 = ;
swtch = ; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O;
min = 1; time = 0;
-brkint -icrnl -imaxbel
-opost
-isig -icanon -iexten -echo


# /tmp/busybox hexdump -vC /dev/ttyS0 &

# /tmp/busybox echo -en '\x0f\x04\x05\x00\x00\x06\xff\xff' > /dev/ttyS0
# 00000050  0f 04 05 00 00 06 ff ff  0f 04 05 00 00 06 ff ff  |................|

The reply looks sensible, great! Now we can talk to the socket without needing the proprietary application. Further protocol analysis will be needed.

Friday, April 27, 2018

Revogi Smart Power Strip SOW323 IoT Security apocalypse

I started looking for a replacement for my trusty Gembird Silvershield USB-controlled 4-socket power plug, after some searching I discovered the Revogi Smart Power Strip SOW323. The device looks awesome, 6 controlled sockets, ethernet plug, power consumption monitoring, ~100EUR, just what I need! So I bought one and started looking around ...

The system security is state of the art, as one would expect from an IoT device.
# telnet 10.77.1.2
Trying 10.77.1.2...
Connected to 10.77.1.2.
Escape character is '^]'.
rlx-linux login: root
RLX Linux version 2.0
         _           _  _
        | |         | ||_|                
   _  _ | | _  _    | | _ ____  _   _  _  _
  | |/ || |\ \/ /   | || |  _ \| | | |\ \/ /
  | |_/ | |/    \   | || | | | | |_| |/    \
  |_|   |_|\_/\_/   |_||_|_| |_|\____|\_/\_/

For further information check:
http://processor.realtek.com/
#
Login is "root", the system doesn't even ask for password.

Sadly, the system is really cut down, most likely for security reasons, so it doesn't offer many useful commands:
#
arp        chmod      egrep      insmod     killall    modprobe   reboot     tar        vi
arping     cp         free       ip         ledbtn     mount      rm         telnetd
ash        cut        grep       iwconfig   ln         mv         rmmod      tftp
brctl      date       halt       iwcontrol  login      netstat    route      touch
busybox    depmod     hostname   iwlist     ls         ping       routed     udhcpc
cat        df         ifconfig   iwpriv     lsmod      poweroff   sh         udhcpd
cfg        echo       init       kill       mkdir      ps         switch     umount
But that's fine, there's the "tftp" command, so let's see:
# tftp -g -r /srv/tftp/test -l /tmp/test 10.0.0.1
# ls /tmp/test
/tmp/test
The syntax is a bit odd, but -g means "get", "-l" means local, "-r" means remote. The busybox version is 1.13.6 or so and oddly cut down. But this looks good, we can download files onto the Smart Power Strip.

Let's compile busybox with some more useful tools to dump the content of the flash, so we can politely ask vendor the for GPLed sources with a binary in hand.

The system runs RTL819x MIPS, uclibc 0.9.30 and Linux 2.6.30.9:

# cat /proc/cpuinfo
system type             : RTL819x
processor               : 0
cpu model               : 52481
BogoMIPS                : 379.28
hardware watchpoint     : no
tlb_entries             : 32
mips16 implemented      : yes
# ls /lib/ 
ld-uClibc-0.9.30.3.so   libcrypt.so.0           libm.so.0
ld-uClibc.so            libgcc.so               libpthread-0.9.30.3.so
ld-uClibc.so.0          libgcc_s.so             libpthread.so.0
ld.so.1                 libgcc_s.so.1           libuClibc-0.9.30.3.so
libc.so.0               libiw.so.29             modules
libcrypt-0.9.30.3.so    libm-0.9.30.3.so
libcrypt.so             libm.so
# ls /lib/modules/2.6.30.9/
build                modules.dep.bin      modules.pcimap
kernel               modules.ieee1394map  modules.seriomap
modules.alias        modules.inputmap     modules.symbols
modules.alias.bin    modules.isapnpmap    modules.symbols.bin
modules.ccwmap       modules.ofmap        modules.usbmap
modules.dep          modules.order        source
No modern MIPS toolchain would be able to produce binaries for that antique, but luckily there is RLX-linux SDK dump at github (link).

Then it's only a matter of doing a static build of busybox using the oldest SDK in the repo:
PATH=/path/to/rtl819x-toolchain/toolchain/rsdk-1.3.6-4181-EB-2.6.30-0.9.30/bin/:$PATH
export CROSS_COMPILE=mips-linux-
make menuconfig
make
And finally, transfer the static busybox binary to the system:
# tftp -g -r /srv/tftp/busybox -l /tmp/busybox 10.0.0.1
# chmod a+x /tmp/busybox 

# /tmp/busybox         
BusyBox v1.21.0 (2018-04-27 18:51:36 CEST) multi-call binary.

...
Good, replacement busybox with functionality like "netcat" is working. Finally, we can do something like this to pipe the content of flash over the network to a remote system:
cat /dev/mtdblock0 | /tmp/test/busybox nc 10.0.0.1 6666
cat /dev/mtdblock1 | /tmp/test/busybox nc 10.0.0.1 6666
Or back up the rootfs binaries for later analysis
# tar -cf /tmp/root.tar /bin /etc /home /init /lib /mnt /usr /var 
tar: removing leading '/' from member names
tar: /var/tmp/root.tar: file is the archive; skipping
# cat /tmp/root.tar | /tmp/busybox nc 10.0.0.1 6666

I can only finish this article with a famous quote, S in IoT stands for Security.