Scripting an automated backup for an AVM FritzBox router

My home server is set up to backup pretty much every device in my network automatically every day. So I figured why not also backup my AVM FritzBox router. In case it breaks or an update fails and it has to be reset, I can easily restore a backup with all settings, phone book entries, logs etc.

Fortunately, there is a very basic interface for automation, so it is possible to shell script the process of exporting the entire configuration. The result is identical to the manual export in the administration interface to export everything to a backup file. The necessary steps are as follows:

  1. Request a challenge
  2. Log in by responding to the challenge
  3. Extract session ID
  4. Export the backup file
  5. Log out

For sake of simplicity, I will assume that the router is available at https://fritz.box (which it is by default) and that the admin password is supersecret.

A challenge can be requested with the URL https://fritz.box/login_sid.lua:

curl -s -k https://fritz.box/login_sid.lua

The response is a SessionInfo XML, which looks like this:

<?xml version="1.0" encoding="utf-8"?>
<SessionInfo>
  <SID>0000000000000000</SID>
  <Challenge>1ma6cy9c</Challenge>
  <BlockTime>0</BlockTime>
  <Rights/>
</SessionInfo>

The challenge is a random string that changes every time the URL is called. Without providing the challenge response, the session ID (SID) will remain empty. To extract the challenge and store it in a variable, simply add a sed statement:

CHALLENGE=`curl -s -k https://fritz.box/login_sid.lua | \
sed 's/.*<Challenge>\([a-z0-9]*\)<.*/\1/'`

So now we have to construct the response and call the URL again. The response is <challenge>-md5(<challenge>-<password>), but it is important to make sure the encoding is UTF-16LE before calculating the hash. Otherwise it will differ and won’t be accepted. This can be done by including iconv:

PASSWORD=supersecret
RESPONSE=$CHALLENGE-`echo -n "$CHALLENGE-$PASSWORD" | iconv -t UTF-16LE | md5`

Call the login URL again, this time with the response:

DATA='response='$RESPONSE'&username=&lp='
curl -s -k --data $DATA https://fritz.box/login_sid.lua

In case you want to use a different user than admin, just provide the username here. The response is again the SessionInfo XML, but SID should be set. It also lists the rights the now logged in user has:

<?xml version="1.0" encoding="utf-8"?>
<SessionInfo>
  <SID>962dd5a4b3d75fb2</SID>
  <Challenge>e56b0c6e</Challenge>
  <BlockTime>0</BlockTime>
  <Rights>
    <Name>Dial</Name>
    <Access>2</Access>
    <Name>App</Name>
    <Access>2</Access>
    <Name>HomeAuto</Name>
    <Access>2</Access>
    <Name>BoxAdmin</Name>
    <Access>2</Access>
    <Name>Phone</Name>
    <Access>2</Access>
    <Name>NAS</Name>
    <Access>2</Access>
  </Rights>
</SessionInfo>

In case the SID remains empty, the login failed. If the password is correct, but it still doesn’t work, it may be an encoding issue with the MD5 hash. Keep in mind that the encoding may also depend on the shell used. Use the following example to check your script:

$ echo -n "test" | iconv -t UTF-16LE | md5
c8059e2ec7419f590e79d7f1b774bfe6

To extract the SID and store it in a variable, add the following sed statement:

SID=`curl -s -k --data $DATA https://fritz.box/login_sid.lua | \
sed 's/.*<SID>\([a-z0-9]*\)<.*/\1/'`

This SID can now be used with the call to export all settings for backup. To do this, a form has to be sent to https://fritz.box/cgi-bin/firmwarecfg, including the SID, the desired operation, as well as the password required to restore the backup in this case. I’ll just use the password backup. This is necessary, because the export contains sensitive information, like ISP and SIP accounts, which will be encrypted.

OUT=/tmp/fritzbox.export
BAKPWD=backup
curl -s -k -o $OUT --form sid=$SID --form ImportExportPassword=$BAKPWD \
--form ConfigExport= https://fritz.box/cgi-bin/firmwarecfg

Now the only thing left to do is log out, so the session doesn’t stay open unnecessarily:

DATA='sid='$SID'&logout=1'
curl -s -k --data $DATA https://fritz.box/login_sid.lua

That’s it! The exported file includes all information stored in the FritzBox, so in case anything goes wrong, it allows a complete restore.