Lucene search

K
hackeroneAlyssawilkH1:730779
HistoryNov 06, 2019 - 5:46 p.m.

Node.js: HTTP header values do not have trailing OWS trimmed

2019-11-0617:46:12
alyssawilk
hackerone.com
37

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

7.5 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:L/Au:N/C:P/I:P/A:P

0.007 Low

EPSS

Percentile

77.8%

[I suspect I may have tagged the wrong vulnerability type -I’m failing to find “insufficient validation of user input”]

According to the HTTP-spec, http values are
field-value = *( field-content | LWS )
http_parser does not appear to trim trailing LWS. This means if a user sends “Host: foo\r\n” the string literal “foo” is passed up, but if the user sends “Host: foo \r\n” the string literal "foo " is passed up, complete with trailing LWS.

Steps To Reproduce:

(Add details for how we can reproduce the issue)

If one hands “GET / HTTP/1.1\r\nHost: foo.com \r\nHello: World\r\n\r\n”
to http_parser, http_parser sends on_header_value "foo.com " instead of “foo.com

Impact: [add why this issue matters]

We are trying to address an issue with Envoy, where if
“GET / HTTP/1.1\r\nHost: my-super-private-domain.com \r\nHello: World\r\n\r\n”
is passed to Envoy, and Envoy is configured to block any requests to “my-super-private-domain.com”, the matcher fails due the trailing whitespace, and external users can tunnel requests that should be blocked.

Originally we were going to address this by doing whitespace trimming in Envoy, but this should probably be fixed upstream in http_parser in case other users are affected, so we’re reaching out to see what folks on your end think.

Supporting Material/References:

My Envoy regression test verifies this lack of LWS trimming, but this is current under envoy security embargo, so please don’t share

TEST_F(Http1ServerConnectionImplTest, LWS) {
initialize();

InSequence sequence;

Http::MockStreamDecoder decoder;
EXPECT_CALL(callbacks_, newStream(_, _)).WillOnce(ReturnRef(decoder));

TestHeaderMapImpl expected_headers{
{“Test”, “value “}, // note the LWS after value is passed up from http_parser to Envoy :-(
{“Hello”, “World”},
{”:path”, “/”},
{“:method”, “GET”},
};
EXPECT_CALL(decoder, decodeHeaders_(HeaderMapEqual(&expected_headers), true)).Times(1);

Buffer::OwnedImpl buffer(“GET / HTTP/1.1\r\nTest: value \r\nHello: World\r\n\r\n”);
codec_->dispatch(buffer);
EXPECT_EQ(0U, buffer.length());
}

Impact

As said above, this could allow privileged escalation, where if one uses an http_parser enabled server configured to block specific domains, those blocks can be trivially bypassed using white-space. It’s possible there are other attacks bypassing http_parser header value checks with whitespace, but I haven’t investigated beyond the most obvious exploit

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

7.5 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:L/Au:N/C:P/I:P/A:P

0.007 Low

EPSS

Percentile

77.8%