Exploiter la vulnérabilité SSRF (2/2)

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 :

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 :

SSRFmap Screen beginning

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

Vulnerable test server

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.

Server launched - port 5000

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

Portscan beginning

Portscan - ending

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.

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.


Pour recevoir d’autres articles : cliquez ici

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