Skip to content
KitploitKITPLOIT
FerramentasBlog
Log in
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.

FeedsContatoPrivacidade© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2026-56848 — PoC de exploit para CVE-2026-56848, um heap-use-after-free no Node.js HTTP/2 que permite DoS remoto não autenticado. Inclui gatilho de raw-socket, instruções de build com ASan e alvo baseado em Docker. | Kitploit
Ferramentas/GitHubGitHub/open-flaw/cve-2026-56848
Análise de VulnerabilidadesAnálise Dinâmica de Código (DAST)ExploraçãoSegurança WebSegurança de Rede
GitHubopen-flaw/cve-2026-56848

CVE-2026-56848

PoC de exploit para CVE-2026-56848, um heap-use-after-free no Node.js HTTP/2 que permite DoS remoto não autenticado. Inclui gatilho de raw-socket, instruções de build com ASan e alvo baseado em Docker.

Ver Repositório
41há 1 mêsAinda 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

CVE-2026-56848

Descrição do NVD

Uma falha no tratamento de HTTP/2 no Node.js permite que nghttp2_session_mem_send() seja chamado de forma reentrante enquanto nghttp2_session_mem_recv() está em execução, resultando em um heap-use-after-free.

Esta vulnerabilidade afeta Node.js 26.x, 24.x e 22.x.

(Nota: as versões mencionadas na descrição se aplicam apenas ao pacote upstream do nodejs e não ao pacote nodejs distribuído pelo Alpine.

Linha de versãoVulnerávelCorrigida
22.x (LTS)≤ 22.23.122.23.2
24.x (LTS)≤ 24.18.024.18.1
26.x≤ 26.5.026.5.1
  • Gravidade: Alta (CVSS 7.5, AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H — DoS remoto, não autenticado, via corrupção de heap)
  • Reportado por: hahahkim (HackerOne #3833629)
  • Corrigido por: Matteo Collina (mcollina)
  • Commit da correção (v22): daa6d25e3dce — "http2: defer rst stream while in scope" (nodejs-private/node-private#921)
  • Divulgado: lançamentos de segurança do Node.js, 2026-07-29

Causa Raiz

Http2Stream::SubmitRstStream() em src/node_http2.cc força uma limpeza dos dados pendentes de saída antes de enfileirar o RST_STREAM:```cpp void Http2Stream::SubmitRstStream(const uint32_t code) { CHECK(!this->is_destroyed()); code_ = code;

// (NGHTTP2_CANCEL is deferred — fix for an older double-free) if (session_->is_in_scope() && is_stream_cancel(code)) { session_->AddPendingRstStream(id_); return; }

// If possible, force a purge of any currently pending data here to make // sure it is sent before closing the stream. ... if (session_->SendPendingData() != 0) { // ← RE-ENTRANT mem_send() session_->AddPendingRstStream(id_); return; }

FlushRstStream(); }

`SendPendingData()` chama `nghttp2_session_mem_send()` ([node_http2.cc:1970](https://github.com/nodejs/node/blob/v22.23.1/src/node_http2.cc#L1970)). Sua única proteção de reentrância é `is_sending()`, que protege contra *envio-durante-envio* (uma escrita já em andamento) — **não contra envio-durante-recepção**. Quando `SubmitRstStream()` executa de dentro de uma cadeia de callbacks de `nghttp2_session_mem_recv()` ("em escopo"), a purga executa `mem_send()` de forma reentrante.

O `mem_send()` reentrante envia frames cujo processamento no lado do envio derruba streams (`nghttp2_session_close_stream_on_goaway()` → `on_stream_close` → `Http2Stream::Destroy()` → liberação do `Http2Stream` C++). O stream liberado ainda é referenciado pela operação de recepção em andamento: o próprio `SubmitRstStream()` continua executando no `this` liberado (seu `FlushRstStream()` final lê `is_destroyed()`), e o `mem_recv()` externo continua percorrendo o estado de frames/headers do stream fechado → **heap-use-after-free**.

### Cadeia de gatilho (tudo dentro de uma única chamada a `nghttp2_session_mem_recv()`)

1. O atacante envia `GOAWAY(lastStreamID=0, NO_ERROR)` imediatamente seguido por frames `HEADERS` para novos streams (3, 5, 7, …) em um único segmento TCP.
2. O `mem_recv()` do servidor processa GOAWAY → o `session.close()` do JS → `session.closed = true` e um GOAWAY de saída é **submetido mas ainda não enviado**.
3. O nghttp2 só recusa novos streams de entrada depois que o GOAWAY é de fato *enviado* (`session_allow_incoming_new_stream()` verifica `TERM_ON_SEND | SENT`, não `SUBMITTED`), então `HEADERS(3)` ainda é aceito.
4. O `onSessionHeaders()` do JS vê um novo stream em uma sessão fechada e o recusa: `handle.rstStream(NGHTTP2_REFUSED_STREAM)` (lib/internal/http2/core.js).
5. O `SubmitRstStream(NGHTTP2_REFUSED_STREAM)` do C++ executa em escopo (dentro de `mem_recv`), `REFUSED_STREAM ≠ CANCEL` → cai em `SendPendingData()` → **`nghttp2_session_mem_send()` reentrante**.
6. O envio reentrante descarrega o GOAWAY de saída; o processamento do GOAWAY no lado do envio do nghttp2 fecha streams de entrada com id > 1 (`session_close_stream_on_goaway(..., NGHTTP2_REFUSED_STREAM)`), disparando `on_stream_close` → `Http2Stream::Destroy()` libera o objeto C++ do stream para o stream 3.
7. A execução retorna para `SubmitRstStream()` no objeto liberado (`FlushRstStream()`), e o `mem_recv()` externo retoma em estado de sessão/stream corrompido → UAF.

Evidência de `NODE_DEBUG_NATIVE=http2` em um servidor vulnerável (uma leitura de 86 bytes):```
receiving 86 bytes, offset 0
complete frame received: type: 7          ← GOAWAY
submitting goaway                          ← GOAWAY submitted, NOT yet sent
beginning headers for stream 3             ← still accepted (only SUBMITTED)
handle headers frame for stream 3          ← JS: session.closed → refuse
sending rst_stream with code 7             ← SubmitRstStream(REFUSED_STREAM), in scope
sending pending data                       ← RE-ENTRANT mem_send()
stream 3 closed with code: 7               ← GOAWAY send closes stream 3
Removing stream: 3 / destroying stream     ← Http2Stream freed mid-recv

Assinatura comportamental

A saída no nível de fio é idêntica em builds vulneráveis e corrigidos (ambos acabam enviando apenas o GOAWAY de saída — em builds vulneráveis o RST é submetido contra um stream já fechado, em builds corrigidos o nghttp2 descarta os RSTs enfileirados assim que o GOAWAY é enviado primeiro). A diferença é interna, visível com NODE_DEBUG_NATIVE=http2:

  • Vulnerável: sending pending data aparece entre sending rst_stream with code 7 e stream 3 closed with code: 7 — o mem_send() reentrante executa no meio do receive e fecha/destrói o stream 3 enquanto mem_recv() ainda está em andamento (crash sob ASan).
  • Corrigido: sem sending pending data entre eles — o RST é meramente enfileirado; o stream 3 é fechado apenas durante o flush normal pós-receive.

PoC```

server.js # minimal http2.createServer() target (no handler needed) exploit.js # raw-socket HTTP/2 client that drives the trigger

### Execução rápida```bash
# Terminal 1: the target (any vulnerable node: 22.23.1 / 24.18.0 / 26.5.0 or older in their lines)
node server.js 8000                       # NODE_BIN=/path/to/node for a specific binary

# Terminal 2: the attack — a crash shows up in terminal 1 (ASan report / segfault)
node exploit.js --port 8000 --iterations 200

./bin/node (o build ASan local usado abaixo) não é rastreado no git — compile-o com as instruções em "Construindo um Node.js vulnerável instrumentado com ASan", ou use a rota via Docker.

O exploit reporta o status por conexão; SKIPPED (no handshake) após a primeira conexão significa que o alvo já morreu em decorrência do ataque.

Docker

O Dockerfile compila um alvo vulnerável v22.23.1 com ASan dentro de um contêiner (nenhuma toolchain local é necessária — apenas o daemon do Docker):```bash docker build -t cve-2026-56848 . docker run --rm -p 8000:8000 --name cve-target cve-2026-56848

from the host, in another terminal:

you could reuse ./bin/node

node exploit.js --port 8000 --iterations 10

Baixar ferramenta