Skip to content
KitploitKITPLOIT
StrumentiExploitsBlog
Log in
Invia
StrumentiExploitsBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2026-56848 — Exploit PoC per CVE-2026-56848, una heap-use-after-free di Node.js HTTP/2 che consente DoS remoto non autenticato. Include trigger raw-socket, istruzioni di build ASan e target basato su Docker. | Kitploit
Strumenti/GitHubGitHub/open-flaw/cve-2026-56848
Analisi delle VulnerabilitàAnalisi Dinamica del Codice (DAST)ExploitSicurezza WebSicurezza di Rete
GitHubopen-flaw/cve-2026-56848

CVE-2026-56848

Exploit PoC per CVE-2026-56848, una heap-use-after-free di Node.js HTTP/2 che consente DoS remoto non autenticato. Include trigger raw-socket, istruzioni di build ASan e target basato su Docker.

Vedi Repository
411 mese faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

CVE-2026-56848

Descrizione NVD

Una falla nella gestione HTTP/2 di Node.js consente che nghttp2_session_mem_send() venga chiamata in modo rientrante mentre nghttp2_session_mem_recv() è in esecuzione, causando un heap-use-after-free.

Questa vulnerabilità riguarda Node.js 26.x, 24.x e 22.x.

(Nota: le versioni menzionate nella descrizione si applicano solo al pacchetto nodejs upstream e non al pacchetto nodejs distribuito da Alpine.

Linea di rilascioVulnerabileCorretta
22.x (LTS)≤ 22.23.122.23.2
24.x (LTS)≤ 24.18.024.18.1
26.x≤ 26.5.026.5.1
  • Gravità: Alta (CVSS 7.5, AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H — DoS remoto non autenticato tramite corruzione dell'heap)
  • Segnalata da: hahahkim (HackerOne #3833629)
  • Corretta da: Matteo Collina (mcollina)
  • Commit di correzione (v22): daa6d25e3dce — "http2: defer rst stream while in scope" (nodejs-private/node-private#921)
  • Divulgata: rilascio di sicurezza Node.js, 2026-07-29

Causa principale

Http2Stream::SubmitRstStream() in src/node_http2.cc forza una pulizia dei dati in uscita in sospeso prima di accodare il 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()` chiama `nghttp2_session_mem_send()` ([node_http2.cc:1970](https://github.com/nodejs/node/blob/v22.23.1/src/node_http2.cc#L1970)). La sua unica protezione di rientranza è `is_sending()`, che protegge da *send-during-send* (una scrittura già in corso) — **non da send-during-receive**. Quando `SubmitRstStream()` viene eseguito dall'interno di una catena di callback di `nghttp2_session_mem_recv()` ("in scope"), la purge esegue `mem_send()` in modo rientrante.

Il `mem_send()` rientrante invia i frame la cui elaborazione lato invio distrugge gli stream (`nghttp2_session_close_stream_on_goaway()` → `on_stream_close` → `Http2Stream::Destroy()` → free dell'`Http2Stream` C++). Lo stream liberato è ancora referenziato dall'operazione di ricezione in corso: `SubmitRstStream()` stesso continua a eseguire sul `this` liberato (il suo `FlushRstStream()` finale legge `is_destroyed()`), e il `mem_recv()` esterno continua a scorrere lo stato frame/header per lo stream chiuso → **heap-use-after-free**.

### Catena di trigger (tutto all'interno di una singola chiamata `nghttp2_session_mem_recv()`)

1. L'attaccante invia `GOAWAY(lastStreamID=0, NO_ERROR)` immediatamente seguito da frame `HEADERS` per nuovi stream (3, 5, 7, …) in un singolo segmento TCP.
2. Il `mem_recv()` del server elabora GOAWAY → `session.close()` in JS → `session.closed = true` e un GOAWAY in uscita viene **sottomesso ma non ancora inviato**.
3. nghttp2 rifiuta nuovi stream in arrivo solo dopo che GOAWAY è stato effettivamente *inviato* (`session_allow_incoming_new_stream()` controlla `TERM_ON_SEND | SENT`, non `SUBMITTED`), quindi `HEADERS(3)` viene ancora accettato.
4. `onSessionHeaders()` in JS vede un nuovo stream su una sessione chiusa e lo rifiuta: `handle.rstStream(NGHTTP2_REFUSED_STREAM)` (lib/internal/http2/core.js).
5. `SubmitRstStream(NGHTTP2_REFUSED_STREAM)` in C++ viene eseguito in scope (all'interno di `mem_recv`), `REFUSED_STREAM ≠ CANCEL` → ricade su `SendPendingData()` → **`nghttp2_session_mem_send()` rientrante**.
6. L'invio rientrante invia il GOAWAY in uscita; l'elaborazione lato invio di GOAWAY di nghttp2 chiude gli stream in arrivo con id > 1 (`session_close_stream_on_goaway(..., NGHTTP2_REFUSED_STREAM)`), attivando `on_stream_close` → `Http2Stream::Destroy()` libera l'oggetto C++ dello stream per lo stream 3.
7. L'esecuzione risale in `SubmitRstStream()` sull'oggetto liberato (`FlushRstStream()`), e il `mem_recv()` esterno riprende su stato sessione/stream corrotto → UAF.

Evidenza da `NODE_DEBUG_NATIVE=http2` su un server vulnerabile (una singola lettura di 86 byte):```
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

Firma comportamentale

L'output a livello di rete è identico nelle build vulnerabili e corrette (entrambe finiscono per inviare solo il GOAWAY in uscita — nelle build vulnerabili l'RST viene inviato contro uno stream già chiuso, nelle build corrette nghttp2 elimina gli RST in coda non appena il GOAWAY esce per primo). La differenza è interna, visibile con NODE_DEBUG_NATIVE=http2:

  • Vulnerabile: sending pending data appare tra sending rst_stream with code 7 e stream 3 closed with code: 7 — la chiamata rientrante mem_send() viene eseguita nel mezzo della ricezione e chiude/distrugge lo stream 3 mentre mem_recv() è ancora in corso (crash sotto ASan).
  • Corretta: nessun sending pending data tra i due — l'RST è solo messo in coda; lo stream 3 si chiude solo durante il normale flush successivo alla ricezione.

PoC```

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

### Esecuzione rapida```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 (la build locale ASan usata di seguito) non è tracciato da git — crealo seguendo le istruzioni in "Building an ASan-instrumented vulnerable Node.js", oppure usa la via Docker.

L'exploit riporta lo stato per connessione; SKIPPED (no handshake) dopo la prima connessione significa che il target è già morto a causa dell'attacco.

Docker

Il Dockerfile crea un target vulnerabile v22.23.1 con ASan all'interno di un container (nessuna toolchain locale necessaria — basta il daemon 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

Scarica lo strumento