Skip to content

Commit

Permalink
Added a method for creating a custom issue, which encouraged several …
Browse files Browse the repository at this point in the history
…other changes.
  • Loading branch information
lanmaster53 committed Aug 22, 2019
1 parent e2ed348 commit 2d34653
Showing 1 changed file with 61 additions and 40 deletions.
101 changes: 61 additions & 40 deletions pyscripter.py
Expand Up @@ -8,14 +8,22 @@ def __init__(self, extender, callbacks, helpers, toolFlag, messageIsRequest, mes
self.toolFlag = toolFlag
self.messageIsRequest = messageIsRequest
self.messageInfo = messageInfo
self.verbose = False
self.in_scope = self.callbacks.isInScope(self.messageInfo.getUrl())
self.debug = False

def debug(self, message):
def _in_scope(self):

in_scope = self.callbacks.isInScope(self.messageInfo.getUrl())
mode = 'Response' if self.messageIsRequest else 'Request'
scope = 'in scope' if in_scope else 'not in scope'
url = self.messageInfo.url.toString()
self._debug('{} {}: {}'.format(mode, scope, url))
return in_scope

def _debug(self, message):
"""Provides an interface for verbose output."""

if self.verbose:
print(message)
if self.debug:
print('[DEBUG] {}'.format(message))

def help(self):
"""Displays this help interface."""
Expand All @@ -37,15 +45,15 @@ def introspect(self):
for func in funcs:
print('\n{}:\n'.format(func.__name__))
print(func(getattr(self, api)))
self.debug('Introspection complete.')
self._debug('Introspection complete.')

def remove_header(self, headers, header_name):
"""Removes a specific header from a list of headers."""

for header in headers:
if header.startswith(header_name):
headers.remove(header)
self.debug('Header removed: {}'.format(header_name))
self._debug('Header removed: {}'.format(header_name))
break
return headers

Expand All @@ -60,7 +68,7 @@ def remove_headers(self, header_names):
body = self.messageInfo.getRequest()[request.getBodyOffset():]
new_request = self.helpers.buildHttpMessage(headers, body)
self.messageInfo.setRequest(new_request)
self.debug('Headers removed: {}'.format(', '.join(header_names)))
self._debug('Headers removed: {}'.format(', '.join(header_names)))

def replace_bearer_token(self, new_token):
"""Replaces a Bearer token in the current request."""
Expand All @@ -73,7 +81,7 @@ def replace_bearer_token(self, new_token):
body = self.messageInfo.getRequest()[request.getBodyOffset():]
new_request = self.helpers.buildHttpMessage(headers, body)
self.messageInfo.setRequest(new_request)
self.debug('Token replaced.')
self._debug('Token replaced.')

def enable_passive_audit_checks(self):
"""Runs passive check methods against in-scope proxy traffic.
Expand All @@ -84,11 +92,11 @@ def enable_passive_audit_checks(self):
and the method must receive it as an argument.
"""

if self.toolFlag == self.callbacks.TOOL_PROXY and self.in_scope:
self.debug('Passive checks enabled.')
if self.toolFlag == self.callbacks.TOOL_PROXY and self._in_scope():
self._debug('Passive checks enabled.')
methods =[x for x in dir(self.__class__) if x.startswith('_passive_')]
for method in methods:
mode = method.split('_')[1]
mode = method.split('_')[2]
if mode == 'request' and self.messageIsRequest:
request = self.messageInfo.getRequest()
getattr(self, method)(request)
Expand All @@ -104,14 +112,12 @@ def _passive_response_autocomplete_enabled(self, response):
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=self.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',
self.create_issue(
issue_name='Text field with autocomplete enabled',
issue_detail='The following text field has autocomplete enabled:\n\n<ul><li>' + result.replace('<', '&lt;').replace('>', '&gt;') + '</li></ul>',
severity='Low',
)
self.callbacks.addScanIssue(issue)
self.debug('Passive check applied: Autocomplete Enabled')
self._debug('Passive check applied: Autocomplete Enabled')

def _passive_response_verbose_headers(self, response):
"""Checks for verbose headers in a response."""
Expand All @@ -122,24 +128,39 @@ def _passive_response_verbose_headers(self, response):
name = header.split(':')[0]
# known bad headers
if name.lower() in bad_headers:
issue = CustomIssue(
BasePair=self.messageInfo,
IssueName='Verbose header',
IssueDetail='The following HTTP response header may disclose sensitive information:\n\n<ul><li>' + header + '</li></ul>',
Severity='Low',
self.create_issue(
issue_name='Verbose header',
issue_detail='The following HTTP response header may disclose sensitive information:\n\n<ul><li>' + header + '</li></ul>',
severity='Low',
)
self.callbacks.addScanIssue(issue)
# custom headers
elif name.lower().startswith('x-'):
issue = CustomIssue(
BasePair=self.messageInfo,
IssueName='Interesting header',
IssueDetail='The following HTTP response header may disclose sensitive information:\n\n<ul><li>' + header + '</li></ul>',
Severity='Low',
Confidence='Tentative',
self.create_issue(
issue_name='Interesting header',
issue_detail='The following HTTP response header may disclose sensitive information:\n\n<ul><li>' + header + '</li></ul>',
severity='Low',
confidence='Tentative',
)
self.callbacks.addScanIssue(issue)
self.debug('Passive check applied: Verbose Headers')
self._debug('Passive check applied: Verbose Headers')

def create_issue(self, issue_name, issue_detail, issue_background=None, remediation_detail=None, remediation_background=None, severity='High', confidence='Certain'):
"""Creates a Burp Suite issue.
Severity: High, Medium, Low, Information, False positive
Confidence: Certain, Firm, Tentative
"""

issue = CustomIssue(
BasePair=self.messageInfo,
IssueName=issue_name,
IssueDetail=issue_detail,
IssueBackground=issue_background,
RemediationDetail=remediation_detail,
RemediationBackground=remediation_background,
Severity=severity,
Confidence=confidence,
)
self.callbacks.addScanIssue(issue)

def extract_all_from_response(self, pattern):
"""Extracts multiple instances of a REGEX capture group from the
Expand Down Expand Up @@ -168,27 +189,27 @@ def replace_response_body(self, url_pattern, body):
headers = self.helpers.analyzeResponse(response).getHeaders()
new_response = self.helpers.buildHttpMessage(headers, self.helpers.stringToBytes(body))
self.messageInfo.setResponse(new_response)
self.debug('Response replaced from: {}'.format(url))
self._debug('Response replaced from: {}'.format(url))


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'):
def __init__(self, BasePair, IssueName='Python Scripter generated issue', IssueDetail=None, IssueBackground=None, RemediationDetail=None, RemediationBackground=None, Severity='High', Confidence='Certain'):

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.IssueName = IssueName # String
self.IssueDetail = IssueDetail # String or None
self.IssueBackground = IssueBackground # String or None
self.RemediationDetail = RemediationDetail # String or None
self.RemediationBackground = RemediationBackground # String or None
self.Severity = Severity # "High", "Medium", "Low", "Information" or "False positive"
self.Confidence = Confidence # "Certain", "Firm" or "Tentative"

def getHttpMessages(self):

Expand Down

0 comments on commit 2d34653

Please sign in to comment.