HTTP Request Smuggling
HTTP Request Smuggling - An attack through the HTTP protocol based on the collision of conflicting configurations of mechanisms that determine the total character count of an incoming user request on both the Front-end and Back-end servers during request processing.
When utilizing popular server software solutions, such issues typically do not arise due to the security measures that are often enabled by default. Nevertheless, it is evident that as software becomes obsolete, custom configurations are introduced by developers for header processing or the determination of request length, lesser-known server solutions unfamiliar to developers are implemented, significant vulnerabilities may be introduced.
Possible security measures include:
- Given its inherent nature, the HTTP/2 protocol version is entirely immune to request smuggling attacks. Therefore, a logical solution would be to exclusively implement HTTP/2 request processing on both servers.
- If using HTTP/2 on both sides is not feasible, mitigating a significant portion of HTTP/2 downgrading attack vectors can be achieved by employing HTTP/1.1.
- Employing a uniform method for determining request length on both servers and rejecting any requests that contain an inactive method as potentially hazardous.
- Vulnerabilities of the CL.0 and H/2.0 types arise when the back-end disregards the value of the CL header and assumes that all received requests have empty bodies. Avoid such behavior.
- To prevent H/2 downgrading attacks with properly filtered CL/TE headers / TE.TE / CL.0, it is necessary to conduct server response testing for header obfuscation, CRLFi, header discrepancy. Additionally, disable unused HTTP methods.
The complexities of exploitation primarily center on identifying front-end request reformatting and normalization patterns for correct back-end server processing. Simultaneously, when both servers employ the HTTP/1 protocol, the vulnerability relies on differences in header "Content-Length" and "Transfer-Encoding" policy interpretations, filtering, and processing. In cases where a downgrade of the HTTP protocol version is required for back-end server request processing, the vulnerability relies on errors, absence, or vulnerabilities in CL/TE (received within the context of an HTTP/2 request) header filtering systems.
- The Content-Length (CL) header is designed to count the number of bytes in an HTTP request, starting immediately after the CRLF delimiter sequence. In brief, CL determines the length of the HTTP request body, and its value is the number of bytes in that body. This is necessary for the server to determine the point at which it should stop reading the request and begin processing it.
- Transfer-Encoding: chunked serves the same purpose but allows the server to dynamically process parts of the received body without waiting for the complete request. According to the official HTTP/1.1 documentation, this is useful when transmitting a large amount of data in a request to the server. When specifying this header with the "chunked" value, the data in the request body is transmitted in chunks. Each chunk, starting from the first, must begin with a sequence that represents the number of octets in the chunk (immediately following the sequence) and a subsequent CRLF (e.g.,
b\r\naaadsfddsds
). The message ends with a final "zero-length" chunk, followed by a CRLF.
Let's consider examples: Suppose the server does not reuse TCP connections for different clients. In that case, the attacker must receive a response to the smuggled request within the main request's body. Here, the HEAD method allows transforming the vulnerability into non-blind, as the response to it contains a CL header equal to the corresponding GET request path. To avoid timeout errors and truncation of the received response body, you can use an endpoint with reflection, as shown below. Here is an example of request tunneling through H/2 downgrading via CRLFi, resulting in cache poisoning.
:method = HEAD
:scheme = https
:path = /smth.js HTTP/1.1\r\n
Host: vulnerable-website.com\r\n
\r\n
GET /reflection-here?<script>alert()<script>sssssssssssssssssssssssssssssssssssssss HTTP/1.1\r\n
Foo: x
:authority = vulnerable-website.com
In accordance with the prescribed scenario, the backend processing encompasses the reception of requests in the subsequent manner:
HEAD /smth.js HTTP/1.1
Host: vulnerable-website.com
GET /reflection-here?<script>alert()<script>sssssssssssssssssssssssssssssssssssssss HTTP/1.1\r\n
Foo: xHTTP/1.1
Host: vulnerable-website.com
Content-Type: text/html
Regarding the criticality in the simplest CL.TE request smuggling: A request smuggling attack resulting in queue poisoning occurs when TCP connections between front-end and back-end servers are not reused multiple times. The technique involves the attacker sending a wrapper request containing a smuggled request that is correctly processed and remains unchanged when merged with the subsequently received client request. The back-end server processes the root request, leaving the smuggled request "hanging" until the next legitimate client request is received. Due to the previously defined structure of the smuggled request, which remains unchanged when additional characters are added to it, the server processes and forwards the previous smuggled request to the client upon receiving the next one. Consequently, until the connection is updated, the back-end server's response queue will permanently consist of a single unprocessed request, creating a desynchronization cycle that affects all server users, resulting in at least a service disruption and the exposure of numerous session keys.
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 61
Transfer-Encoding: chunked
0
GET /anything HTTP/1.1
Host: vulnerable-website.com\r\n\r\n