Detecting And Preventing HTTP Response Splitting And HTTP Request Smuggling Attacks At The TCP Level
16 Aug. 2005
This technical note describes a detection/prevention technique that works in many cases both with HTTP Response Splitting and with HTTP Request Smuggling. This technique makes use of implicit information found in the TCP stream, namely the segmentation into packets and the TCP PSH bit.
In HTTP Response Splitting, the proposed technique needs to be applied at the proxy server, the one closest to the web server, and to the response stream. In HTTP Request Smuggling, this technique needs to be applied at the entity closest to the attacked proxy server/device (i.e. implemented in another proxy server, or the web server itself), and to the request stream (note, however, that this second server may be off the premises of the organization wherein the web server is, see also "Can HTTP Request Smuggling be blocked by Web Application Firewalls?".
TCP PSH bit and PUSH flag:
Before describing the technique, the reader is reminded what are the TCP PSH bit and PUSH flag. RFC 793 defines the push functionality as following (from section 1.5): "Sometimes users need to be sure that all the data they have submitted to the TCP has been transmitted. For this purpose a push function is defined. To assure that data submitted to a TCP is actually transmitted the sending user indicates that it should be pushed through to the receiving user. A push causes the TCPs to promptly forward and deliver data up to that point to the receiver."
And in section 2.8: "The sending user indicates in each SEND call whether the data in that call (and any preceeding [sic] calls) should be immediately pushed through to the receiving user by the setting of the PUSH flag."
This is realized by a PSH bit in the TCP header.
RFC 793 also mandates that the socket API provides means for the caller to set this bit via a PUSH flag in the SEND function, and to likewise receive it in the RECV function.
However, this requirement was later waived in RFC 1122, section 126.96.36.199: "A TCP MAY implement PUSH flags on SEND calls. If PUSH flags are not implemented, then the sending TCP: (1) must not buffer data indefinitely, and (2) MUST set the PSH bit in the last buffered segment (i.e., when there is no more queued data to be sent).
The discussion in RFC-793 on pages 48, 50, and 74 erroneously implies that a received PSH flag must be passed to the application layer. Passing a received PSH flag to the application layer is now OPTIONAL."
This means that according to RFC 1122, these implementations should simply set the TCP PSH flag in the last TCP segment of the caller's data buffer. Unfortunately, this also means that socket applications do not have direct access to the PSH bit (in other words, it would take some hacking around the standard sockets API to get this information - thus making the whole idea presented below much harder to implement in pure sockets applications).
To illustrate: a sender uses the sockets send() function to send a payload of 2000 bytes over a TCP circuit on a LAN. The call is (assuming C API):
send(socket, buffer, 2000, ...);
This results in 2 TCP segments (IP packets), the first carrying a payload of 1448 bytes (maximal LAN packet, minus level 2, IP and TCP headers), the second carrying a payload of the remaining 552 bytes, with a PSH bit set.
In contrast, having the caller invoke send twice to send the same data:
Results in 2 TCP segments, both having 1000 bytes of payload, and both having the PSH bit set.
Therefore, by inspecting the TCP header, one can figure out (in this rather simplistic example) whether the data was sent via a single call to send(), or via two calls.
This observation is the basis for the following technique described below.
Detecting HTTP Response Splitting and HTTP Request Smuggling:
Detection of HTTP Response Splitting attack can be realized by fulfilling the following requirements (the technique can be applied to HTTP Request Smuggling with some obvious modifications):
Requirement #1: Deny "pipelined" traffic, that is, do not accept a second response before a first response was fully served, and a second request was fully received. Particularly, a packet containing data for the first response must not contain superfluous data beyond the end of the first response (i.e. a second response).
Requirement #2: Since from #1 it follows that the end of the first response coincides with an end of a packet, and end of transmission, such packet should contain a PSH bit set (see above).
Requirement #1 is obvious, yet insufficient, as shown in the successful HTTP Response Splitting attacks against Squid and NetCache (see Divide and Conquer - HTTP Response Splitting, Web Cache Poisoning Attacks, and Related Topics, pp. 15-19), although both products impose packet boundary requirements (making sure that the first response terminates at a packet boundary isn't so hard if the packet length is known to the attacker). But if we are to add requirement #2, the attack can be thwarted in many cases, because the attacker has no way of forcing the web server to send the PSH flag (remember that the from the web server's perspective, it is in the middle of the first response, and will send the PSH bit only at the end of the first response). Of course, it may be possible that the web server always sends the PSH bit (for example, the TCP stack of IBM TPF 4.1 apparently does so by default - see the description of TCP_PSH_LAST ioctl option in http://www-306.ibm.com/software/htp/tpf/serv/GTPMLB19.pdf),
or sends it after each HTTP response header, or in the middle of the response, but that is not the case with many servers (although I have seen servers that on occasion will send the PSH flag in the middle of HTTP responses).
So, while it may not be perfect, it seems that this technique has a high detection probability (much higher than enforcing requirement #1 alone), yet very low likelihood for false positives.
1. The technique fails if there are TCP/HTTP aware devices between the web server and the proxy server, as these may alter the TCP stream.
2. The technique can be applied to HTTP Request Smuggling as following: the proxy server forwards the requests to the web server. The web server (or the receiving entity) needs to verify that the request ends on a packet boundary, and that the PSH flag is set.
3. While the technique covers detection of attacks, since such detection is carried out in real-time, it is possible to terminate the TCP connection (or perform other actions) and thereby to block the attack.
4. This technique lends itself nicely to detection/prevention by network IDS/IPS, as it only requires sniffing the TCP/IP traffic and flagging HTTP requests/responses that do not terminate on a packet boundary, with PSH bit set.
Other, complementary methods (for prevention) that are known to work are:
1. The web site can use SSL connections (HTTPS) only. This will only eliminate 3rd party proxy servers. It does not eliminate the browser cache issue, and it may not handle the site's own cache server (or any other on-site HTTP aware devices). Of course, migrating to SSL only has many real-life drawbacks.
2. A proxy cache server can be configured not to use persistent HTTP connections with the *server*, in which case, its cache will not be poisoned. This prevention technique has significant performance impact.
Observing that an end of HTTP request/response message is aligned with a TCP segment (packet) boundary, *and* that that segment has the PSH bit set, can be an effective way to detect and prevent HTTP Response Splitting and HTTP Request Smuggling. This technique can be easily employed when the TCP layer is directly accessible (as opposed to the sockets model).