@hurrian I’ve had a chance to compare the 2 firmware versions a little more now. The line
cp $DEFAULT_UCI/ $ETC_CONFIG/* isn’t actually the issue. This just copies the default_uci from /tmp/uci_default. The next line cp -rf $RESTORE_UCI/ $ETC_CONFIG/* would still overwrite any files from the default_uci uploaded with the configuration.
The real issue is restore_config.sh which isn’t in the 3.2.0.9 firmware.
#!/bin/sh
tmp_restore=/tmp/restore_config
tmp_restore_etc_config=/tmp/restore_config/etc/config
tmp_restore_default_config=/tmp/restore_config/default_config
package_list=`cat /etc/package_list`
mkdir -p $tmp_restore_etc_config
for package in $package_list
do
if [ -f /tmp/config/uci/$package ]; then
cp -f /tmp/config/uci/$package $tmp_restore_etc_config
fi
done
cp -rf /tmp/uci_default $tmp_restore_default_config
if [ -d $tmp_restore_default_config -a -d $tmp_restore_etc_config ]; then
ucihlp -u $tmp_restore_default_config restore $tmp_restore /etc/allow.list
for package in $package_list
do
if [ -f $tmp_restore_default_config/$package ]; then
cp -f $tmp_restore_default_config/$package /data/restore_uci
fi
done
rm -rf $tmp_restore
else
rm -rf $tmp_restore
exit 1
fi
Now it checks with package_list and allow.list before copying any files. I couldn’t find package_list, but allow.list is in the extracted 3.2.0.11 firmware I posted.
I also had a chance to look at rolling back the firmware. That is controlled by authentication.sh
#/bin/sh
AUTH_DIR="/tmp/.auth”
CRSP_SIGN="$AUTH_DIR/sign”
CRSP_IMAGE="$AUTH_DIR/image”
PROD_PUB_KEY="/etc/key/whole_img_prod_pub.pem”
DEV_PUB_KEY="/etc/key/whole_img_dev_pub.pem”
img_authentication() {
signed_image=$1
token=$(uci get sshd.config.usb_token_path)
interim_fw=1
rm -fr $AUTH_DIR
echo 3 /proc/sys/vm/drop_caches
mkdir -p $AUTH_DIR
echo "signed_image $signed_image”
echo "CRSP_SIGN $CRSP_SIGN”
echo "CRSP_IMAGE $CRSP_IMAGE”
dd if=$signed_image of=$CRSP_SIGN bs=256 count=1
dd if=$signed_image of=$CRSP_IMAGE bs=256 skip=1
# Check prod signature on 1st 256 bytes
openssl dgst -sha256 -verify $PROD_PUB_KEY -sigopt rsa_padding_mode:pss -signature $CRSP_SIGN $CRSP_IMAGE
if [ $? == 0 ]; then
echo "Image authentication (prod) successfully”
mv $CRSP_IMAGE $signed_image # Flash the unsigned image, replace source file!
rm -fr $AUTH_DIR
echo 3 /proc/sys/vm/drop_caches
return 1
elif [[ "$token" != "empty" ]] && [[ "$interim_fw" != "1" ]]; then
echo "Image authentication failed!”
return 0
fi
# Check dev signature on 1st 256 bytes
openssl dgst -sha256 -verify $DEV_PUB_KEY -sigopt rsa_padding_mode:pss -signature $CRSP_SIGN $CRSP_IMAGE
if [ $? == 0 ]; then
echo "Image authentication (dev) successfully on signature”
mv $CRSP_IMAGE $signed_image # Flash the unsigned image, replace source file!
rm -fr $AUTH_DIR
echo 3 /proc/sys/vm/drop_caches
return 1
else
echo "Image authentication failed!”
fi
# rm -fr $AUTH_DIR
echo 3 /proc/sys/vm/drop_caches
return 0
}
Here we extract the first 256 bytes of the firmware, and then take the sha256 hash of the rest of the image. The first 256 bytes is decrypted with the “whole_img” key and compared against the hash, if they’re a match the image authenticates and will be installed. I ran the commands myself, and the firmware successfully validate using the dev key. The issue is that they changed the keys in 3.2.0.11, but signed it with the keys for 3.2.0.9. So when you update to 3.2.0.11 you will get the new keys, which work to decrypt all firmware versions after that. However, trying to roll back to 3.2.0.9 no longer works since the signature is now decrypted with the wrong key.
Since we have the firmware, we could replace those first 256 bytes in the signature with the correct SHA256 digest (8ff3dcf02dadd48ea879848e14961aec59be24fc6c79581afbd8ad0f9ffb62a0) if we had the private key. Unfortunately we don’t, and likely never will. We could correctly guess the 256 byte signature, but there are 512^16 possibilities, which AI tells me is way more than the number of atoms in the known universe