Bypassing servlet input validation filters (OWASP Stinger + Struts example)

ORIGINAL ADVISORY
http://o0o.nu/~meder/o0o_bypassing_servlet_input_validation_filters.txt

BACKGROUND
NOTE: This advisory will use OWASP's Stinger and Struts framework to illustrate the concept, however this technique should be applicable to other input validation servlet filters that do not handle multipart requests properly and frameworks that automatically parse multipart requests.

Java Servlets provide a filter component which can dynamically intercept requests and responses to transform information contained in the requests or responses[1]. Servlet filters are often recommended as an effective way to perform input validation in Java web applications due to the centralized nature and little modifications required to the application's code.

Open Web Application Security Project (OWASP) has developed Stinger, which aims to provide a centralized input validation component which can be easily applied to existing or developmental applications[4].

There is a vulnerability in servlet filters, such as the Stinger filter, which under certain conditions will allow attacker to bypass input validation routines of the filter thus supplying unvalidated input to the application, potentially exploiting vulnerabilities, such as XSS or SQL injection.

DESCRIPTION
OWASP Stinger is built with the assumption that content of requests passing through it are always form-urlencoded. This assumption is harmless in a simple J2EE web application setup as both Stinger and application will use the same methods to access HTTP parameters (i.e. Request.getParameter or Request.getParameterNames[3]). However, in an application that uses frameworks that abstract HTTP protocol and provide automatic request handling/parsing, this assumption can result in the ability to bypass Stinger filtering while still delivering inputs to the target application.

The following Stinger code snippet illustrates the problem (Stinger.java):

private int checkMalformedParameters(...) { ...  e = request.getParameterNames; while(e.hasMoreElements) { ...  }   ... }

If HTTP request content was form-urlencoded then request.getParameterNames will return Enumeration of all HTTP parameters names. However, if the request is multipart encoded, Enumeration that is returned will be empty and e.hasMoreElements will return false, which in turn will result in Stinger not performing any input validation on the multipart encoded HTTP requests. It should be noted that standard servlet API doesn't provide a convenient way of handling multipart requests.

If the target application is a plain vanilla servlet application, multipart encoded HTTP parameters will not be returned by the Request.getParameter call and thus input will not be honored by the target application. However, frameworks like Struts abstract HTTP details from the application and perform automatic parsing of HTTP requests, including multipart encoded requests. The framework will then pass the input parameters supplied in a multipart request to the application, which will be unaware whether parameters came in through a multipart request or a regular form-urlencoded request. And as Stinger did not perform any validation on the multipart request, unescaped and unvalidated data will be supplied to the application, which in turn may result in a security vulnerability such as XSS or SQL injection being exploited.

RECOMMENDATIONS
Servlet filters should handle multipart requests too and perform input validation on the multipart encoded content.

Additionally, following the multi-layered security approach, applications should not rely on the filter to provide input validation and be the only line of defense. Most of the frameworks today provide a way to perform input validation within the application [5,6].

Also, if multipart requests are not required by the application (e.g. no file uploads are performed) automatic handling of multipart requests should be disabled in the framework and servlet filter could be configured.

VENDOR STATUS
OWASP Stinger 2.5 contains a quick fix to drop non-urlencoded requests.

DISCLOSURE TIMELINE
18/07/2007 - Vulnerability details sent to the maintainer 23/07/2007 - Vulnerability details resent 26/07/2007 - Initial vendor response (delay due to spam filters) 05/08/2007 - Quick-fix implemented dropping multipart requests in Stinger 2.5

ACKNOWLEDGMENTS
blshkv, jml for helping to verify the issue. Rogan Dawes and Jeff Williams for helping to get in contact with maintainer. Eric Sheridan for a timely resolution of the issue.