Please respect the license under which this work is made available. (See terms and conditions at the end of the page)
The scripts and code used are available on github
Here we present a quick teardown of the Lidl Smart Home Gateway and a quick introduction to gaining access to the Linux root shell of the device.
This device is plesantly "hackable," and gaining access to the device to load custom firmware and modifications is easy. (once you have physical access.) As a general point I think this is how it should always be. An electronic device that is totally locked down to the manufacturer provides no opportunites for further use and thus its potential for education, entertainment and utility beyond what the original manufacturer forsaw is lost.
One of the aspirations for this project is to turn this device into a simple ZigBee gateway, capable of running basic functions (light switches, etc) autonomously in offline mode but also supporting an online mode integrated with Home Assistant. If I have time I will develop this but no promises!
You can use this hack to directly integrate this gateway with Home Assistant.. Click the link for more information.
The home gateway uses a screwless design to hold the case together. There are 8 plastic clips spread equally around the case and you need to work carefully around about half of them until you can separate the lid from the case.
Inside the gateway there's a single PCB featuring a main CPU, some RAM, an SPI flash chip, a separate ZigBee CPU, ethernet magnetics, LEDs, connectors and other supporting components. A neat design overall.
Main components are detailed here:
J1 - A Combined Serial port and ZigBee module ARM debug port. This is not usually populated - we added a header to ours. Pinout is:
Serial port parameters are:
The manufacturer has kindly labelled the test points.
Notes for newbies: You must use a 3.3V TTL serial port to connect to this device. Connect only Ground (GND), TX and RX. Do not connect Vcc. Do not be tempted to connect the device directly to a PC serial port. Failure to observe these notes may damage your device.
After connecting a 3.3V TTL Serial port to J1, the Linux Console is available. Note, this is password protected and the password is different for each device. More on this later.
When starting the device, the bootloader is accessible by pressing ESC on the console very early on in the boot process. Doing this will stop the boot process and land you in the RealTek bootloader prompt.
Entering a ?, followed by enter will list out the available commands. Available features include the ability to read and write the FLASH, download from a TFTP server into memory, and inspect memory.
The bootloader has a default IP address of 192.168.1.6 and the TFTP server is set to 192.168.1.97.
The bootlog helpfully shows the flash layout as follows:
0x000000000000-0x000000020000 : "boot+cfg"
0x000000020000-0x000000200000 : "linux"
0x000000200000-0x000000400000 : "rootfs"
0x000000400000-0x000000420000 : "tuya-label"
0x000000420000-0x000001000000 : "jffs2-fs"
It's always a good idea to backup devices, where possible, before playing around. To do this, rather than desolder the SPI, we created a script (dump.py) to repeatedly call the FLR and DB commands and we used that to create a backup copy of the flash. It took a long time for the script to run but it was overnight so we didn't care.
Note: Below is how we gained access initially. We have since created a script that reveals the root password without needing to do the below.
1) We pulled the SquashFS rootfs. This process took about 40 minutes.
python dump_flash.py --serial-port /dev/ttyUSB0 --output-file rootfs.bin --start-addr 0x200000 --end-addr 0x400000
2) We extracted the SquashFS
sudo unsquashfs rootfs.bin
3) We replaced the /etc/passwd symlink with a passwd file we created with a known root password. The password for this one is "password":
root:dMPfG7vdo8u1I:0:0:root:/:/bin/sh
4) We recreated the SquashFS blob
sudo mksquashfs squashfs-root newroot.sqfs -comp xz -noappend
5) We wrote a script (rootfs_tool.py) to modify the header to include the new length and fix up the 16-bit checksum on the end
python rootfs_tool.py build newroot.sqfs newroot.bin
6) Finally we TFTP'd the newroot.bin file to the device and used the bootloader command FLW to write it to flash.
After booting up, we were able to log into the device as root. Win.
Attaching an ARM debugger to pins 5 and 6 of J1 allows inspection and live debugging of the ZigBee module CPU and backing up the code if required. We used a Segger J-Link Edu Mini whih supports this part directly.
The actual root password is set, each time the device boots, to the last 8 characters of the device's "auzkey". Running "/tuya/tuyamtd read auzkey" on the device will tell you this value. You can also read this value straight out of flash using this technique.
The device runs an SSH server (dropbear) on port 2333. The server has some brute force protection whereby failed logins will cause the device to stop this server for an increasing amount of time. The device has to be left switched on for the anti-brute force timer to expire because the failure counter is stored persistently in the flash. If you already have filesystem access, you can reset this prematurely by deleting the /tuya/ssh/cnt file.