Adding Anti-CSRF Support to Burp Suite Intruder

In the web application penetration testing industry, Burp Suite is considered a must-have tool – it includes an intercepting proxy, both active and passive web vulnerability scanners, crawler, session ID analysis tools and various other useful features, all under a single application. One of Burp's best features is the Intruder, a tool which allows the tester to provide a list of values which should be sent to the application as parameter values. By providing values which trigger SQL errors or inject Javascript into the resulting page, one can easily determine if and how the application is doing filtering on the parameters, and whether it is vulnerable to a given issue.

Intruder

Burp's Intruder works perfectly when the application responds to those requests as if they came from the user. The screenshot above shows the submission of the following HTML form:

<formaction="/CSRFGuardTestAppVulnerable/HelloWorld"method="POST"name="first"><inputtype="text"value="SpiderLabs"name="name"><inputtype="submit"value="submit"name="submit"></form>

However, modern application frameworks are adding support for Anti-CSRF (Cross-Site Request Forgery) techniques, which protect the application from forged requests such as those Burp uses. The most commonly implemented prevention measure is the Synchronizer Token Pattern, which adds a parameter with a random value to all forms generated by the application for a given user session, and validates this token when the form is submitted. For example:

<formaction="/CSRFGuardTestApp/HelloWorld"method="POST"name="first"><inputtype="text"value="SpiderLabs"name="name"><inputtype="submit"value="submit"name="submit"><inputtype="hidden"value="Z0XN-1FRF-975E-GB9F-GGQM-L2RC-04H1-GKHQ"name="OWASP_CSRFTOKEN"></form>

Because the OWASP_CSRFTOKEN parameter will change between every submission, the Intruder will not work, as it expects the application to respond to the request as if they came from the user. The solution is rather simple: instead of simply feeding a set of values to the parameters being tested, we need to have the Intruder populate the Anti-CSRF token parameter from the form page.

Intruder_regular

This changes the default behavior of the Intruder tool quite a bit. First, it must know which parameter represents the Anti-CSRF token in the request. While many frameworks will use parameter names that include the "csrf" string, this can be configured per application, and thus we cannot rely on automatic detection. Second, it means the Intruder must make twice the number of requests it would normally perform: one to fetch the form page, which contains the Anti-CSRF token embedded in it, and a second one to actually submit the form with the parameter values provided by the tester. We will address both issues by developing a Burp extension called CSRF Intruder.

Burp offers an extensibility API, called Burp Extender, which allows us to hook into various points in the application, including the UI and the request interception engine. The first thing we need to do is create a Java class which will host our extension.

package burp;import spiderlabs.burp.intruder.CSRFIntruder;publicclass BurpExtender {private IBurpExtenderCallbacks callbacks;private CSRFIntruder csrfIntruder;publicvoid registerExtenderCallbacks(IBurpExtenderCallbacks callbacks){this.callbacks = callbacks;this.csrfIntruder =new CSRFIntruder(this.callbacks);this.callbacks.registerMenuItem("CSRF Intruder",this.csrfIntruder);this.callbacks.issueAlert(String.format("Starting up CSRF Intruder extension [%s]",this.getClass().getCanonicalName()));}publicvoid processHttpMessage(java.lang.String toolName,boolean messageIsRequest,        IHttpRequestResponse messageInfo){/* Intercept Intruder requests and check if they came from CSRF Intruder */if(toolName.equals("intruder")&& messageIsRequest)this.callbacks.issueAlert("TODO: Intercept CSRF Intruder requests");}}

The registerExtenderCallbacks() method acts as the extension constructor, and is the first method called by Burp when the extension is loaded. It provides us with a IBurpExtenderCallbacks instance, which we use to create a new context menu entry for our CSRF Intruder handler. We also implement a processHttpMessage() method, which we will use to intercept Intruder requests and modify the Anti-CSRF token velues before they are sent to the remote application.

How does Burp use this class? It must obey a series of restrictions before Burp can find and use it:

  • It must be in package burp;
  • It must be named BurpExtender;
  • It must implement at least one of the methods in interface IBurpExtender;
  • Burp must be executed with the JVM classpath pointing to our BurpExtender class:
    java -classpath burp.jar;BurpProxyExtender.jar burp.StartBurp

If these criteria are met, then when Burp starts up our CSRF Intruder extension message should show up in the Alerts tab.

Burp_alerts
We can now right-click everywhere where a "Send to [...]" menu entry is displayed and click on "CSRF Intruder".

Csrf_intruder_context_menu

Clicking on the CSRF Intruder menu entry will trigger the handler in our CSRFIntruder class, shown below:

package spiderlabs.burp.intruder;import javax.swing.JOptionPane;import spiderlabs.burp.intruder.gui.CSRFConfigurationDialog;import burp.IBurpExtenderCallbacks;import burp.IHttpRequestResponse;import burp.IMenuItemHandler;publicclass CSRFIntruder implements IMenuItemHandler {private IBurpExtenderCallbacks callbacks;public CSRFIntruder(IBurpExtenderCallbacks callbacks){this.callbacks = callbacks;}@Override    publicvoid menuItemClicked(String caption, IHttpRequestResponse[] messageInfo){try{            IHttpRequestResponse message = messageInfo[0];String refererUrl =newString();for(String header:this.callbacks.getHeaders(message.getRequest())){System.out.println(header);if(header.startsWith("Referer:"))                    refererUrl = header.split(":\\s")[1];}String parameters[][]=this.callbacks.getParameters(message.getRequest());            CSRFIntruderConfiguration configuration =                    CSRFConfigurationDialog.getConfigurationFromDialog(refererUrl, parameters);this.callbacks.issueAlert(configuration.toString());}catch(Exception exception){this.callbacks.issueAlert(String.format("Error while obtaining request URL: %s",                    exception.toString()));}}}

The menuItemClicked() handler does two things: first, it fetches the value of the Referer header (if present) from the request the user right-clicked on and uses it as the suggested source form URL, that is, the place where we can find the Anti-CSRF token values; next, it obtain a list of all parameters in that request. It then sends those to a CSRFConfigurationDialog, which displays the URL and parameters, and waits for the user to configure the Anti-CSRF parameters.

Csrf_intruder_configuration
When the user provides the URL and the token parameter to be used, we already have all the information necessary to start up Intruder and manipulate its requests. This will come on a second post.

Trustwave reserves the right to review all comments in the discussion below. Please note that for security and other reasons, we may not approve comments containing links.