Quick patch for jsp source disclosure vulnerability?

Brad Plies

Jakarta Tomcat has released a new version that simply deactivates a default ${catalina.home}/conf/web.xml setting of an InvokerServlet.

However, for some people with legacy systems using type 1 (non-MVC) architecture, they still require the ability to make posts (like an HTML form) to a target such as /servlet/PlaceOrder. Clearly the suggested workaround is not suitable for this class of use and they will remain vulnerable to .jsp source discloser which is very dangerous in type 1, since their complicated logic is usually within the .jsp file itself!

I have written a quick Servlet & web.xml entries to remove the problem so that instead of displaying the .jsp source code, it will use return a simple response.sendError(HttpServletResponse.SC_NOT_FOUND, ...);

/**
 * Written by:	Bradley Plies
 * A hack for securing JSP source disclosure vulnerabilities with Jakarta-Tomcat
 *
 * Usage:  In ${catalina.home}/conf/web.xml
 * Load this Servlet at boot time
 * Add a ServletMapping entry for pattern '/servlet/default/*' for this servlet
 * 
 * Source modelled after org.apache.catalina.servlets.DefaultServlet
 */
package org.apache.catalina.servlets;

import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class GenericNotFoundServlet extends HttpServlet 
{
	/**
     * Finalize this servlet.
     */
    public void destroy() 
	{
		// No actions necessary
		super.destroy();
   	}
	
    /**
     * Initialize this servlet.
     */
    public void init() throws ServletException 
	{
		super.init();
	}
    /**
     * Process a GET request for the specified resource.
     *
     * @param request The servlet request we are processing
     * @param response The servlet response we are creating
     *
     * @exception IOException if an input/output error occurs
     * @exception ServletException if a servlet-specified error occurs
     */
    protected void doGet(HttpServletRequest request,
                         HttpServletResponse response)
        throws IOException, ServletException {

        // Serve the requested resource, including the data content
        serveResource(request, response, true);

    }


    /**
     * Process a HEAD request for the specified resource.
     *
     * @param request The servlet request we are processing
     * @param response The servlet response we are creating
     *
     * @exception IOException if an input/output error occurs
     * @exception ServletException if a servlet-specified error occurs
     */
    protected void doHead(HttpServletRequest request,
                          HttpServletResponse response)
        throws IOException, ServletException {

        // Serve the requested resource, without the data content
        serveResource(request, response, false);

    }


    /**
     * Process a POST request for the specified resource.
     *
     * @param request The servlet request we are processing
     * @param response The servlet response we are creating
     *
     * @exception IOException if an input/output error occurs
     * @exception ServletException if a servlet-specified error occurs
     */
    protected void doPost(HttpServletRequest request,
                          HttpServletResponse response)
        throws IOException, ServletException {
        doGet(request, response);
    }
	
    /**
     * Serve the specified resource, optionally including the data content.
     *
     * @param request The servlet request we are processing
     * @param response The servlet response we are creating
     * @param content Should the content be included?
     *
     * @exception IOException if an input/output error occurs
     * @exception ServletException if a servlet-specified error occurs
     */
    protected void serveResource(HttpServletRequest request,
                                 HttpServletResponse response,
                                 boolean content)
        throws IOException, ServletException 
	{
		// Get them out of here!
		response.sendError(HttpServletResponse.SC_NOT_FOUND, 
						   request.getRequestURI());
		return;
	}
}


Compile this code by however you can manage it, and copy the class file to ${catalina.home}/server/classes/

Add the following to your ${catalina.home}/conf/web.xml file
  <!-- Load this servlet BEFORE the JSP servlet, set the JSP servlet's load-on-startup to 4 -->
  <servlet>
    <servlet-name>jsp-source-disclosure-blocker</servlet-name>
    <servlet-class>org.apache.catalina.servlets.GenericNotFoundServlet</servlet-class>
    <init-param>
      <param-name>logVerbosityLevel</param-name>
      <param-value>WARNING</param-value>
    </init-param>
    <load-on-startup>3</load-on-startup>
  </servlet>

  ...
  <!-- Place ABOVE the 'jsp' servlet mapping -->
  <servlet-mapping>
    <servlet-name>jsp-source-disclosure-blocker</servlet-name>
    <url-pattern>/servlet/default/*</url-pattern>
  </servlet-mapping>
I am not sure if this is a wonderful solution or not, or it will work for any type 1 situation, but it was quick & effective for the most part. I hope this helps you legacy folks!

Brad Plies has also added:

Tim Moore of blackboard.com has noted that an additional mapping is needed:
 <servlet-mapping>
    <servlet-name>jsp-source-disclosure-blocker</servlet-name>
    <url-pattern>/servlet/org.apache.catalina.servlets.DefaultServlet/*</url-pattern>
  </servlet-mapping>
Alternatively, you could explicitly map each of your Servlets and disable the InvokerServlet as recommended by the Apache Group.

Another solution is to write your own Servlet that extends the DefaultServlet (get the source) and overrides the culprit methods to not fetch .jsp files. Use that as the type of the default servlet entry in {catalina.home}/conf/web.xml.
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.