Dans l’article précédent, nous avons vu ce qu’est une vulnérabilité SSRF et comment, de manière générale, celle-ci peut être exploitée. Pour cela, nous nous étions placés dans un cadre théorique assez simple, mais différents éléments (soit dus à la nature de la vulnérabilité ou à des implémentations de sécurité) peuvent rendre la tâche plus compliquée.
Dans cet article, nous allons voir diverses méthodes permettant d’aller plus loin. Au programme :
- Différentes méthodes de contournement manuel de filtres ;
- SSRFMap : un outil d’exploitation semi-automatique
Ces points permettent de mettre en évidence le risque potentiel que représente cette vulnérabilité, et en particulier, parce qu’une protection trop simple n’est généralement pas suffisante.
Évasion des filtres
Reprenons le cas d’un paramètre vulnérable au SSRF mentionné dans l’article précédent. Étant donné la nature du paramètre attendu, ici une URL par exemple, il est probable que certaines vérifications (filtres) soient réalisées côté serveur. En voici deux exemples.
Situation 1 : scanner le réseau interne
Nous voulons scanner les IPs du réseau interne du serveur vulnérable. L’application pourrait cependant exiger que la valeur saisie soit un nom de domaine, et non une adresse IP, empêchant une exploitation de type « ?url=http://192.168.1.100 ». Pour cela, le back-office peut par exemple intégrer une vérification (via une regex par exemple) afin de s’assurer du format de la valeur saisie.
Une méthode simple de contournement est d’acheter n’importe quel domaine et d’ajouter l’enregistrement DNS vers l’IP voulu. Par exemple, on pourrait réaliser les enregistrements DNS suivants :
- 1.mon-domaine-de-test.com -> 192.168.1.1
- 2.mon-domaine-de-test.com -> 192.168.1.2
- …
- 254.mon-domaine-de-test.com -> 192.168.1.254
On pourrait ensuite scanner le réseau avec : « ?url=http://100.mon-domaine-de-test.com ».
Bien que fonctionnelle, cette méthode est assez contraignante.
Plus simplement, la plateforme NIP.IO permet de réaliser cela. Il suffit de saisir <IP-CIBLE>.nip.io : le serveur DNS va dynamiquement fournir l’adresse IP saisie comme IP correspondante. Par exemple : http://192.168.1.100.nip.io permettrait d’accéder à l’IP 192.168.1.100.
Si le filtre est un peu plus restrictif (pas de chiffres dans le sous-domaine par exemple), on peut ajouter n’importe quelles valeurs avant l’IP : http://this.bypass-filter.192.168.100.nip.io donne le même résultat que précédemment.
Situation 2 : Cibler le serveur vulnérable
Nous voulons à présent fouiller le serveur vulnérable. Cependant, une vérification est faite sur le paramètre url vulnérable, ne permettant pas de saisir localhost ou 127.0.0.1.
Plusieurs méthodes peuvent permettre de contourner cette restriction et cibler le serveur :
- Utiliser NIP.IO mentionné précédemment : 127.0.0.1.nip.io
- Utiliser d’autres domaines prévus à cet effet : http://spoofed.burpcollaborator.net ou http://localtest.me (enregistrés à l’adresse 127.0.0.1)
- Utiliser des valeurs décimales : http://2130706433/ (= http://127.0.0.1)
- …
Pour aller plus loin
De très nombreuses méthodes permettent ce type de contournement, en fonction du paramètre vulnérable, de l’objectif recherché et des protections mises en place. Le projet PayloadsAllTheThings– et notamment sa section dédiée au SSRF – est une importante ressource pour plus d’informations sur le sujet.
Dans la section suivante, nous allons voir que des outils d’exploitation semi-automatisés permettent de (très fortement) simplifier l’exploitation des vulnérabilités SSRF.
Un outil puissant : SSRFmap
Pour mieux connaitre l’exploitation des vulnérabilités SSRF, SSRFmap est l’outil qu’il vous faut. Développé en Python3 et publié depuis octobre 2018, il est encore activement maintenu [1].
Comme son nom l’indique, SSRFmap a vocation à devenir le SQLmap [2] de la vulnérabilité SSRF. Il permet d’exploiter les paramètres vulnérables d’une requête de manière très simple et efficace.
Voyons à quoi cela ressemble :
Comme on peut le voir, SSRFmap met à dispositions des modules tout prêts. On voit ici les très utiles portscan ainsi que redis, mais il existe en fait toute une liste que l’on peut retrouver sur la page github du projet. A ce jour, les modules disponibles sont les suivants :
Nom | Description |
fastcgi | FastCGI RCE |
redis | Redis RCE |
github | Github Enterprise RCE < 2.8.7 |
zabbix | Zabbix RCE |
mysql | MySQL Command execution |
docker | Docker Infoleaks via API |
smtp | SMTP send mail |
portscan | Scan top 8000 ports for the host |
networkscan | HTTP Ping sweep over the network |
readfiles | Read files such as /etc/passwd |
alibaba | Read files from the provider (e.g: meta-data, user-data) |
aws | Read files from the provider (e.g: meta-data, user-data) |
gce | Read files from the provider (e.g: meta-data, user-data) |
digitalocean | Read files from the provider (e.g: meta-data, user-data) |
socksproxy | SOCKS4 Proxy |
smbhash | Force an SMB authentication via a UNC Path |
tomcat | Bruteforce attack against Tomcat Manager |
custom | Send custom data to a listening service, e.g: netcat |
memcache | Store data inside the memcache instance |
Ces modules sont très utiles pour toute sorte d’exploitation. Notons de plus que le paramètre –level permet d’implémenter automatiquement les techniques de contournement de filtre vu dans la section précédente !
Notons enfin que l’outil met également à disposition des fichiers servants de tests. Ceux-ci comprennent un fichier de configuration pour monter un serveur web (python) vulnérable ainsi que différentes requêtes permettant l’exploitation du serveur via les vulnérabilités SSRF d’exemple. Tout cela se trouve dans le sous-répertoire data/ du projet, et c’est ce que nous allons utiliser pour présenter l’outil.
Quelques tests
Le serveur de test
Tout d’abord, lançons le serveur web vulnérable :
# python3 data/example.py
Attention : le serveur ainsi lancé est volontairement vulnérable. Comme l’indique le message en rouge, ne démarrez jamais celui-ci dans un environnement accessible publiquement ou sur le réseau.
Le serveur est fonctionnel et accessible sur le port 5000 en local.
Scanner les services avec portscan
Test du port scanner sur le paramètre url de la page de test ssrf2 :
python3 ssrfmap.py -r data/request2.txt -p url -m portscan
…
Les requêtes émises par SSRFmap sont de la forme suivante [3] :
POST /ssrf2 HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0
Accept-Encoding: gzip, deflate
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Connection: close
Host: 127.0.0.1:5000
Accept-Language: en-US,en;q=0.5
Referer: http://127.0.0.1:5000/
Content-Type: application/json
Content-Length: 47
Upgrade-Insecure-Requests: 1
{"userId": "1", "url": "http://127.0.0.1:993/"}
Le temps de réponse détermine la présence ou non du service.
Le paramètre level et les bypass
Observons maintenant ce qu’il se passe lorsque l’on joue sur le paramètre –level.
Bien que les résultats soient les mêmes dans cet exemple, le module utilise cette fois des méthodes de contournement de filtres/protections.
Toujours avec le module portscan, cette fois avec le level à 2 :
POST /ssrf2 HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0
Accept-Encoding: gzip, deflate
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Connection: close
Host: 127.0.0.1:5000
Accept-Language: en-US,en;q=0.5
Referer: http://127.0.0.1:5000/
Content-Type: application/json
Content-Length: 45
Upgrade-Insecure-Requests: 1
{"userId": "1", "url": "http://127.0.1:513/"}
Il s’agit ici d’un contournement classique, consistant à remplacer 127.0.0.1 par 127.0.1
D’autres level peuvent par exemple utiliser le contournement suivant :
« url »: « http://localtest$google.me:1059/ »
ce qui équivaut, en plus de le rendre plus difficile à lire, à l’utilisation de localtest.me évoqué dans la section précédente.
N’hésitez pas à tester les différents contournements que propose SSRFmap, certains peuvent se révéler efficaces dans des situations qui semblent pourtant sécurisées.
Autres modules
Un mot sur les autres modules disponibles :
networkscan permet de chercher si d’autres services web sont présents sur le réseau interne du serveur vulnérable.
readfiles télécharge les fichiers système sensibles (/etc/passwd, /etc/shadow, …) sur le serveur vulnérable.
Astuce : pour télécharger d’autres fichiers, il est possible de modifier le module dans modules/readfiles.py et ajouter les fichiers correspondants dans la variable files.
De la même manière, alibaba, aws, gce et digitalocean permettent de télécharger des fichiers spécifiques en fonction du type de serveur.
Certains modules (redis, github, zabbix, mysql, …) permettent d’exploiter des services vulnérables à partir de vulnérabilités connues afin d’obtenir un contrôle en ligne de commande au serveur. Dans ce cas, les paramètres -lhost et -lport permettent de spécifier l’adresse IP et le port sur lequel la machine attaquante va être contactée par la victime.
Le module ProxySocks permet d’utiliser le serveur vulnérable comme proxy[4] de manière à pouvoir utiliser son navigateur (ou tout autre programme orienté web) comme si nous étions dans le réseau du serveur exploité. Ce module ne semble cependant pas totalement fonctionnel actuellement.
En conclusion, les filtres mis en place pour empêcher les exploitations SSRF peuvent être contournés de diverses manières. De plus, des outils semi-automatisés peuvent permettre une exploitation relativement rapide et efficace.
Ressources
[1] Au moment de l’écriture de ce poste, le 23/07/2019, le dernier commit datait de 11 jours.
[2] SQLmap est un outil permettant l’exploitation de vulnérabilités de type Injection SQL. Il est incontournable dans son domaine.
[3] Afin d’obtenir les requêtes, le mode VERBOSE ne semblant pas fonctionnel durant les tests, nous avons utilisé un Proxy HTTP (burp) et paramétré ProxyChains afin que les requêtes d’SSRFmap soient dirigées vers celui-ci.
[4] Comme le proposait l’outil SSRF Proxy, qui n’est plus maintenu depuis 2 ans.
https://portswigger.net/web-security/ssrf