
Kit d'outils PoC et de détection pour Danfoss AK-SM 8xxA CVE-2025-41450/-41451/-41452 : contournement d'authentification par code du jour, RCE alarme-vers-mail et injection de configuration nginx, avec règles Suricata/Sigma.
PoC de recherche/ingénierie de détection pour les trois vulnérabilités de l'interface web AK-SM 8xxA divulguées par Claroty Team82 et corrigées par Danfoss dans R4.2 / R4.3.1 (DSA-2025-03-01, DSA-2025-08-01, CISA ICSA-25-140-03) :
| CVE | Faiblesse | Affecté | Corrigé |
|---|---|---|---|
| CVE-2025-41450 | Contournement d'authentification caché « code-of-the-day » (mot de passe dérivé de la date/heure) sur xml.cgi?action=getauth | < R4.2 | R4.2 |
| CVE-2025-41451 | Injection de commandes OS post-authentification dans la configuration alarme-vers-mail / SMTP (élément 0x1be1) | < 4.3.1 | 4.3.1 |
| CVE-2025-41452 | Remplacement post-authentification de headers.conf nginx via action=load_nginx_headers → injection de directives + DoS par plantage de sm_app | < 4.3.1 | 4.3.1 |
emulator/aksm800a_emulator.py vulnerable-behavior emulator (127.0.0.1 only)
poc/cve_2025_41450_code_of_the_day.py
poc/cve_2025_41451_alarm_mail_cmd_injection.py
poc/cve_2025_41452_nginx_conf_injection.py
detection/suricata/danfoss-aksm-cves.rules Suricata rules (see in-file caveats)
detection/sigma/*.yml Sigma host/log rules
detection/test_rules_against_captures.py replay captures against the ruleset
captures/http-requests.jsonl full request log, tagged per CVE
WRITEUP.md FROMAGEGATE incident context + full research summary
Python 3 stdlib uniquement ; aucune dépendance.
python3 emulator/aksm800a_emulator.py 8080 & # start the target
python3 poc/cve_2025_41450_code_of_the_day.py # exit 0 = bypass works
python3 poc/cve_2025_41451_alarm_mail_cmd_injection.py
python3 poc/cve_2025_41452_nginx_conf_injection.py # add --no-dos to skip DoS
python3 detection/test_rules_against_captures.py # replay captures vs Suricata rules
Les PoC 41451 et 41452 enchaînent par défaut sur le contournement 41450 (un véritable
attaquant ne dispose d'aucun identifiant configuré) ; les deux acceptent --user/--password
(41451) pour démarrer à partir d'une session légitime à la place. Tous les PoC acceptent --target HOST:PORT, ce qui leur permet de fonctionner aussi contre un firmware réellement vulnérable — mais
l'algorithme du code du jour et les noms d'attributs du contournement doivent être remplacés par
les valeurs récupérées depuis le firmware (voir les réserves ci-dessous).
Chaque requête de l'émulateur est journalisée dans captures/http-requests.jsonl avec
des étiquettes. Les artefacts réseau stables et dignes d'une signature sont :
CVE-2025-41450 (contournement d'authentification)
POST /xml.cgi?action=getauth transportant des attributs inattendus au-delà
du nom d'utilisateur/mot de passe (ici : codeofday=1 / support=1 ; les noms réels sont
expurgés dans les sources publiques — à récupérer depuis le firmware pour les règles finales).Server: nginx sur le port de gestion) sur un firmware < R4.2 est intrinsèquement
vulnérable — la détection de bannière/version est le signal le plus fiable.CVE-2025-41451 (injection de commande → RCE)
POST /xml.cgi?action=set_email_config authentifié avec des
métacaractères de shell (; | & $() `) dans le champ mot de passe e-mail
(élément de configuration 0x1be1). Les mots de passe SMTP légitimes contiennent rarement ;+commande.x'; <cmd> # / $(<cmd>) etc. — voir les lignes de journal
constructed_cmd: étiquetées pour savoir exactement comment la valeur atterrit dans un shell.id, curl, ...).CVE-2025-41452 (injection de configuration nginx → manipulation du trafic / DoS)
xml.cgi?action=load_nginx_headers
(nom de fichier headers.conf). Cet endpoint n'a aucune raison légitime d'être
appelé en dehors d'une rare maintenance administrateur — une alerte basée sur le volume fonctionne.location, proxy_pass, rewrite,
add_header.emulator/aksm800a_emulator.py:generate_code) qui préserve la propriété documentée
(code dérivé uniquement de la date de l'appareil). Les PoC et l'émulateur le partagent,
de sorte que la chaîne est fonctionnelle de bout en bout. Pour du matériel réel, extrayez
check_code_of_day depuis le firmware et intégrez-le.id → fichier de preuve).
À lier/exécuter uniquement sur 127.0.0.1.