Burp Suite vs CSRF Tokens

Recently I wrote a quick HowTo about dealing with using Burp Suite against an application that invalidates your session whenever it spots a potential malicious payload. I wrote that a Burp Macro that can perform Automatic Reauthentication can overcome that issue. Another common issue that gets in the way of performing penetration tests against mobile applications is having to deal with anti cross-site request forgery tokens. These are tokens that an application embeds in a response and expects to see in the body of the subsequent request, if the token is ever missing or incorrect the request is ignored. This interferes terribly with Burp Suite tools such as repeater, intruder and scanner as by default these don’t handle the tokens and therefore the requests are all ignored. I get around this issue through the use of simple custom burp extensions and I wanted to share some notes about how surprisingly simple this is!

These are much easier to write than I initially expected and can be a few lines long to many hundreds of lines depending on the complexity of what you’re trying to achieve, but for the simple task of pulling a token and updating a request with it, it’s as easy as pie. Extensions can be written in Java, Python or Ruby. Python’s my choice of language and this requires a small change to Burp but don’t panic, I’ve already written about how to add Python to burp and how to install a custom extension, in this article I’m going to introduce writing extensions, specifically for dealing with CSRF tokens but the lesson is a good introduction into general extension writing.

The code is available here. Although below I’ll run you through how it works.

The extension is really simple and all it does is pull CSRF tokens out of responses and place them into the next request. It runs continually in the background and it works with Responder, Intruder and Scanner automatically. It only has four small functions:

registerExtenderCallbacks: simply sets up the extension, gives it a name and prints to the output window when initialisation is complete.

processHttpMessage: runs for every HTTP message that Burp’s HTTP listener gets and it determines which tool that messages is coming from. If it’s coming from proxy it’s completely ignored but if it’s coming from another tool such as repeater or scanner then the request is tampered with. This function check to see if it’s a request or a response and sends the message to be tampered with to either processRequest or processResponse as appropriate.

processResponse: this is the function that finds the token in the response body and holds on to it so that it can be embedded in later requests to the protected function. It outputs if it found a token or not to make debugging easier.

processRequest: this function takes the token found by processResponse and places it silently in the request as it goes out. It’s important to note that tools like active scanner and repeater won’t show the fact that the token was modified because it happens silently, but a good way to check that everything is working as it should is to use the burp extension Logger++ which will show exactly how the messages are being modified, so you can simply scroll through the output message at a time and see each token being pulled from a response and placed into the next request. Remember to run tools like spider, repeater and intruder in single thread mode so that the right token is used at the right time.

The extension detects tokens by looking for something in the response that looks like this:

<input type="hidden" name="csrft" value="1a79a4d60de6718e8e5b326e338ae533">

“csrft” is the default name the token is expected to have in responses but you can change this to anything you like by editing the following line:

csrfregex = re.compile(r"name='csrft's+value='(.*?)'")

If your target application uses a different name for the token shown in the response body, then just change the code of the extension above, where it says csrft just put the name of your token! Also watch out for the speech marks, here we’re saying that the name and value are delimited by apostrophes, ‘ , although your application might use quotes, ” , so you might have to tweak that too.

At first people are often put off by the potentially vast complexities of Regular Expressions, but take a quick look at the above and you can see, all it does is scan the page until it sees that name=”csrft” section and then simply grabs the value for the token (and ultimately holds that value in a variable for later use). The extension will print to its output window (found under the “Extender” tab under the “Extensions” sub-tab) for every request that’s sent from any of the Burp tools; the extension will print whether or not a token was observed in the response. If a token was spotted it holds on to it until the next request is sent and updates the request with the proper token! That’s it, simple.

The way the update works is another simple Regular Expression:

updatedBody = re.sub(r'csrft=.*?&', 'csrft={0}&'.format(BurpExtender.discoveredToken), requestBody)

Here all it does is look for the parameter “csrft” in the outgoing request and silently changes the value to be the one found in the response body! Again all you have to do is change where I’ve put csrft with the name of the parameter tokens are sent in and that’s it! A quick note however is that this extension uses the seperating & to determine the end of the token value, so it expects your request body to look something like this:

csrft=1a79a4d60de6718e8e5b326e338ae533&

That’s it! That a simple example extension and a quick run through of how it works. Hopefully it’ll be useful to some people as a standalone took for dealing with tokens when trying to scan targets and useful to others as an introduction into just how simple writing burp extensions is!

The code is available here.