Dealing with a new, powerful intruder attack
Steve is CTO of Sanctum and participates in several working groups of the Internet Engineering Task Force (IETF) and Web Application Security Consortium (WASC). He can be contacted at sorrinsanctuminc.com. Amit is Director of Security and Research for Sanctum. He can be contacted at aklein sanctuminc.com.
In the process of developing AppScan (a security testing tool from Sanctum, the company we work for), we discovered a new attack technique called "HTTP response splitting." This powerful and elegant technique has an impact on various web environments. HTTP response splitting enables various attacks, such as web-cache poisoning, cross-user defacement, page hijacking of user information, and cross-site scripting (XSS). HTTP response splittingand the attacks derived from itis relevant to most web environments and is the result of an application's failure to reject illegal user input; in this case, input containing malicious or unexpected charactersthe CR and LF characters.
An HTTP response-splitting attack always involves at least three parties:
- The web server, which has a security hole enabling HTTP response splitting.
- The target, which interacts with the web server perhaps on behalf of attackers. Typically, this is a cache server (forward/reverse proxy) or browser (possibly with a browser cache).
- The attacker who initiates the attack.
At the heart of HTTP response splitting is the attacker's ability to send a single HTTP request that forces the web server to form an output stream, which is then interpreted by the target as two HTTP responses instead of the normal single response. The first response may be partially controlled by attackers, but this is less important. What is material is that attackers completely control the form of the second response from the HTTP status line to the last byte of the HTTP response body. Once this is possible, attackers realize the attack by sending two requests through the target. The first one invokes two responses from the web server, and the second request typically is to some "innocent" resource on the web server. However, the second request is matched by the target to the second HTTP response, which is fully controlled by attackers. Attackers, therefore, trick the target into believing that a particular resource on the web server (designated by the second request) is the server's HTTP response (server content) while, in fact, it is some data that is forged by attackers through the web serverthis is the second response.
HTTP response-splitting attacks occur where the server script embeds user data in HTTP response headers. This typically happens when the script embeds user data in the redirection URL of a redirection response (HTTP status code 3xx), or when the script embeds user data in a cookie value or name when the response sets a cookie. In the first case, the redirection URL is part of the Location HTTP response header, and in the second cookie setting case, the cookie name/value is part of the Set-Cookie HTTP response header.
For instance, consider the JSP page (located in /redir_lang.jsp) in Example 1(a). When invoking /redir_lang.jsp with a parameter lang=English, it redirects to /by_lang.jsp?lang=English. Example 1(b) is a typical response (the web server is BEA WebLogic 8.1 SP1). As you can see, the lang parameter is embedded in the Location response header. In terms of mounting an HTTP response-splitting attack, instead of sending the value English, we send a value that makes use of URL-encoded CRLF sequences to terminate the current response and shape an additional one. Example 2(a) illustrates how this is done. This results in the output stream in Example 2(b), sent by the web server over the TCP connection. This TCP stream is parsed by the target as follows:
- A first HTTP response, a 302 (redirection) response.
- A second HTTP response, a 200 response with content comprising of 19 bytes of HTML.
- Superfluous data. Everything beyond the end of the second response is superfluous and does not conform to the HTTP standard. So when attackers feed the target with two requests, the first being to the URL in Example 3(a) and the second to the URL in Example 3(b), then the target would believe that the first request is matched to the first response; see Example 3(c). And by this, the attacker manages to fool the target.
Admittedly, this example is naive. For instance, it doesn't take into account problems with how targets parse the TCP stream, issues with the superfluous data, problems with the data injection, and how to force caching.
With HTTP response splitting, it is possible to mount various kinds of attacks:
- Cross-site scripting (XSS). Until now, it has been impossible to mount XSS attacks on sites through a redirection script when the clients use IE unless the Location header can be fully controlled. With HTTP response splitting, it is possible to mount XSS attacks even if the Location header is only partially controlled by the attacker.
- Web-cache poisoning (defacement). This is a new attack. Attackers force the target (a cache server of some sort, for instance) to cache the second response in response to the second request. An example is to send a second request to "http://web.site/index.html" and force the target (cache server) to cache the second response, which is fully controlled by attackers. This is effectively a defacement of the web site, at least as experienced by other clients who use the same cache server. Of course, in addition to defacement, attackers can steal session cookies, or "fix" them to a predetermined value.
- Cross-user attacks (single user, single page, temporary defacement). As a variant of the attack, attackers don't send the second request. This seems odd at first, but the idea is that, in some cases, the target may share the same TCP connection with the server, among several users (this is the case with some cache servers). The next user to send a request to the web server through the target is served by the target with the second response, which the attackers generated. The net result is having a client of the web site being served with a resource crafted by attackers. This enables attackers to deface the site for a single page requested by a single user (a local, temporary defacement). In addition to defacement, attackers can steal session cookies and/or set them.
- Hijacking pages with user-specific information. With this attack, attackers can receive the server response to user requests instead of the user. Therefore, attackers gain access to user-specific information that may be sensitive and confidential.
- Browser-cache poisoning. This is a special case of web-cache poisoning. It is similar to XSS in that the attacker needs to target individual clients. However, unlike XSS, it has a long-lasting effect because the spoofed resource remains in the browser's cache.
A Step Toward the "Perfect Hack"
One of the unique properties of HTTP response-splitting's web-cache poisoning attack is its forensics and incident-response hampering qualities. Typically, when a site is defaced or hacked, site administrators are notified by unhappy users. In classic examples of web-site defacement where a file on the web server itself has been altered or replaced, a quick look at the site by the administrator is all that is necessary to validate that the attack has occurred. With web-cache poisoning, the altered or replaced page will not show up on the web server and may be invisible to internal employees accessing the site directly as opposed to accessing it from the external Internet (where the cache server typically provides its service). Further, in the instance of an intermediate web-cache server attack, such as an online service or ISP's cache servers, administrators will be unable to verify the attack unless they are accessing the site via the ISP or online service. Web-cache poisoning can also result in insufficient logs. Due to the transient nature of the data held in cache servers, pages cached and the time of cache refresh or update are rarely logged, and even if the time of update is logged, the page content is not. This also impedes incident response and forensics.
Finally, HTTP response splitting is reversible by attackers, who have the ability to undo the web-cache poisoning attack by submitting the injection with a payload constructed to reverse the effects. This is important on two key levels:
- Standard forensics and incident-response procedures hinge on capturing attack evidence; in this case, the modified HTML page. By removing the malicious page prior to the site administrator or law enforcement obtaining a copy, attackers can cover their tracks and hamper (if not disable) forensics procedures. Thus, attackers can implement the attack and quickly reverse it, leaving site administrators and law enforcement with nothing to establish that an attack even occurred.
- Some web-cache servers are scheduled to automatically refresh cached pages from the web site at regular intervals. With past web-site defacement attacks, covering one's tracks typically required hacking back into the site and deleting the manipulated files. Only very skilled intruders could change or manipulate the web-server logs to mask the break-ins. An HTTP response-splitting web-cache poisoning attack lets even novice crackers hack with a level of impunity once reserved for the very skilled.
It is critical that web-application developers validate input. You need to remove CRs and LFs (and all other hazardous characters) before embedding data into any HTTP response headers, particularly when setting cookies and redirecting. Another option is to reject requests that contain these characters in data that is embedded into HTTP headers, as such requests are attack attempts. It is possible to use third-party products (like Sanctum's AppShield, for example) to prevent CR/LF injection.
Consider the (vulnerable) J2EE script example from Example 1(a), in which the code was shown to be vulnerable (at least, in BEA WebLogic 8.1 SP1 and in IBM WebSphere 5.1 servers). It can be easily fixed by making sure that no CR/LF is present in the parameter; see Example 4. This logic ensures that the lang parameter does not contain any CR or LF by searching for each and ascertaining that neither is found in the parameter value.
In ASP.NET, making sure that controls do not contain specific characters amounts to using (correctly) the regular expression field validator. For example:
"lang " ValidationExpression="^[^\r\n]*$"
runat="server" id="..." />
This ASP.NET field validator is bound to the user-input control lang, and validates this input field by ensuring that it does not contain the CR/LF characters. This is done via matching the input field to a regular expression that does not allow any CR or LF in its pattern. Of course, it is also necessary to test explicitly for the state of the validator (by checking lang.IsValid or by checking the global page state Page.IsValid).
Furthermore, you should make sure to use the most up-to-date application engine and ensure that your application is accessed through a unique IP address (that is, that the same IP address is not used for another application as it is with virtual hosting).
Lastly, we advise that you scan the application (before deployment, using a tool such as Sanctum's AppScan, http://www.sanctuminc.com/) to ensure that the application is not vulnerable to HTTP response-splitting (and other) attacks.
HTTP response splitting is a new technique that enables several new and interesting attacks. This technique only applies to applications that do not validate their input before embedding it into HTTP response headers. Avoiding this vulnerability is a simple matter of adding a short If test (or, in ASP.NET, using a field validator control). Application programmers are encouraged to understand the new threat and to apply the simple security measures in their applications and, in general, to implement security (via input validation) in their code.