Created
October 14, 2015 20:33
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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