Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
react2shell — Un análisis de CVE-2025-55182 y CVE-2025-66478 -- las vulnerabilidades detrás de React2Shell. Herramientas, información técnica, etc. | Kitploit
Herramientas/GitHubGitHub/freeqaz/react2shell
Análisis Dinámico (Sandboxing)Análisis de VulnerabilidadesAnálisis de CódigoExplotaciónExplotación de Aplicaciones WebPruebas de PenetraciónPapers e InvestigaciónAprendizaje y EducaciónDesarrollo de Payloads
GitHubfreeqaz/react2shell

react2shell

Un análisis de CVE-2025-55182 y CVE-2025-66478 -- las vulnerabilidades detrás de React2Shell. Herramientas, información técnica, etc.

6818hace 8 mesesRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir
Ver Repositorio

React2Shell: RCE 0-day en React Server Components

CVE-2025-55182 (React) y CVE-2025-66478 (Next.js)

Este repositorio contiene código de exploit únicamente para pruebas de seguridad autorizadas y fines educativos.

Ver también: Múltiples investigadores han publicado análisis de esta vulnerabilidad. Consulta la sección Referencias para obtener perspectivas adicionales, técnicas de explotación y métodos de detección.

¿Qué es?

El miércoles 3 de diciembre de 2025 se reveló públicamente una vulnerabilidad crítica de ejecución remota de código en React Server Components. El fallo, bautizado como «React2Shell», permite a un atacante no autenticado ejecutar código arbitrario en cualquier servidor que ejecute versiones vulnerables de React RSC o Next.js App Router mediante el envío de una única petición HTTP.

Dado lo omnipresente que se ha vuelto Next.js - impulsa una parte significativa de la web moderna - el impacto de esta vulnerabilidad es grave. Cualquier aplicación Next.js que use App Router (el valor predeterminado para proyectos nuevos desde Next.js 13) con RSC habilitado es vulnerable. Sin configuración especial. Sin endpoints específicos. Solo una petición POST a cualquier ruta.

La vulnerabilidad reside en el protocolo «Flight» de React, el formato de serialización utilizado para transferir datos entre servidor y cliente en React Server Components. La ausencia de una comprobación de hasOwnProperty durante la deserialización permite recorrer la cadena de prototipos, llegando en última instancia al constructor Function de JavaScript para ejecutar código controlado por el atacante.

El fallo existe en los paquetes react-server-dom-webpack, react-server-dom-turbopack y react-server-dom-parcel de React. Next.js, como principal consumidor de RSC, hereda la vulnerabilidad a través de su App Router.

¿Quién se ve afectado?

Muchos servicios son potencialmente vulnerables. Next.js es uno de los frameworks de React más populares, utilizado por empresas de todos los tamaños - desde startups hasta grandes corporaciones. App Router con React Server Components ha sido la arquitectura predeterminada para proyectos nuevos de Next.js desde la versión 13, lo que significa que la mayoría de los despliegues modernos de Next.js están afectados.

Cualquier aplicación que use:

  • React Server Components con paquetes react-server-dom-* vulnerables (19.0.0 - 19.2.0)
  • Next.js App Router versiones 15.x (anteriores a 15.0.5) y 16.x (anteriores a 16.0.7)

Esto incluye despliegues en producción en Vercel, AWS, infraestructura autoalojada y cualquier otro lugar donde se ejecuten aplicaciones Next.js App Router.

No afectados:

  • Aplicaciones Next.js Pages Router (sin RSC)
  • Versiones estables de Next.js 13.x y 14.x
  • Aplicaciones que usan solo renderizado en cliente de React
  • Despliegues en Edge Runtime (no hay process.mainModule disponible)

Versiones afectadas

React Server Components

PaqueteVulnerableParcheada

Next.js

Mitigación

Actualiza de inmediato. No hay soluciones alternativas.

Para aplicaciones Next.js:

root@kitploit:~
npm install next@latest
# or
pnpm update next

Para uso directo de React RSC:

root@kitploit:~
npm install react-server-dom-webpack@latest

Verifica tus versiones instaladas:

root@kitploit:~
npm ls next react-server-dom-webpack react-server-dom-turbopack

Cómo funciona el exploit

Requisitos del exploit

  1. Un servidor que ejecute React Server Components vulnerable (mediante Next.js App Router o uso directo de RSC)
  2. Acceso de red para enviar una petición HTTP POST
  3. Eso es todo. Sin autenticación. Sin endpoint específico. Cualquier ruta funciona.

El ataque

Se han descubierto múltiples vectores de ataque para esta vulnerabilidad. El más común - y el que funciona sin ningún requisito previo - utiliza la contaminación de prototipos a través del sistema de referencias del protocolo Flight de React.

El exploit envía una petición POST multipart manipulada con una cabecera Next-Action. El payload abusa del sistema de referencias para:

  1. Recorrer la cadena de prototipos mediante $1:__proto__:then
  2. Construir un objeto «chunk» falso que imite la clase Chunk interna de React
  3. Engañar al deserializador para que llame al constructor Function de JavaScript
  4. Ejecutar código arbitrario cuando la función resultante se invoca como un thenable de Promise
root@kitploit:~
POST / HTTP/1.1
Host: target.com
Content-Type: multipart/form-data; boundary=----Boundary
Next-Action: x

------Boundary
Content-Disposition: form-data; name="0"

{"then":"$1:__proto__:then","status":"resolved_model","value":"{...}","_response":{...}}
------Boundary
Content-Disposition: form-data; name="1"

"$@0"
------Boundary--

El código se ejecuta durante la deserialización, antes de que se realice cualquier validación del ID de acción. Esto significa que cualquier valor de la cabecera Next-Action activa la ruta de código vulnerable - no se requiere un ID de acción válido.

Existen otros vectores de ataque, incluidas las referencias a funciones $F y los gadgets de módulo directos. Estos suelen requerir un ID de acción válido. Consulta Vectores de ataque alternativos para más detalles.

La causa raíz

El protocolo Flight de React resuelve referencias como $1:path:to:value dividiendo por dos puntos y recorriendo el objeto:

root@kitploit:~
// ReactFlightReplyServer.js - getOutlinedModel()
for (let i = 1; i < path.length; i++) {
  value = value[path[i]];  // No hasOwnProperty check!
}

La ironía: En la parte superior de este mismo archivo, línea 35:

root@kitploit:~
import hasOwnProperty from 'shared/hasOwnProperty';

La protección se importó. Estaba disponible. Simplemente no se usó en el único bucle donde más importaba.

Esta única comprobación ausente permite que $1:__proto__:then recorra desde un objeto chunk, a través de la cadena de prototipos, hasta Chunk.prototype.then - una función que procesa objetos similares a Promise. Al crear un chunk falso con las propiedades adecuadas, controlamos qué código se ejecuta.

Reproducción local

Clona el servidor de pruebas vulnerable:

root@kitploit:~
git clone https://github.com/freeqaz/react2shell
cd react2shell/vulnerable-next-server
pnpm install
pnpm dev

En otra terminal:

root@kitploit:~
./detect.sh http://localhost:3443

Un servidor vulnerable devuelve HTTP 500 con E{"digest" en el cuerpo de la respuesta. Para demostrar RCE:

root@kitploit:~
./exploit-redirect.sh http://localhost:3443 "id"

La salida del comando aparece en la respuesta. Para exploración interactiva:

root@kitploit:~
./shell.sh http://localhost:3443

Contenido de este repositorio

Servidor de pruebas vulnerable

El directorio vulnerable-next-server/ contiene una aplicación Next.js 16.0.6 + React 19.2.0 preconfigurada para pruebas locales seguras. Se ejecuta en el puerto 3443 por defecto. Es una configuración mínima de App Router que demuestra que las configuraciones predeterminadas son vulnerables.

Scripts de exploit

Desarrollamos múltiples variantes de exploit para manejar diferentes escenarios:

Nota sobre producción: React elimina los mensajes de error en las compilaciones de producción, lo que rompe el método throw. Solo exploit-redirect.sh captura de forma fiable la salida de comandos en producción sin requisitos previos. La URL de redirección se almacena en la propiedad digest del error (metadatos), que no se sanea - a diferencia de message, que se convierte únicamente en {digest: "..."}.

Scripts de utilidad:

  • detect.sh - Sonda de vulnerabilidad no destructiva (sin ejecución de código)
  • enumerate-actions.sh - Descubre IDs de Server Action válidos en el HTML del objetivo
  • exfil-file.sh - Exfiltración de archivos por fragmentos (maneja automáticamente archivos grandes)
  • shell.sh - Pseudo-shell interactiva sobre RCE

El método de redirección es el recomendado porque funciona en producción, no requiere requisitos previos y devuelve la salida del comando directamente. Funciona lanzando un error NEXT_REDIRECT especialmente manipulado - la salida se codifica en base64 dentro de la URL de redirección y se devuelve en la cabecera x-action-redirect.

Para un uso detallado de cada script, consulta USAGE.md.

Cómo detectar servidores vulnerables

Detección rápida

root@kitploit:~
./detect.sh https://target.com

Esto envía una sonda mínima que activa la ruta de código vulnerable sin ejecutar código arbitrario.

Respuesta de un servidor vulnerable:

  • Estado HTTP: 500
  • Content-Type: text/x-component
  • El cuerpo contiene: E{"digest"

Servidor parcheado o sin RSC: Devuelve 404, un formato de error diferente o ninguna respuesta del protocolo Flight.

Detección manual

root@kitploit:~
curl -s -o /dev/null -w "%{http_code}" -X POST https://target.com \
  -H "Next-Action: x" \
  -H "Content-Type: multipart/form-data; boundary=----Boundary" \
  --data-binary $'------Boundary\r\nContent-Disposition: form-data; name="0"\r\n\r\n["$1:a:a"]\r\n------Boundary\r\nContent-Disposition: form-data; name="1"\r\n\r\n{}\r\n------Boundary--'

Esta sonda referencia una propiedad inexistente en un objeto vacío. Los servidores vulnerables se bloquean al intentar acceder a {}.a.a y devuelven 500. Los servidores parcheados tienen una protección hasOwnProperty que evita el bloqueo.

Identificación de Next.js App Router

Busca estos indicadores:

  • Payload RSC en el HTML: etiquetas <script> que contienen datos del protocolo Flight (0:, 1:, etc.)
  • Cabeceras x-nextjs-cache o x-nextjs-matched-path
  • Rutas de recursos estáticos /_next/
  • IDs de Server Action en el HTML: patrones $ACTION_ID_ en campos de formulario ocultos

Análisis técnico en profundidad

El flujo del ataque

El siguiente diagrama ilustra cómo una única petición HTTP logra la ejecución remota de código:

root@kitploit:~
sequenceDiagram
    participant A as Attacker
    participant N as Next.js
    participant F as Flight Parser
    participant JS as JS Engine

    A->>N: POST with Next-Action header + malicious payload
    N->>F: Parse multipart form data
    F->>JS: await getRoot - returns chunk as thenable

    rect rgb(80, 20, 20)
        Note over F,JS: VULNERABILITY - No hasOwnProperty check
        JS->>F: chunk.then parses $1:__proto__:then
        F-->>F: Traverses to Chunk.prototype.then
    end

    F->>JS: resolve(attackerObject)
    Note over JS: JS Promise spec: resolve(thenable)<br/>calls thenable.then()
    JS->>F: fakeChunk.then() with attacker's _response

    rect rgb(80, 20, 20)
        Note over F,JS: EXPLOITATION - Attacker controls _response
        F->>F: $B0 → _formData.get(_prefix + "0")
        Note over F: _formData.get = Function constructor<br/>_prefix = malicious code string
        F->>JS: Function(code) invoked as thenable
    end

    Note over JS: RCE - execSync() runs

    rect rgb(20, 60, 20)
        Note over A,JS: OUTPUT EXFILTRATION (redirect method)
        JS-->>F: throw NEXT_REDIRECT with base64(output)
        F-->>N: Error propagates up
        N-->>A: HTTP 303 + x-action-redirect header
    end

El protocolo Flight

React Server Components usa un formato de serialización personalizado llamado «Flight» para transmitir árboles de componentes del servidor al cliente. Utiliza códigos de prefijo para diferentes tipos de valores:

  • $1, $2, ... - Referencias a otros chunks por ID
  • $@0 - Referencia al objeto chunk sin procesar (devuelve el chunk en sí, no su valor)
  • $B0 - Referencia a blob (activa _formData.get(_prefix + id))
  • $1:path:to:prop - Recorre una ruta sobre el valor de un chunk referenciado

La vulnerabilidad explota la combinación de $@ (referencia sin procesar) y rutas delimitadas por dos puntos para acceder a __proto__.

La cadena de ataque completa

Fase 1: Procesamiento de la petición

  1. El POST con la cabecera Next-Action activa el manejo de acciones RSC
  2. Busboy analiza los campos del formulario multipart y los almacena como chunks
  3. await getRoot(response) devuelve el chunk 0 como un thenable

Fase 2: Recorrido de prototipos

  1. El chunk tiene un método then - la especificación de Promise de JS llama a thenable.then(resolve, reject)
  2. Nuestro payload se analiza; $1:__proto__:then se resuelve a Chunk.prototype.then
  3. Se crea un objeto chunk falso con then, status: "resolved_model" y _response

Fase 3: Ejecución de código

  1. resolve(ourObject) activa otra llamada a then() (especificación de thenable de JS)
  2. Chunk.prototype.then se ejecuta usando nuestro objeto _response controlado
  3. $B0 activa _formData.get(_prefix + "0") - ambos controlados por el atacante
  4. La Function construida se invoca como thenable → RCE

Fase 4: Exfiltración de la salida (opcional, método de redirección)

  1. El payload lanza un error NEXT_REDIRECT con la salida del comando codificada en base64
  2. Next.js captura la redirección y establece la cabecera x-action-redirect antes de la validación de URL
  3. Se devuelve HTTP 303 al atacante con la salida en la cabecera

Estrategias de captura de salida

La Function construida se invoca como un thenable: fn(resolve, reject). Cómo manejemos esto determina si recuperamos la salida:

Recomendado: Redirección. Funciona en producción, sin requisitos previos, salida en la cabecera x-action-redirect.

El enfoque ciego se cuelga porque la Promise nunca se resuelve - await bloquea para siempre. Esto es útil para escenarios de dispara y olvida (reverse shells, exfiltración fuera de banda mediante curl).

Vectores de ataque alternativos

La vulnerabilidad principal se ha explotado mediante tres clases de ataque distintas. Este repositorio usa el primer enfoque; otros PoC demuestran las alternativas:

Por qué la contaminación de prototipos no requiere un ID de acción: El análisis del formulario multipart alimenta los chunks al deserializador Flight de inmediato. El RCE ocurre en getOutlinedModel() durante la resolución de la referencia al chunk - antes de que Next.js valide el ID de acción. Las peticiones codificadas en URL validan primero el ID de acción (ruta de código diferente en action-handler.ts:768).

Por qué la referencia $F requiere un ID de acción: La referencia $F activa loadServerReference(), que realiza una búsqueda en el manifiesto. Si la acción no existe, la petición falla antes de la ejecución de código.

Para un análisis detallado de todas las implementaciones de PoC y sus ventajas e inconvenientes, consulta external-pocs/COMPARISON.md.

Producción vs. Desarrollo

React elimina los detalles de error en las compilaciones de producción. Esto afecta a la exfiltración basada en throw:

Desarrollo:

root@kitploit:~
{"digest":"...","name":"Error","message":"uid=501(free)...","stack":[...]}

Producción:

root@kitploit:~
{"digest":"..."}

El método de redirección evita esto porque la URL de redirección se almacena en la propiedad digest, no en message. La cabecera se establece de forma incondicional antes de la validación de URL, por lo que incluso las URLs inválidas reciben la cabecera.

Agradecimientos

La idea clave de la explotación - usar referencias $@ a chunks sin procesar para crear un chunk falso autorreferencial - se atribuye a maple3142. La metodología de detección referenciada aquí proviene de Searchlight Cyber / Assetnote.

Referencias

Divulgaciones oficiales:

  • CVE-2025-55182 - RCE en React Server Components
  • CVE-2025-66478 - Impacto aguas abajo en Next.js
  • Aviso de seguridad de React - Divulgación oficial de React

Investigación de la comunidad:

Para una comparación detallada de todas las implementaciones de PoC, consulta external-pocs/COMPARISON.md.

Antecedentes:

  • Protocolo Flight de React - Comprender la serialización de RSC

Licencia

El código está bajo la Licencia MIT. La documentación (archivos *.md) está bajo CC-BY-SA 4.0.

Descargar herramienta
react-server-dom-webpack
19.0.0, 19.1.0, 19.1.1, 19.2.0
19.0.1, 19.1.2, 19.2.1+
react-server-dom-turbopack19.0.0, 19.1.0, 19.1.1, 19.2.019.0.1, 19.1.2, 19.2.1+
react-server-dom-parcel19.0.0, 19.1.0, 19.1.1, 19.2.019.0.1, 19.1.2, 19.2.1+
Línea de versiónVulnerableParcheada
15.0.x< 15.0.515.0.5+
15.1.x< 15.1.915.1.9+
15.2.x< 15.2.615.2.6+
15.3.x< 15.3.615.3.6+
15.4.x< 15.4.815.4.8+
15.5.x< 15.5.715.5.7+
16.0.x< 16.0.716.0.7+
ScriptHTTPSalidaProducciónNotas
exploit-redirect.sh303Cabecera x-action-redirectSíRecomendado. Sin requisitos previos.
exploit-throw.sh500Cuerpo de la respuesta de errorNoSolo modo dev (los errores se sanean en producción).
exploit-blind.sh200Solo en el servidorSíDispara y olvida. Úsalo para exfiltración OOB.
exploit-urlencoded.sh303Cabecera x-action-redirectSíFirma WAF diferente. Requiere ID de acción.
exploit-reflect.sh200Cuerpo de la respuestaSíEl más sigiloso. Requiere ID de acción.
EstrategiaSufijo del payloadCómo funciona
CiegoexecSync('CMD');0Ejecuta pero nunca se resuelve - la conexión se cuelga, sin salida
Lanzarthrow execSync('CMD').toString()Rechaza la Promise, salida en el cuerpo del error (solo modo dev)
Redirecciónthrow {digest:'NEXT_REDIRECT;...;'+b64(output)}Abusa del manejo de redirecciones de Next.js, salida en la cabecera
Reflejoarguments[0](https://github.com/freeqaz/react2shell/blob/HEAD/%5BexecSync(%27CMD%27).toString()])Resuelve la Promise con la salida como argumento de la acción (requiere ID de acción válido)
Clase de ataqueMecanismoID de acción requeridoEjemplo de PoC
Contaminación de prototiposRecorrido $1:__proto__:then hasta Chunk.prototypeNoreact2shell, lachlan2k, joe-desimone
Referencia a función $F$F1 + action#constructor para llegar a FunctionSíshellinteractive
Gadget de móduloSintaxis module#export (p. ej., child_process#execSync)VaríaInvestigación de ejpir
AutorContribuciónRuta de ataqueCaracterísticas destacadas
lachlan2kDescubridor originalContaminación de prototiposEncadenamiento con Array.map, estructura de 5 chunks, soporte para Waku
ejpirInvestigación de gadgetsTodas las rutasCatálogo de gadgets de módulo, ataques de persistencia, ruta data URI
joe-desimoneHerramientas en PythonContaminación de prototiposAsistente de reverse shell, exfiltración por callback, detección de timeouts
labubusDest / MrR0b0t19Shell interactivaReferencia a función $FREPL de Python, subida/descarga de archivos, suite de pruebas integrada
Searchlight CyberMétodos de detección—Metodología de detección de alta fidelidad, firmas de WAF