Skip to content

Instantly share code, notes, and snippets.

@babywyrm
Forked from lanmaster53/pyscripter-snippets.py
Created August 21, 2020 23:30
Show Gist options
  • Save babywyrm/2e0cca7d933cf9ddcade851f4e4c6e8f to your computer and use it in GitHub Desktop.
Save babywyrm/2e0cca7d933cf9ddcade851f4e4c6e8f to your computer and use it in GitHub Desktop.
Burp Python Scripter scripts
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('<', '&lt;').replace('>', '&gt;') + '</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)))
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