
Breve discusión sobre el análisis de la vulnerabilidad RCE en React Server Components
Estos días se ha hablado mucho de una vulnerabilidad RCE por deserialización en React, con una puntuación CVSS oficial de 10.0, igual que Log4j en su momento. No pocos rumores la calificaban como el Log4j del frontend moderno, causando pánico entre desarrolladores de muchas empresas. Así que, al despertar, todos estaban revisando documentos y aplicando parches... Al mismo tiempo, también circularon dudas en Internet; algunos probaron la vulnerabilidad y descubrieron que no es tan grave como se decía, sino que requiere ciertas condiciones para su explotación. Por eso, decidí dedicar tiempo a investigar a fondo esta vulnerabilidad.
react-server-dom-webpack < 19.2.0, react-server-dom-turbopack < 19.2.0La causa de esta vulnerabilidad es la siguiente: en [email protected], la función clave del lado del servidor para analizar Server Actions es requireModule (seudocódigo):
function requireModule(metadata) {
var moduleExports = __webpack_require__(metadata[0]);
// ...
return "*" === metadata[2]
? moduleExports
: "" === metadata[2]
? moduleExports.__esModule
? moduleExports.default
: moduleExports
: moduleExports[metadata[2]]; // ← Punto vulnerable
}
El núcleo del problema está en moduleExports[metadata[2]]; no se valida metadata[2], lo que permite al atacante acceder no solo a las propiedades exportadas del módulo, sino también a propiedades de la cadena de prototipos (como constructor, __proto__, etc.). Cuando el atacante construye metadata[0] (por ejemplo, apuntándolo a vm), puede construir metadata[2] para exportar métodos peligrosos del módulo especificado, como vm.runInThisContext, logrando así la explotación.
En mi análisis, me basé en el entorno de prueba y la explotación proporcionados por ejpir, usando como ejemplo el gadget vm_runInThisContext para ejecución de código. El proceso es el siguiente (¡nota: en un entorno real, la explotación puede diferir!).
Primero, después de enviar una solicitud con el payload, se coloca un punto de interrupción en el lugar donde se recibe la solicitud:


Luego, el programa llega a const formData = parseMultipart(buffer, boundaryMatch[1]);; se ingresa a parseMultipart:

parseMultipart extrae los datos del cuerpo de la solicitud y los devuelve a formData:

Se ingresa a const actionFn = await decodeAction(formData, serverManifest); punto donde ocurre la vulnerabilidad:

Se ingresa a loadServerReference:


Ahora llegamos al código central donde se produce la vulnerabilidad: requireModule; ingresamos:


Devuelve el valor id con # como separador entre módulo y método, y el valor bound como argumento del método:




Se ingresa a actionFn para ejecutar el payload final:



¡Con esto termina la explotación!
Esta vulnerabilidad se debe esencialmente a una validación de entrada deficiente, similar a Log4j y fastjson. En mi prueba usé vm_runInThisContext, pero en realidad hay múltiples gadgets explotables, como:
vm#runInThisContextvm#runInNewContextchild_process#execSyncchild_process#execFileSyncchild_process#spawnSyncfs#readFileSyncfs#writeFileSync#constructor#__proto__#prototypeUn atacante puede usar esta vulnerabilidad para lograr:
vm#runInThisContext o child_process#execSync para ejecutar comandos arbitrarios del sistema.fs#readFileSync y fs#writeFileSync para leer/escribir archivos arbitrarios..bashrc, sobrescribir archivos de la aplicación, etc..env, claves privadas, credenciales de bases de datos, etc.).Por lo tanto, se pueden proponer las siguientes medidas defensivas:
Se pueden configurar reglas en el WAF para bloquear estos campos peligrosos y así interceptar ataques maliciosos a tiempo. También se puede hacer coincidencia en Nginx, por ejemplo:
# Configuración de ejemplo en Nginx
location /formaction {
# Bloquear solicitudes que contengan referencias a módulos peligrosos
if ($request_body ~* "(vm#|child_process#|fs#|module#)") {
return 403;
}
# Bloquear intentos de contaminación de la cadena de prototipos
if ($request_body ~* "(#constructor|#__proto__|#prototype)") {
return 403;
}
}
El equipo oficial ya ha publicado parches de seguridad. ¡Actualice inmediatamente a una versión segura!:
# Actualizar react-server-dom-webpack
npm install react-server-dom-webpack@>=19.2.0
# Actualizar react-server-dom-turbopack
npm install react-server-dom-turbopack@>=19.2.0
# Usuarios de Next.js
npm install next@>=15.0.5
Versiones corregidas:
react-server-dom-webpack: >= 19.2.0react-server-dom-turbopack: >= 19.2.0next.js: >= 15.0.5