
Ceci est un bref rapport d'une vulnérabilité (CVE-2019-12489) découverte en jouant avec un modem/routeur Fastgate de Fastweb et Ghidra. La vulnérabilité permet l'exécution d'une injection de commande via une requête HTTP et peut être utilisée pour activer un shell SSH.
Tous les fichiers du firmware se trouvent sur http://59.0.121.191:8080/ACS-server/file/FILENAME
Où FILENAME est égal à :
Ainsi, par exemple, pour obtenir le dernier firmware, allez à http://59.0.121.191:8080/ACS-server/file/0.00.89_FW_200_Askey
Pour extraire les fichiers, nous avons besoin de l'utilitaire sur https://github.com/nlitsme/ubidump (c'est le premier qui a fonctionné pour moi).
En faisant un binwalk sur le fichier, nous obtenons :
$ binwalk 0.00.89_FW_200_Askey
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
94 0x5E JFFS2 filesystem, little endian
3276894 0x32005E UBI erase count header, version: 1, EC: 0x0, VID header offset: 0x800, data offset: 0x1000
Nous n'avons pas besoin du système de fichiers JFFS2, seulement de la partie UBI. Pour ce faire, nous pouvons découper le fichier avec dd. Pour cela, nous avons besoin de la taille totale et du point de départ de l'UBI.
La taille du fichier peut être obtenue avec ls :
$ ls -la
total 55836
drwxr-xr-x 3 riccardo users 4096 set 24 10:07 .
drwx------ 83 riccardo users 12288 set 24 10:08 ..
-rw-r--r-- 1 riccardo users 57147506 set 24 10:05 0.00.89_FW_200_Askey
La valeur 57147506 est ce dont nous avons besoin.
En regardant la sortie de binwalk, nous voyons que la partie UBI commence à 3276894. Avec ces deux valeurs, nous pouvons utiliser dd comme ceci :
$ dd if=0.00.89_FW_200_Askey of=0.00.89_FW_200_Askey.UBI bs=1 skip=3276894 count=57147506
Maintenant, nous pouvons utiliser ubidump (après une configuration initiale selon la configuration système) :
$ git clone https://github.com/nlitsme/ubidump.git
$ sudo pip install crcmod
$ yay -S python-lzo
$ python ubidump/ubidump.py -s bump 0.00.89_FW_200_Askey.UBI
Nous avons maintenant le système de fichiers dans bump/rootfs_ubifs/
Nous pouvons maintenant poursuivre un peu plus loin dans l'analyse.
En explorant le système de fichiers, nous voyons que l'interface web est gérée par mini_httpd :
$ grep -i -r "mini_httpd"
etc/sniproxy/urlfilter3.sh:ln -sf /usr/sbin/mini_httpd $URLFILTER_WEBD_PATH
etc/sniproxy/urlfilter3.sh:$URLFILTER_WEBD_PATH -d $URLFILTER_WEB_PATH -c "**.cgi" -u admin -S -E /web/mini_httpd.pem -p $webd_https_port
bin/web.sh:#mv /tmp/mini_httpd /usr/sbin
bin/web.sh:killall -9 mini_httpd
bin/web.sh:mini_httpd -d /web -c "STATUSAPI/**.cgi|STATUSAPI/*" -u admin -T "UTF-8" -p 8080
Et nous voyons que mini_httpd dépend d'un fichier .cgi :
$ grep -i -r "status.cgi"
web/factory/mtcmd/mt_info.htm: "url":"/status.cgi",
web/fw-router/app/app.js:.value('apiServiceUrl', '/status.cgi')
**web/js/status.js:var CGI_NAME='status.cgi';**
web/js/status.js: "url":"http://192.168.101.93/STATUSAPI/status.cgi",
web/js/status.js: "url":"http://192.168.101.93/STATUSAPI/status.cgi",
web/js/status.js: "url":http://192.168.101.93/STATUSAPI/status.cgi,
Donc, en utilisant Ghidra, nous pouvons commencer à examiner status.cgi
En sautant beaucoup de détails, la vulnérabilité est décrite ci-dessous.
La première chose à chercher est une méthode main comme celle de cette image :

Nous voyons que setup est appelée. Après un peu de recherche, run_service(...) semble être le cœur de toutes les fonctionnalités.

En cherchant &service_tab, nous voyons que certaines chaînes spécifiques sont liées au code réel exécuté par run_service(...)

Après avoir examiné ces méthodes une par une, je tombe sur usb_remove

En détail :
mountVal = (char *)find_val(httpparams,"mount");
Prend la chaîne de la requête URL directement dans une variable
sprintf((char *)&mountLocation,"/mnt/%s",mountVal);
Crée un chemin complet à partir du paramètre dans la requête URL
mountLocation
mountLocation est directement utilisé dans une commande
Il existe des vérifications pour empêcher l'injection de commande. En particulier :
invalidChars = 0x60273b7c;
Est utilisé pour vérifier certains caractères invalides comme ` ' ; | mais & n'est pas présent dans la liste, donc si le paramètre mount est égal à &ping -c 10 192.168.1.172&, la vérification permettra l'exécution de /statusapi/bin/umount -lf &ping -c 10 192.168.1.172&.
La commande mount échouera mais le ping suivant sera exécuté.
Le patch publié simplifie le code en supprimant les vérifications des caractères spéciaux en vérifiant simplement si le dossier existe.

Le code pour exploiter cette vulnérabilité et activer SSH se trouve dans fastwebEnableSSH.py https://github.com/garis/Fastgate/blob/master/fastwebEnableSSH.py