-
-
Save babywyrm/2e0cca7d933cf9ddcade851f4e4c6e8f to your computer and use it in GitHub Desktop.
Burp Python Scripter scripts
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
import sys | |
# Provides introspection into the Python Scripter API. | |
apis = ('extender', 'callbacks', 'helpers', 'toolFlag', 'messageIsRequest', 'messageInfo') | |
funcs = (type, dir) | |
if messageIsRequest: | |
for api in apis: | |
print('\n{}:\n{}'.format(api, '='*len(api))) | |
for func in funcs: | |
print('\n{}:\n'.format(func.__name__)) | |
try: | |
print(func(locals()[api])) | |
except Exception as e: | |
print(func(globals()[api])) | |
# *********************************************** | |
from pyscripter_utils import CustomIssue | |
import re | |
import sys | |
# Adds custom passive audit checks. | |
# Requires pyscripter_utils.py to be loaded with Burp. | |
if not messageIsRequest: | |
if toolFlag in (callbacks.TOOL_PROXY,): | |
if callbacks.isInScope(messageInfo.getUrl()): | |
response = messageInfo.getResponse() | |
# Checks for autocomplete on text form fields. | |
results = re.findall(r'(<input [^>]*>)', response) | |
for result in results: | |
if re.search(r'''type=['"]text['"]''', result) and not re.search(r'autocomplete', result): | |
issue = CustomIssue( | |
BasePair=messageInfo, | |
IssueName='Text field with autocomplete enabled', | |
IssueDetail='The following text field has autocomplete enabled:\n\n<ul><li>' + result.replace('<', '<').replace('>', '>') + '</li></ul>', | |
Severity='Low', | |
) | |
callbacks.addScanIssue(issue) | |
# Checks for verbose headers. | |
bad_headers = ('server', 'x-powered-by', 'x-aspnet-version') | |
headers = helpers.analyzeResponse(messageInfo.getResponse()).getHeaders() | |
for header in headers: | |
name = header.split(':')[0] | |
if name.lower() in bad_headers: | |
issue = CustomIssue( | |
BasePair=messageInfo, | |
IssueName='Verbose header', | |
IssueDetail='The following HTTP response header may disclose sensitive information:\n\n<ul><li>' + header + '</li></ul>', | |
Severity='Low', | |
) | |
callbacks.addScanIssue(issue) | |
# *********************************************** | |
import re | |
import sys | |
# Extracts multiple instances of a REGEX capture group from responses. | |
pattern = r'<regex>' | |
if not messageIsRequest: | |
response = messageInfo.getResponse() | |
matches = re.findall(pattern, response) | |
for match in matches: | |
print(match) | |
# *********************************************** | |
import re | |
# Replaces the body of a response from a matched URL. | |
# Great for swapping SPA UI build definitions between user roles. | |
url_pattern = r'<regex for response URL>' | |
body = r'''<new body>''' | |
if not messageIsRequest: | |
url = messageInfo.url.toString() | |
if re.search(url_pattern, url): | |
response = messageInfo.getResponse() | |
headers = helpers.analyzeResponse(response).getHeaders() | |
new_response = helpers.buildHttpMessage(headers, helpers.stringToBytes(body)) | |
messageInfo.setResponse(new_response) | |
print('Response replaced from: {}'.format(url)) | |
# *********************************************** | |
import sys | |
import re | |
from hashlib import md5 | |
# Overwrites a previously attempted password signature to bypass client-side anti-automation logic. | |
# Not sure why anyone would do this, but they did, or this wouldn't be a thing. | |
if messageIsRequest: | |
if toolFlag in (callbacks.TOOL_INTRUDER,): | |
request = helpers.bytesToString(messageInfo.getRequest()) | |
if '&nonce=' in request: | |
nonce = re.search(r'&nonce=([^&]*)', request).group(1) | |
password = re.search(r'&password=([^&]*)', request).group(1) | |
token = md5(password+nonce).hexdigest() | |
orig_token = re.search(r'&token=([^\s]*)', request).group(1) | |
request = request.replace(orig_token, token) | |
messageInfo.setRequest(helpers.stringToBytes(request)) | |
# *********************************************** | |
# Fetches and replaces a Bearer token in the current request. | |
def get_new_token(): | |
url = '<url>' | |
username = '<username>' | |
password = '<password>' | |
import urllib2 | |
import json | |
data = { | |
'username': username, | |
'password': password, | |
} | |
req = urllib2.Request(url) | |
req.add_header('Content-Type', 'application/json') | |
response = urllib2.urlopen(req, json.dumps(data)) | |
data = json.load(response) | |
token = data.get('token', '') | |
print('New token obtained.') | |
return token | |
# only apply to repeater | |
if toolFlag == callbacks.TOOL_REPEATER: | |
# only apply to requests | |
if messageIsRequest: | |
# obtain a new token | |
new_token = get_new_token() | |
# remove any existing Authorization header | |
request = helpers.analyzeRequest(messageInfo) | |
headers = request.getHeaders() | |
for header in headers: | |
if header.startswith('Authorization'): | |
headers.remove(header) | |
break | |
# add a new Authorization header with the new token | |
headers.add('Authorization: Bearer {}'.format(new_token)) | |
body = messageInfo.getRequest()[request.getBodyOffset():] | |
new_request = helpers.buildHttpMessage(headers, body) | |
messageInfo.setRequest(new_request) | |
print('Token replaced.') | |
# *********************************************** | |
# Removes authentication information from the current request. | |
header_names = ['Cookie', 'Authorization'] | |
# only apply to target | |
if toolFlag == callbacks.TOOL_TARGET: | |
# only apply to requests | |
if messageIsRequest: | |
request = helpers.analyzeRequest(messageInfo) | |
headers = request.getHeaders() | |
for header_name in header_names: | |
for header in headers: | |
if header.startswith(header_name): | |
headers.remove(header) | |
break | |
body = messageInfo.getRequest()[request.getBodyOffset():] | |
new_request = helpers.buildHttpMessage(headers, body) | |
messageInfo.setRequest(new_request) | |
print('Headers removed: {}'.format(', '.join(header_names))) |
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
from burp import IScanIssue | |
class CustomIssue(IScanIssue): | |
def __init__(self, BasePair, Confidence='Certain', IssueBackground=None, IssueDetail=None, IssueName='Python Scripter generated issue', RemediationBackground=None, RemediationDetail=None, Severity='High'): | |
self.HttpMessages=[BasePair] # list of HTTP Messages | |
self.HttpService=BasePair.getHttpService() # HTTP Service | |
self.Url=BasePair.getUrl() # Java URL | |
self.Confidence = Confidence # "Certain", "Firm" or "Tentative" | |
self.IssueBackground = IssueBackground # String or None | |
self.IssueDetail = IssueDetail # String or None | |
self.IssueName = IssueName # String | |
self.IssueType = 134217728 # always "extension generated" | |
self.RemediationBackground = RemediationBackground # String or None | |
self.RemediationDetail = RemediationDetail # String or None | |
self.Severity = Severity # "High", "Medium", "Low", "Information" or "False positive" | |
def getHttpMessages(self): | |
return self.HttpMessages | |
def getHttpService(self): | |
return self.HttpService | |
def getUrl(self): | |
return self.Url | |
def getConfidence(self): | |
return self.Confidence | |
def getIssueBackground(self): | |
return self.IssueBackground | |
def getIssueDetail(self): | |
return self.IssueDetail | |
def getIssueName(self): | |
return self.IssueName | |
def getIssueType(self): | |
return self.IssueType | |
def getRemediationBackground(self): | |
return self.RemediationBackground | |
def getRemediationDetail(self): | |
return self.RemediationDetail | |
def getSeverity(self): | |
return self.Severity |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment