Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 26 additions & 18 deletions DetectDynamicJS.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def registerExtenderCallbacks(self, callbacks):
# Define some constants
self.validStatusCodes = [200]
self.ifields = ['cookie', 'authorization']
self.possibleFileEndings = ["js", "jsp", "json"]
self.possibleFileEndings = ["js", "json"]
self.possibleContentTypes = [
"javascript", "ecmascript", "jscript", "json"]
self.ichars = ['{', '<']
Expand All @@ -72,12 +72,15 @@ def doPassiveScan(self, baseRequestResponse):
# for this test.
scan_issues = []

if not self.isGet(baseRequestResponse.getRequest()):
baseRequestResponse = self.switchMethod(baseRequestResponse)
if (not self.isScannableRequest(baseRequestResponse) or
not self.isScript(baseRequestResponse) or
not self.containsAuthenticationCharacteristics(baseRequestResponse) or
self.isProtected(baseRequestResponse)):
return None

if not self.isGet(baseRequestResponse.getRequest()):
baseRequestResponse = self.switchMethod(baseRequestResponse)

newRequestResponse = self.sendUnauthenticatedRequest(baseRequestResponse)
issue = self.compareResponses(newRequestResponse, baseRequestResponse)
if not issue:
Expand All @@ -94,6 +97,19 @@ def doPassiveScan(self, baseRequestResponse):
scan_issues.append(issue)
return scan_issues

def containsAuthenticationCharacteristics(self, requestResponse):
"""
Check whether the request contains ambient authority information
returns a boolean
"""
reqHeaders = self._helpers.analyzeRequest(requestResponse).getHeaders()
newHeaders = []
for header in reqHeaders:
headerName = header.split(':')[0].lower()
if headerName in self.ifields:
return True
return False

def sendUnauthenticatedRequest(self, requestResponse):
"""
Send the request without ambient authority information
Expand Down Expand Up @@ -156,24 +172,14 @@ def isScannableRequest(self, requestResponse):
"""
response = requestResponse.getResponse()
responseInfo = self._helpers.analyzeResponse(response)
return (self.hasValidStatusCode(responseInfo.getStatusCode()) and
self.hasAuthenticationCharacteristic(requestResponse))
return self.hasValidStatusCode(responseInfo.getStatusCode())

def hasValidStatusCode(self, statusCode):
"""
Checks the status code of the request
"""
return statusCode in self.validStatusCodes

def hasAuthenticationCharacteristic(self, requestResponse):
"""
Detects whether the request contains some kind of authentication
information.
"""
reqHeaders = self._helpers.analyzeRequest(requestResponse).getHeaders()
hfields = [h.split(':')[0] for h in reqHeaders]
return any(h for h in self.ifields if h not in str(hfields).lower())

def stripAuthenticationCharacteristics(self, requestResponse):
"""
Strip possible ambient authority information.
Expand All @@ -199,14 +205,16 @@ def hasScriptFileEnding(self, requestResponse):
Checks for common script file endings
"""
url = self._helpers.analyzeRequest(requestResponse).getUrl()
fileEnding = ".totallynotit"
extractedFileEnding = ".totallynotit"
urlSplit = str(url).split("/")
if len(urlSplit) != 0:
fileName = urlSplit[len(urlSplit) - 1]
fileNameSplit = fileName.split(".")
fileEnding = fileNameSplit[len(fileNameSplit) - 1]
fileEnding = fileEnding.split("?")[0]
return any(fileEnd in fileEnding for fileEnd in self.possibleFileEndings)
extractedFileEnding = fileNameSplit.pop() # pop() returns last item of list when called without index
extractedFileEnding = extractedFileEnding.lower() # account for upper case letters
extractedFileEnding = extractedFileEnding.split("?")[0]
return extractedFileEnding in self.possibleFileEndings # will not detect, e.g., 'jspa' as script file ending


def hasScriptContentType(self, response):
""" Checks for common content types, that could be scripts """
Expand Down