jhubig / FritzBoxShell

Some shell scripts for controlling and checking the Fritz!Box/Fritz!Repeater
MIT License
139 stars 22 forks source link

Automatic back-up of the Fritzbox-Configuartion #48

Open UweGrunewald opened 2 months ago

UweGrunewald commented 2 months ago

It happens rarely but also a Fritzbox can die. Once you encounter this and you run a smart home with 80 Wi-Fi connected devices on fix IP-addresses and your Fritzbox back-up is fairly old, you get the idea of saving the Fritzbox config regularly. So did I and had expected to find a recipe to implement a solution on one of my Raspi's.

Neither Google nor any AI revealed a solution. Open-AI at least made a proposal for a shell script, that does not really work. I am hoping for someone here being able to either find the cause for the script not working or provide a solution.

I run a 7530 AX on the latest firmware that has an admin user "Backup". Script and error log below.

Whoever provides a solution may determine a charity organization I am willing to donate 50,- € to.

The script (made by open AI)

#!/bin/bash
set -x  # Enable error logging

# Fritz!Box IP address
FRITZBOX_IP="192.168.178.1"

# Fritz!Box credentials
USERNAME="Backup"
PASSWORD="xxxxxxxxxxxxxxxxxxx"

# Path to save the backup
BACKUP_PATH="$HOME/fritzbox_backups/fritzbox_config_$(date +%Y%m%d).export"

# Fetch the challenge from Fritz!Box
CHALLENGE=$(curl -s "http://${FRITZBOX_IP}/login_sid.lua" | grep -oP '(?<=<Challenge>)[^<]+')

if [ -z "$CHALLENGE" ]; then
    echo "Failed to fetch challenge. Exiting."
    exit 1
fi

# Calculate the response (MD5 hash of Challenge + '-' + Password)
RESPONSE=$(echo -n "$CHALLENGE-$PASSWORD" | iconv -t UTF-16LE | md5sum | awk '{print $1}')

# Log in and get the session ID
SID=$(curl -s "http://${FRITZBOX_IP}/login_sid.lua" --data "response=${CHALLENGE}-${RESPONSE}&username=${USERNAME}" | grep -oP '(?<=<SID>)[^<]+')

if [ "$SID" = "0000000000000000" ]; then
    echo "Login failed! Check your username and password."
    exit 1
fi

# Prepare the SOAP body for configuration export
SOAP_BODY='<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <s:Body>
    <u:ConfigurationStarted xmlns:u="urn:dslforum-org:service:DeviceConfig:1"></u:ConfigurationStarted>
  </s:Body>
</s:Envelope>'

# Send the SOAP request to start configuration export
EXPORT_RESPONSE=$(curl -s -X POST "http://${FRITZBOX_IP}:49000/upnp/control/deviceconfig" \
    -H "Content-Type: text/xml; charset=\"utf-8\"" \
    -H "SoapAction: urn:dslforum-org:service:DeviceConfig:1#ConfigurationStarted" \
    --data "$SOAP_BODY" -b sid="$SID")

# Check if the response indicates success
if echo "$EXPORT_RESPONSE" | grep -q '401 Unauthorized'; then
    echo "Export request failed with 401 Unauthorized. Check permissions or API changes."
    echo "$EXPORT_RESPONSE"
    exit 1
fi

# Download the backup file
curl -s "http://${FRITZBOX_IP}/cgi-bin/backup.lua?sid=${SID}&action=export" -o "$BACKUP_PATH"

# Check if the backup file was created
if [ ! -s "$BACKUP_PATH" ]; then
    echo "Backup failed. The file is empty or wasn't created."
else
    echo "Backup successfully saved to $BACKUP_PATH"
fi

# Logout
curl -s -k --data "sid=${SID}&logout=1" "http://${FRITZBOX_IP}/login_sid.lua"
echo "Logged off"

Log, when running the script:

admin@raspberrypi:/etc $ ./fritz.sh
+ FRITZBOX_IP=192.168.178.1
+ USERNAME=Backup
+ PASSWORD=xxxxxxxxxxxxxxxx
++ date +%Y%m%d
+ BACKUP_PATH=/home/admin/fritzbox_backups/fritzbox_config_20240909.export
++ curl -s http://192.168.178.1/login_sid.lua
++ grep -oP '(?<=<Challenge>)[^<]+'
+ CHALLENGE=68e6a09a
+ '[' -z 68e6a09a ']'
++ echo -n 68e6a09a-Backup2024
++ iconv -t UTF-16LE
++ md5sum
++ awk '{print $1}'
+ RESPONSE=a45c852efd0f83efebc9acee4eb72fa0
++ curl -s http://192.168.178.1/login_sid.lua --data 'response=68e6a09a-a45c852efd0f83efebc9acee4eb72fa0&username=Backup'
++ grep -oP '(?<=<SID>)[^<]+'
+ SID=70a6a26a81ad5d24
+ '[' 70a6a26a81ad5d24 = 0000000000000000 ']'
+ SOAP_BODY='<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <s:Body>
    <u:ConfigurationStarted xmlns:u="urn:dslforum-org:service:DeviceConfig:1"></u:ConfigurationStarted>
  </s:Body>
</s:Envelope>'
++ curl -s -X POST http://192.168.178.1:49000/upnp/control/deviceconfig -H 'Content-Type: text/xml; charset="utf-8"' -H 'SoapAction: urn:dslforum-org:service:DeviceConfig:1#ConfigurationStarted' --data '<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <s:Body>
    <u:ConfigurationStarted xmlns:u="urn:dslforum-org:service:DeviceConfig:1"></u:ConfigurationStarted>
  </s:Body>
</s:Envelope>' -b sid=70a6a26a81ad5d24
+ EXPORT_RESPONSE='<HTML><HEAD><TITLE>401 Unauthorized (ERR_NONE)</TITLE></HEAD><BODY><H1>401 Unauthorized</H1><BR>ERR_NONE<HR><B>Webserver</B> Mon, 09 Sep 2024'04:12:34 GMT</BODY></HTML>
+ echo '<HTML><HEAD><TITLE>401 Unauthorized (ERR_NONE)</TITLE></HEAD><BODY><H1>401 Unauthorized</H1><BR>ERR_NONE<HR><B>Webserver</B> Mon, 09 Sep 2024 04:12:34 G'T</BODY></HTML>
+ grep -q '401 Unauthorized'
+ echo 'Export request failed with 401 Unauthorized. Check permissions or API changes.'
Export request failed with 401 Unauthorized. Check permissions or API changes.
+ echo '<HTML><HEAD><TITLE>401 Unauthorized (ERR_NONE)</TITLE></HEAD><BODY><H1>401 Unauthorized</H1><BR>ERR_NONE<HR><B>Webserver</B> Mon, 09 Sep 2024 04:12:34 G'T</BODY></HTML>
<HTML><HEAD><TITLE>401 Unauthorized (ERR_NONE)</TITLE></HEAD><BODY><H1>401 Unauthorized</H1><BR>ERR_NONE<HR><B>Webserver</B> Mon, 09 Sep 2024 04:12:34 GMT</BODY></HTML>
jhubig commented 1 month ago

Hello.

I did some investigations recently and found out the following. First prerequisite to be able to do any automatic backup solution is to disable the 2FA inside the FritzBox which is in the most cases not so easy to do. But I found a way to manage that. I found the information in the following post(s): https://www.ip-phone-forum.de/threads/fb7590-und-andere-boxen-ab-os-7-50-best%C3%A4tigungen-deaktivieren.314515/post-2538475

Then I prepared the FritzBoxShell relevant script for the backup:

# Login Data
BoxIP="fritz.box"
BoxUSER="MeinBenutzer"
BoxPW="MeinPasswort"

# Get Security Port
location="/upnp/control/deviceinfo"
uri="urn:dslforum-org:service:DeviceInfo:1"
action='GetSecurityPort'

securityPort=$(curl -s -k -m 5 --anyauth -u "$BoxUSER:$BoxPW" "http://$BoxIP:49000$location" -H 'Content-Type: text/xml; charset="utf-8"' -H "SoapAction:$uri#$action" -d "<?xml version='1.0' encoding='utf-8'?><s:Envelope s:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'><s:Body><u:$action xmlns:u='$uri'></u:$action></s:Body></s:Envelope>" | grep NewSecurityPort | awk -F">" '{print $2}' | awk -F"<" '{print $1}')
echo "$securityPort"

# Config File Download
location="/upnp/control/deviceconfig"
uri="urn:dslforum-org:service:DeviceConfig:1"
action='X_AVM-DE_GetConfigFile'
option2='testing'

curlOutput1=$(curl -s -k -m 5 --anyauth -u "$BoxUSER:$BoxPW" "https://$BoxIP:$securityPort$location" -H 'Content-Type: text/xml; charset="utf-8"' -H "SoapAction:$uri#$action" -d "<?xml version='1.0' encoding='utf-8'?><s:Envelope s:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'><s:Body><u:$action xmlns:u='$uri'><NewX_AVM-DE_Password>$option2</NewX_AVM-DE_Password></u:$action></s:Body></s:Envelope>")

echo "$curlOutput1"

BUT...It does not work. Usually the 2nd SOAP call should give me the download URL of the backup, but instead I get an empty string. I will still try to investigate but I wanted to give you a short update.

49443
<und eine leere Zeile>

Cheers, Johannes

UweGrunewald commented 1 month ago

Wow, thx a lot Johannes for pursuing on the issue. All I can comment is that I am unaware of any 2FA for my Fritzbox, but this may not mean anything. Further I can tell that the KI created script above was able to login - at least according to the FritzBox's logs. Press thumbs, you can find a working solution. Best, Uwe