Skip to content

Backup Restore config files

Adam edited this page Jan 12, 2019 · 4 revisions

DISCLAIMER - USE AT YOUR OWN RISK !

All the sripts and commands used on this page work on my Archer C2300 router, but I take no responsibility if you brick yours! Use with caution !!!

OpenWrt roots

Original firmware is based on OpenWrt, however when you backup the settings, these are not the nice .tar.gz files we're used to. After a few nights of analysis, I discovered that backup procedure follows the steps listed below.

Ready to use scripts

Please refer to scripts for ready to use scripts converting between binary file (download from original firmware "Backup") and xml file (reflecting /config/ files structure).

Note: the scripts require the OpenSSL with ZLIB support, see the section below if scripts fail

Compiling OpenSSL with zlib support

  1. Go to https://www.openssl.org/source/ and download latest source code, 1.1.0j in my example:
wget https://www.openssl.org/source/openssl-1.1.0j.tar.gz
  1. Install zlib-dev package, example for Debian Stretch:
sudo apt install zlib1g-dev
  1. Extract, configure, compile and install
tar zxvf openssl-1.1.0j.tar.gz
cd openssl-1.1.0j/
./config zlib -Wl,--enable-new-dtags,-rpath,'$(LIBRPATH)'
make
sudo make install

Scripts usage

The scripts bin2xml.sh and xml2bin.sh assume openssl path to be /usr/local/bin/openssl - default for 1.1.0j compiled from sources. If your OpenSSL with zlib support is located somewhere else, please edit the scripts to reflect the correct path.

You can use the scripts to convert binary file to a human readable xml, adjust your settings, create binary file and upload.

Files created from the backup

The xml structure gives you the power to create new files. In theory you could think about creating your own file by just adding a new eg. <myfile> tag under <config> directly. I didn't test it, but might be it's forbidden and you can alter only existing configuration files. I found in strace logs that probably only these files are taken into account when performing Restore functionality:

access_control administration appflow autoreboot basic_security client_mgmt ddns dhcp dhcp6s diagnostic dnsproxy domain_login dos_protection dropbear feedback firewall fstab history_list ifttt_trigger igmpproxy imb iptv ledctrl ledpm locale luci mcproxy mcu minidlna modem nat network offline_download openvpn pc_insights portspeed pptpd protocol quicksetup radvd ripd samba security security_history sharecfg shn_dev_stats speed_test switch syslog sysmode system tfstats time_machine tm_parental_control tm_qos ucitrack uhttpd upnpd usbshare wake_up wireless wireless_schedule wportal

Backup binary file to xml file conversion

user@debian:~/scripts$ ./bin2xml.sh backup-AC2300-2019-01-10.bin
File MD5: b37598ac5105ea9974fc6634a4c92a76, product MD5: b37598ac5105ea9974fc6634a4c92a76
MD5 matches, this is the right binary file :-)
XML file saved in backup-AC2300-2019-01-10.xml

user@debian:~/scripts$ head -20 backup-AC2300-2019-01-10.xml
<?xml version="1.0" encoding="utf-8"?>
<config>
<security>
<modules_status name="modules_status">
<intrusion_prevention_system>1</intrusion_prevention_system>
<malicious_sites_blocking>1</malicious_sites_blocking>
<infected_device_prevention_blocking>1</infected_device_prevention_blocking>
</modules_status>
</security>
<tm_qos>
<qos_mode name="qos_mode">
<mode>fair</mode>
</qos_mode>
<custom_detail name="custom_detail">
<media>normal</media>
<download>normal</download>
<chat>normal</chat>
<surf>normal</surf>
<game>normal</game>
<change>0</change>

xml to binary Restore file conversion

The example below copies produced xml file to newfile.xml, converts to bin and calculates md5sum for both .bin files to prove that bin2xml produced exactly the same Backup/Restore binary file.

user@debian:~/scripts$ cp backup-AC2300-2019-01-10.xml newfile.xml

user@debian:~/scripts$ ./xml2bin.sh newfile.xml
BIN file saved in newfile.bin

user@debian:~/scripts$ md5sum *.bin
28ec10d2f7232b7e95d1a683c68d25a6  backup-AC2300-2019-01-10.bin
28ec10d2f7232b7e95d1a683c68d25a6  newfile.bin

Now, if you want to change something in your configuration, just play with xml file, convert it to bin and upload via web interface Restore settings functionality.

Original firmware Backup script details (for EXPERIENCED users)

Using lua script to produce Backup .bin file (same as downloaded from original firmware web interface)

Once you have access to ssh console, you could simulate creating backup binary file by calling this lua command:

root@AC2300:~# lua -l 'luci.controller.admin.firmware' -e 'local x=luci.controller.admin.firmware.config_backup()'
lua: attempt to yield across metamethod/C-call boundary
stack traceback:
        [C]: in function 'yield'
        ?: in function 'header'
        ?: in function 'config_backup'
        (command line):1: in main chunk
        [C]: ?

The script fails because of lacking HTTP libraries ("header"), therefore... it didn't remove some of the files we want. You can ls -al /tmp and grep by current time, and you'll see these files are left:

root@AC2300:~# ls -al /tmp | grep "Jan 10 11:28"
drwxrwxrwt   23 root     root             0 Jan 10 11:28 .
-rw-r--r--    1 root     root         12576 Jan 10 11:28 mid-backup-userconf.bin
-rw-r--r--    1 root     root         12560 Jan 10 11:28 ori-backup-userconf.bin
-rw-r--r--    1 root     root            16 Jan 10 11:28 product_name_md5_file
-rw-r--r--    1 root     root           274 Jan 10 11:28 productinfo
-rw-r--r--    1 root     root         12592 Jan 10 11:28 save-backup-userconf.bin

save-backup-userconf.bin is the file being downloaded from original firmware web interface

Using strace for more advanced analysis of executed commands

You can get more verbose analysis by using strace (see cross-compiled-files) for a binary, and then see what commands were executed by lua script. I splitted the output, removed unnecessary logs and put some comments.

Execution, checking for some partitions (not found for me - nvrammanger -s shows partitions but without any names, these are hidden somehow, because nvrrammanager can still READ them)

root@AC2300:~# strace -x -f -s 1024  lua -l 'luci.controller.admin.firmware' -e 'luci.controller.admin.firmware.config_backup()' 2>&1 | grep execve\(
[pid  3660] execve("/bin/sh", ["sh", "-c", "nvrammanager -s | grep default-config2 >/dev/null 2>&1"], 0xff97d21c /* 12 vars */) = 0
[pid  3663] execve("/bin/sh", ["sh", "-c", "nvrammanager -s | grep user-config2 >/dev/null 2>&1"], 0xff97d21c /* 12 vars */) = 0

Next block extracts product name from product-info (which is a string "Archer C2300"), stores it in /tmp/product_name (by LUA script itself), calls md5sum to calculate md5 and stores md5 value as binary in /tmp/product_name_md5_file (storing in files done by LUA itself)

[pid  3666] execve("/bin/sh", ["sh", "-c", "nvrammanager -r /tmp/productinfo -p product-info >/dev/null 2>&1"], 0xff97d21c /* 12 vars */) = 0

[pid  3668] execve("/bin/sh", ["sh", "-c", "md5sum /tmp/product_name"], 0xff97d21c /* 12 vars */) = 0
[pid  3670] execve("/bin/sh", ["sh", "-c", "rm -f /tmp/product_name"], 0xff97d21c /* 12 vars */) = 0

Now, the binary config (NOT the same as downloaded from web!!!) is received from nvram partition user-config, decrypted and decompressed. BTW: the AES keys are stored as plaintext in crypto.lua, see yourself: strings /usr/lib/lua/luci/model/crypto.lua | head -22

[pid  3672] execve("/bin/sh", ["sh", "-c", "nvrammanager -r /tmp/ori-backup-userconf.bin -p user-config >/dev/null 2>&1"], 0xff97d21c /* 12 vars */) = 0
[pid  3674] execve("/bin/sh", ["/bin/sh", "-c", "openssl aes-256-cbc -d -in \"/tmp/ori-backup-userconf.bin\" -K 2EB38F7EC41D4B8E1422805BCD5F740BC3B95BE163E39D67579EB344427F7836 -iv 360028C9064242F81074F4C127D299F6 | openssl zlib -d"], 0xff97d21c /* 12 vars */) = 0

Now, LUA script internally converts the decrypted data (which is an xml) to a folder structure /tmp/backupcfg_merge/config and removes two files for security reasons: accountmgnt and cloud_config. Once done, converts the files structure back to xml file /tmp/ori-backup-userconf-raw.xml, compresses and encrypts it to /tmp/ori-backup-userconf.bin

[pid  3677] execve("/bin/sh", ["sh", "-c", "rm -f /tmp/ori-backup-userconf.bin"], 0xff97d21c /* 12 vars */) = 0
[pid  3679] execve("/bin/sh", ["sh", "-c", "mkdir -p /tmp/backupcfg_merge"], 0xff97d21c /* 12 vars */) = 0
[pid  3681] execve("/bin/sh", ["sh", "-c", "mkdir /tmp/backupcfg_merge/config"], 0xff97d21c /* 12 vars */) = 0
[pid  3683] execve("/bin/sh", ["sh", "-c", "rm -f /tmp/backupcfg_merge/config/accountmgnt"], 0xff97d21c /* 12 vars */ <unfinished ...>
[pid  3685] execve("/bin/sh", ["sh", "-c", "rm -f /tmp/backupcfg_merge/config/cloud_config"], 0xff97d21c /* 12 vars */) = 0
[pid  3687] execve("/bin/sh", ["sh", "-c", "rm -f /tmp/ori-backup-userconf-raw.xml"], 0xff97d21c /* 12 vars */) = 0
[pid  3689] execve("/bin/sh", ["/bin/sh", "-c", "openssl zlib -e -in \"/tmp/ori-backup-userconf-raw.xml\" | openssl aes-256-cbc -e -K 2EB38F7EC41D4B8E1422805BCD5F740BC3B95BE163E39D67579EB344427F7836 -iv 360028C9064242F81074F4C127D299F6"], 0xff97d21c /* 12 vars */) = 0
[pid  3692] execve("/bin/sh", ["sh", "-c", "rm -f /tmp/ori-backup-userconf-raw.xml"], 0xff97d21c /* 12 vars */) = 0

The final part concatenates binary file with product name md5 with the encrypted data, producing /tmp/mid-backup-userconf.bin. This file is then compressed and encrypted again and result is saved in /tmp/save-backup-userconf.bin

[pid  3694] execve("/bin/sh", ["sh", "-c", "rm -rf /tmp/backupcfg_merge"], 0xff97d21c /* 12 vars */) = 0
[pid  3696] execve("/bin/sh", ["sh", "-c", "cat /tmp/product_name_md5_file /tmp/ori-backup-userconf.bin > /tmp/mid-backup-userconf.bin"], 0xff97d21c /* 12 vars */) = 0
[pid  3698] execve("/bin/sh", ["/bin/sh", "-c", "openssl zlib -e -in \"/tmp/mid-backup-userconf.bin\" | openssl aes-256-cbc -e -K 2EB38F7EC41D4B8E1422805BCD5F740BC3B95BE163E39D67579EB344427F7836 -iv 360028C9064242F81074F4C127D299F6"], 0xff97d21c /* 12 vars */) = 0