Skip to content

Instantly share code, notes, and snippets.

@ungeskriptet
Created January 16, 2025 19:01
Show Gist options
  • Save ungeskriptet/35f7c6f785eb01d6ffd6b3852e6ac970 to your computer and use it in GitHub Desktop.
Save ungeskriptet/35f7c6f785eb01d6ffd6b3852e6ac970 to your computer and use it in GitHub Desktop.
FRITZ!Box cleanup script
from requests import get, post, put
from time import sleep
import hashlib
import xml.etree.ElementTree as ET
URL = 'https://fritz.box/login_sid.lua?version=2'
USERNAME = 'user'
PASSWORD = 'password'
def main():
with get(URL) as login_sid:
xml = ET.fromstring(login_sid.content)
challenge = xml.find('Challenge').text
blocktime = int(xml.find('BlockTime').text)
challenge_response = calculate_pbkdf2_response(challenge, PASSWORD)
if blocktime > 0:
sleep(blocktime)
data = {'username': USERNAME, 'response': challenge_response}
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
with post(url=URL, data=data, headers=headers) as post_sid:
sid = ET.fromstring(post_sid.content).find('SID').text
data = '{"cleanup_landevices":"1"}'
headers = {'Content-Type': 'application/json', 'AUTHORIZATION': f'AVM-SID {sid}'}
put(url='https://fritz.david-w.eu/api/v0/landevice', headers=headers, data=data)
def calculate_pbkdf2_response(challenge: str, password: str) -> str:
challenge_parts = challenge.split('$')
iter1 = int(challenge_parts[1])
salt1 = bytes.fromhex(challenge_parts[2])
iter2 = int(challenge_parts[3])
salt2 = bytes.fromhex(challenge_parts[4])
hash1 = hashlib.pbkdf2_hmac('sha256', password.encode(), salt1, iter1)
hash2 = hashlib.pbkdf2_hmac('sha256', hash1, salt2, iter2)
return f'{challenge_parts[4]}${hash2.hex()}'
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment