Skip to content

Instantly share code, notes, and snippets.

@averagesecurityguy
Created October 14, 2015 20:33
Show Gist options
  • Save averagesecurityguy/b79fd9605e1f9485f952 to your computer and use it in GitHub Desktop.
Save averagesecurityguy/b79fd9605e1f9485f952 to your computer and use it in GitHub Desktop.
Burp Extension to Extract CSRF Token from Response and Insert it into Next Request
# I was testing a web app recently where each POST request updated the session cookie
# and generated a new CSRF token in a hidden input field in the body of the response.
# By default, Burp's Session handling rules will only use the cookie jar for Spider
# and Scanner. I modified the rules to use the cookie jar for Intruder and Repeater
# as well. In addition, Burp will only update the cookie jar from Proxy and Scanner
# so I had to allow Repeater, Spider, and Intruder to update the cookie jar as well.
# This allowed me to use a fresh cookie with each request as required by the app.
#
# To get a fresh CSRF token with each request I had to write an extension. The
# extension processes any responses that it receives from any tool except Proxy and
# uses regex to extract the CSRF token. It then stores the token to be added to any
# requests that are processed. Again regex is used to substitue the request's CSRF
# token with the latest token. This worked well but would lead to the occaisonal
# session logout, so I created a session handling rule to run the login macro whenever
# I was logged out.
#
# All of this together allowed me to use Burp as I normally would with one exception,
# I had to do everything singe threaded to ensure I was always using the latest cookie
# and CSRF token. Fortunately, this was a small web app.
from burp import IBurpExtender
from burp import IHttpListener
import re
csrf_re = re.compile(r'name="csrfToken"\s+value="(.*?)" />')
class BurpExtender(IBurpExtender, IHttpListener):
csrf = ''
def registerExtenderCallbacks(self, callbacks):
self._callbacks = callbacks
self._helpers = callbacks.getHelpers()
callbacks.setExtensionName("CSRF Extract and Send")
callbacks.registerHttpListener(self)
return
def getBody(self, rawMessage, parsedMessage):
return self._helpers.bytesToString(rawMessage[parsedMessage.getBodyOffset():])
def toString(self, byteArray):
return self._helpers.bytesToString(byteArray)
def parseResponse(self, currentMessage):
response = currentMessage.getResponse()
parsedResponse = self._helpers.analyzeResponse(response)
respBody = self.getBody(response, parsedResponse)
# Extract the CSRF token from the body
m = csrf_re.search(respBody)
if m is not None:
BurpExtender.csrf = m.group(1)
def parseRequest(self, currentMessage):
request = currentMessage.getRequest()
parsedRequest = self._helpers.analyzeRequest(request)
reqBody = self.getBody(request, parsedRequest)
# print('\nOriginal Request:\n{0}'.format(self.toString(request)))
# Update the CSRF token in the body.
if BurpExtender.csrf != '':
newBody = re.sub(r'csrfToken=.*?&', 'csrfToken={0}&'.format(BurpExtender.csrf), reqBody)
else:
newBody = reqBody
# Build new request
newRequest = self._helpers.buildHttpMessage(parsedRequest.getHeaders(), newBody)
# print('Modified Request:\n{0}'.format(self.toString(newRequest)))
currentMessage.setRequest(newRequest)
def processHttpMessage(self, toolFlag, messageIsRequest, currentMessage):
if toolFlag != self._callbacks.TOOL_PROXY:
if messageIsRequest:
self.parseRequest(currentMessage)
else:
self.parseResponse(currentMessage)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment