Writeup de Hack The Box para el Challenge retirado ReactOOPS - Solución completa y guía educativa sobre CVE-2025-55182/CVE-2025-66478 (React2Shell RCE). Incluye análisis detallado de vulnerabilidades, técnicas de explotación y materiales de aprendizaje para el equipo.
Autor: TheStingR - Equipo ISP1337Hackers
Desafío: ReactOOPS (Web)
Plataforma: Hack The Box
Dificultad: Muy Fácil - RETIRADO
Fecha de resolución: 13 de diciembre de 2025
ReactOOPS es un desafío web que explota CVE-2025-55182 / CVE-2025-66478, una vulnerabilidad crítica de ejecución remota de código no autenticada en React Server Components y Next.js App Router.
Hallazgos Clave:
hasOwnProperty en la deserialización del protocolo FlightEl desafío presenta una aplicación Next.js pulida que ejecuta la interfaz de asistente de NexusAI. La aplicación parece manejar la entrada del usuario a través de React Server Components, pero fallos sutiles en la capa reactiva insinúan vulnerabilidades subyacentes.
La aplicación utiliza:
El protocolo Flight es el formato de serialización propietario de React para transmitir datos entre servidor y cliente en arquitecturas de Server Components. Utiliza referencias como:
$1 - Referencia al objeto en la posición 1$1:path:to:value - Recorrido de rutas de propiedadesCódigo Vulnerable en ReactFlightReplyServer.js de React:
// Line ~450: getOutlinedModel function
function getOutlinedModel(response, id) {
let chunk = chunks.get(id);
const value = chunk.value;
// Process references like "$1:path:to:value"
if (reference.startsWith('$')) {
const refId = parseInt(reference.slice(1).split(':')[0]);
const path = reference.slice(1).split(':').slice(1);
let obj = chunks.get(refId).value;
// VULNERABLE LOOP - NO hasOwnProperty CHECK!
for (let i = 0; i < path.length; i++) {
obj = obj[path[i]]; // ← Allows prototype chain access
}
return obj;
}
}
La Versión Segura (Lo Que Debería Ser):
for (let i = 0; i < path.length; i++) {
if (Object.prototype.hasOwnProperty.call(obj, path[i])) {
obj = obj[path[i]];
} else {
throw new Error('Invalid property access');
}
}
Sin la comprobación hasOwnProperty, un atacante puede recorrer:
myObject[__proto__][then] → Chunk.prototype.then
myObject[__proto__][constructor] → Function
myObject[__proto__][constructor][prototype] → function.prototype
Paso 1: Enviar la referencia "$1:__proto__:then"
│
├─ Acceder a myChunk[__proto__]
└─ Luego acceder a [then] en el prototipo
Paso 2: Crear un objeto falso tipo Promise
│
└─ { then: maliciousFunction }
Paso 3: React ejecuta await sobre este objeto
│
├─ Invoca el método .then()
└─ Ejecuta la función del atacante
Paso 4: Ejecución de Código Arbitrario
│
└─ El código se ejecuta en el contexto del servidor como root
La vulnerabilidad existe antes de la validación de Next-Action:
Flujo de Procesamiento de la Petición:
├─ Parsear los datos del formulario multipart
├─ Deserializar el protocolo Flight ← EL RCE OCURRE AQUÍ
│ └─ Procesar referencias y objetos
│ └─ ¡Sin comprobación hasOwnProperty!
├─ Extraer la cabecera Next-Action
├─ Validar el ID de acción ← Esto viene DESPUÉS
└─ Ejecutar el manejador de acción
Al provocar el RCE durante la deserialización, los atacantes omiten todas las comprobaciones de seguridad a nivel de acción.
# Test if service is responding
curl -v http://<IP>:PORT/
Esperado: Aplicación Next.js sirviendo HTML con RSC habilitado
Busca indicadores:
next-<script type="text/x-component">.nextEl indicador más fiable es intentar un ataque de contaminación de prototipos y observar la respuesta:
# Non-destructive detection payload
# Sends: ["$1:a:a"] referencing {}
# Vulnerable: {}.a.a throws → HTTP 500 + E{"digest"
# Patched: hasOwnProperty prevents access → no crash
# Navigate to challenge directory
cd /Challenges/ReactOOPS
# Clone react2shell exploit framework
git clone https://github.com/freeqaz/react2shell.git
# Verify all scripts are executable
chmod +x react2shell/*.sh
Objetivo: Confirmar que el servidor es vulnerable sin causar daños
cd react2shell
# Run the detection probe
./detect.sh http://<IP>:PORT
Qué Hace:
Next-Action: x["$1:a:a"] referenciando el objeto vacío {}{}.a.aSalida Esperada:
[*] React2Shell Detection Probe (CVE-2025-55182 / CVE-2025-66478)
[*] Target: http://<IP>:PORT
[*] HTTP Status: 500
[!] VULNERABLE - Server returned 500 with E{"digest" pattern
[*] Response body:
0:{\"a\":\"$@1\",\"f\":\"\",\"b\":\"s8I48LfEDhqpCdFN5-HbU\"}
1:E{\"digest\":\"346246470\"}
[!] This server is running a vulnerable version of React RSC / Next.js