Security, OpenWRT and storage

Tales of security woes over the years made me a bit paranoid about the various vulnerabilities I could expose my users to, so in the development of Prism I wanted to make everything as secure as possible without breaking the bank.

The first goal is to avoid remote attacks as they’re way harder to detect than ones requiring physical access. We want to make especially sure that we avoid fleet-wide hacks and that compromising a single device will not make it easier to compromise the others. Today we will look at the first step in this direction: default passwords must be different among all devices as users are still not prone to changing them. This is usually done in the industry by calculating a unique password based on the basic devices characteristics, like the MAC address. This usually makes users feel safer and even less motivated to change the password (how may times have you taken pictures of the label under a friends router?). But once we find the algorithm behind the password generator by reversing the routers firmware, we can just sniff the MAC address and use the SSID to calculate the password for any vulnerable router. Device makers usually use this technique because it costs nothing, is very easy and provides some basic security; issuing truly unique passwords requires extra storage that has to be written before the device ships and needs to be persistent across updates. Routers usually have a specific partition for storing various calibration data; I experimented a bit with OpenWRT and found it quite hard to use that for storage and it sometimes wouldn’t survive recovery or direct flashing, but I don’t have a valid reason for why big manufacturers with big money and big development teams are not using it.

Well, turns out I have a nice STM32 on board. The easiest thing would be to read its serial number and hash it in some way to generate the passwords, and that would already be better than just using the publicly discoverable MAC address; but I wanted to go one step further as we have plenty of flash for my firmware and some storage. BOOT0 and Reset pins are connected to the Linux module for firmware updates, so I can use stm32flash to read and write its memory! And I’m not even enabling read protection since this is an open source project, so I can just use the tool to read the chunk of memory I need without bothering writing a custom serial command to fetch the data for me. Let’s try this!

I can generate a RSA key pair, a bunch of passwords for WiFi, root, user/admin/installer for the GUI, an update key, and store them all in a bunch of files:


#gen private
openssl genrsa -out ./$folder/$serial/id_rsa 2048
#save public key
openssl rsa -in ./$folder/$serial/id_rsa -outform PEM -pubout -out ./pub/$serial.pem

echo "$i" > ./$folder/$serial/serial

#wifi pass
echo `pwgen -Bcn 8 -1` > ./$folder/$serial/pw

[...]

I can then tar.gz it all, pad the file to 4k with dd and flash it at the end of the STM32 memory.

cd ./$folder/$serial/
tar -czvf ../$serial.tar.gz *
cd ../..

#check size
sz=`wc -c $folder/$serial.tar.gz | awk '{print $1}'`
if [ $sz -ge 4000 ]; then
	echo -e "\e[31mERROR!! $sz size for $serial\e[0m"
else 
	# First, create a 128K file of all zeros:
	dd if=/dev/zero bs=1024 count=4 of=./$folder/$serial.bin
	# Then, write the BIN to the file without truncating the result:
	dd if=./$folder/$serial.tar.gz of=./$folder/$serial.bin conv=notrunc
fi

This way I can read it up on first boot from a clean image and setup everything!

 
stm32flash -R -i $reset -r key.bin -S $address:0x1000 /dev/ttyS1 
tar -zxf key.bin 

[...] 

if [ -f "root_pass" ]; then 
 #set root password 
 pass=`cat root_pass` 
 echo -e "$pass\n$pass" | passwd root 
else 
 logger -t loadkey "Error! No root pass file" 
fi 

[...]

And that is a great way to protect our users from “keygen” types of attack. But an attacker can still disassemble the device and read the STM32 flash! At this point we are only trying to protect the root password and the private key, as all the other passwords are printed on the manual and on a sticker. Protecting the root password (and other passwords if needed) is easy, as we can just store the pre-calculated hash:

#OpenWRT uses md5
mkpasswd -m md5 $password

but the id-rsa file with the private key needs to be readable! So as far as I know, the only way to do this other than using a TPM would be to gpg encrypt the whole file to add a layer of security. Of course I would have to use the same key for all the products due to the aforementioned limitations, and that means that an attacker just have to read the contents of an update or the flash of a device to discover that key. I could use an encryption password that is based on the MAC address or some other parameter, but that would only make it a bit harder as the attacker just has to reverse that.

I tried to implement all the best practices here, and I think I did quite well compared to big corporations. The biggest threat is, as always, physical access, but I have a big deterrent on my side: the charging station works at very high voltages, so the chances of an attacker messing with it are a bit lower; and if they play safe by removing power before touching it, that shouldn’t go unnoticed by the owner.

So what do you think? Can I take other measures to improve the password storage security, or am I already overthinking it? Let the Hackaday commenters wisdom decide! :)


Bonus short post: I wanted to write a script to automate the printing of labels with passwords, serial numbers and MAC addresses so I purchased a Brother label printer instead of a Dymo because it was better compatible with Linux. I started with the best intentions, but it turns out the included software already allows importing data from a database, so I just had to throw all the data in a CSV  and I was good to go in 20 minutes. The end.  ¯\_(ツ)_/¯

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.