HTTP Attacks  

Further H2 Vulnerabilities


While the H2.CL and H2.TE vulnerabilities we have discussed in the previous section are straightforward exploits, there are more complex H2 vulnerabilities. In many cases, the reverse proxy's request rewriting is not vulnerable simply when the CL or TE headers are present. However, we can exploit differences in HTTP/1.1 and HTTP/2 to trick the reverse proxy into rewriting the request in a way that causes desynchronization. In this section, we will discuss these more complex cases that can lead to request smuggling vulnerabilities in HTTP/2 downgrading settings.


Foundation

Since HTTP/2 is a binary protocol, there are inherent differences in the way data is represented in HTTP/1.1 and HTTP/2 requests. These differences in data representation lead to different behavior when it comes to certain control characters. In particular, HTTP headers in HTTP/1.1 cannot contain the CRLF control sequence \r\n since this sequence is used to terminate a header. If it was included in a header value, it would just terminate the header. However, in HTTP/2 the headers are represented completely differently such that arbitrary characters can be contained in the headers, at least in theory. In practice, the HTTP/2 RFC defines the following restrictions in section 8.2.1:

Failure to validate fields can be exploited for request smuggling attacks. 
In particular, unvalidated fields might enable attacks when messages are forwarded using HTTP/1.1, 
where characters such as carriage return (CR), line feed (LF), and COLON are used as delimiters. 
Implementations MUST perform the following minimal validation of field names and values:

- A field name MUST NOT contain characters in the ranges 0x00-0x20, 0x41-0x5a, or 0x7f-0xff (all ranges inclusive). This specifically excludes all non-visible ASCII characters, ASCII SP (0x20), and uppercase characters ('A' to 'Z', ASCII 0x41 to 0x5a).

- With the exception of pseudo-header fields, which have a name that starts with a single colon, field names MUST NOT include a colon (ASCII COLON, 0x3a).

- A field value MUST NOT contain the zero value (ASCII NUL, 0x00), line feed (ASCII LF, 0x0a), or carriage return (ASCII CR, 0x0d) at any position.

- A field value MUST NOT start or end with an ASCII whitespace character (ASCII SP or HTAB, 0x20 or 0x09).

<SNIP>

A request or response that contains a field that violates any of these conditions MUST be treated as malformed. 
In particular, an intermediary that does not process fields when forwarding messages MUST NOT 
forward fields that contain any of the values that are listed as prohibited above.

In particular, according to the standard, implementations should reject requests containing special characters like CR, LF, and : in HTTP headers. If a reverse proxy does not implement this correctly or skips it entirely, we might be able to exploit request smuggling by creating an H2.TE vulnerability. Let's discuss a few examples of this.


Request Header Injection

If the reverse proxy does not check for CRLF characters in HTTP/2 header values before rewriting the request to HTTP/1.1, we might be able to create a request smuggling vulnerability with an HTTP/2 request like the following (header names are red, header values are green, and the request body is yellow):

:method POST
:path /
:authority http2.htb
:scheme http
dummy asd\r\nTransfer-Encoding: chunked
0

GET /smuggled HTTP/1.1
Host: http2.htb


The HTTP/2 request contains a header dummy with the value asd\r\nTransfer-Encoding: chunked since the CRLF sequence has no special meaning in HTTP/2. A vulnerable reverse proxy creates the following TCP stream:

POST / HTTP/1.1
Host: http2.htb
Dummy: asd
Transfer-Encoding: chunked
Content-Length: 48

0

GET /smuggled HTTP/1.1
Host: http2.htb


When rewriting the request to HTTP/1.1, the semantics of the CRLF sequence changes as it now separates headers from each other. Therefore, the HTTP/1.1 request now contains a header Dummy with the value asd, and a header Transfer-Encoding with the value chunked. Furthermore, the reverse proxy adds the CL header in the rewriting process to inform the web server about the request body's length. However, since the TE header has precedence over the CL header, the web server treats the first request as having chunked encoding. Thus, we have an H2.TE vulnerability.


Header Name Injection

A similar issue arises if the reverse proxy does not properly check the HTTP/2 header names before rewriting the request to HTTP/1.1. We might be able to create a request smuggling vulnerability with an HTTP/2 request like the following (header names are red, header values are green, and the request body is yellow):

:method POST
:path /
:authority http2.htb
:scheme http
dummy: asd\r\nTransfer-Encoding chunked
0

GET /smuggled HTTP/1.1
Host: http2.htb


The HTTP/2 request contains a header dummy: asd\r\nTransfer-Encoding with the value chunked since the CRLF sequence has no special meaning in HTTP/2. A vulnerable reverse proxy creates the following TCP stream:

POST / HTTP/1.1
Host: http2.htb
Dummy: asd
Transfer-Encoding: chunked
Content-Length: 48

0

GET /smuggled HTTP/1.1
Host: http2.htb


When rewriting the request to HTTP/1.1, the semantics of the CRLF sequence changes as it now separates headers from each other. Therefore, the HTTP/1.1 request now contains a header Dummy with the value asd, and a header Transfer-Encoding with the value chunked. Just like in the previous case, we have an H2.TE vulnerability since the TE header has precedence over the CL header in HTTP/1.1.


Request Line Injection

Since pseudo-headers are special in HTTP/2, they might be treated differently. It might therefore be worth checking them separately, since potential validation checks may not be applied. For instance, we can achieve request smuggling if the reverse proxy does not properly check the HTTP/2 pseudo-headers before rewriting the request to HTTP/1.1 with an HTTP/2 request like the following (header names are red, header values are green, and the request body is yellow):

:method POST / HTTP/1.1\r\nTransfer-Encoding: chunked\r\nDummy: asd
:path /
:authority http2.htb
:scheme http
0

GET /smuggled HTTP/1.1
Host: http2.htb


The HTTP/2 request contains the value POST / HTTP/1.1\r\nTransfer-Encoding: chunked\r\nDummy: asd in the pseudo-header :method. A vulnerable reverse proxy creates the following TCP stream:

POST / HTTP/1.1
Transfer-Encoding: chunked
Dummy: asd / HTTP/1.1
Host: http2.htb
Content-Length: 48

0

GET /smuggled HTTP/1.1
Host: http2.htb


When rewriting the request to HTTP/1.1, the CRLF sequence in the method pseudo-header results in the TE header being added to the request. The actual path and HTTP/1.1 keyword are appended to the Dummy HTTP header during the rewriting process. Therefore, the HTTP/1.1 request now contains a header Dummy with the value asd / HTTP/1.1, and a header Transfer-Encoding with the value chunked. Just like in the previous cases, we have an H2.TE vulnerability since the TE header has precedence over the CL header in HTTP/1.1.

Previous

+10 Streak pts

Next