HTTP Request smuggling
Last updated
Last updated
HTTP request smuggling is a security exploit on the HTTP protocol that uses inconsistency between the interpretation of Content-Length and/or Transfer-Encoding headers between HTTP server implementations in an HTTP proxy server chain. It was first documented in 2005 by Linhart et al.
--
Place both Content-Length
(CL) and Transfer-Encoding
(TE) headers into a single HTTP request.
OR
Infrastructure uses HTTP/2, but not end-to-end, e.g. FE downgrades requests to HTTP/1 for BE.
The Content-Length entity-header field indicates the size of the entity-body, in decimal number of OCTETs, sent to the recipient or, in the case of the HEAD method, the size of the entity-body that would have been sent had the request been a GET.
From the
Be aware that linebreaks (\r
) are 2 octets/bytes long.
Calculation
"test": 4 bytes
linebreak (\r\n): 2 bytes
"123": 3 bytes
linebreak (\r\n): 2 bytes => Content-Length: 11
The Transfer-Encoding general-header field indicates what (if any) type of transformation has been applied to the message body in order to safely transfer it between the sender and the recipient. This differs from the content-coding in that the transfer-coding is a property of the message, not of the entity.
For this vulnerability type we're only interested in the chunked
option.
Each chunk starts with a hexadecimal number, determining the length of the chunk, followed by a linebreak (\r
), followed by the acutal data (chunk), followed by another linebreak (\r
).
The terminating chunk has a length of 0
, an empty chunk and another linebreak, after the "empty chunk".
Frontend uses Content-Length
, backend Transfer-Encoding
.
Frontend determines the request body is 13 bytes long (up to the end of "SMUGGLED").
Backend determines the first chunk is 0 and terminates the request. => "SMUGGLED" is then treated as the start of next request.
Frontend uses Transfer-Encoding
, backend Content-Length
.
Frontend determines the request body has one 8 byte long chunk (up to the end of "SMUGGLED").
Backend determines the request body is 3 bytes long ("8" plus 2 bytes for the following linebreak, right up until the start of "SMUGGLED"). => "SMUGGLED" is then treated as the start of the next request.
Both support Transfer-Encoding
, but the header can be obfuscated to be only processed by one of them. This leads to either CL.TE
or TE.CL
depending on wether frontend or backend then uses Content-Length
instead of Transfer-Encoding
.
If HTTP/2 is not used end-to-end, but only by frontend servers, which then downgrade requests to HTTP/1 for backend servers, quite a few potential attacks are possible.
Eventhough HTTP/2 doesn't use a Content-Length
header, some frontend servers may nevertheless copy it over when downgrading a request to HTTP/1.
Basically the same as H2.CL
, but regarding Transfer-Encoding
header.
Injecting linebreaks into HTTP/2 requests, like: foo: bar\r\nTransfer-Encoding: chunked
Sending the Host
header together with :authority
pseudo-header may enable a range of "Host header attacks"
Supplying ambiguous path by applying the :path
pseudo-header twice with different values
Injecting a HTTP/1 request line in :method
pseudo-header, like :method GET /whatever HTTP/1.1
Injecting a URL prefix into :scheme
pseudo-header, like: :scheme https://evil-site.com?
Injecting newlines into pseudo-headers, like: :path /path HTTP/1.1\r\nTransfer-Encoding: chunked\r\nX: x
From the
For more examples see .
For details, see .