Backup Restore config files - acc-/tplink-archer-c2300 GitHub Wiki
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 !!!
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.
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
- 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
- Install zlib-dev package, example for Debian Stretch:
sudo apt install zlib1g-dev
- 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
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.
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
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>
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.
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
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