-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdom_xss_scanner.py
More file actions
130 lines (113 loc) · 5.36 KB
/
Copy pathdom_xss_scanner.py
File metadata and controls
130 lines (113 loc) · 5.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import argparse
from urllib.parse import urlparse
from selenium import webdriver
from selenium.common.exceptions import UnexpectedAlertPresentException
import os
import tempfile
import requests
from bs4 import BeautifulSoup
import urllib3
import threading
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def setup_driver():
"""Sets up the Selenium WebDriver.
Uses a temporary cache location and configures the browser to accept
insecure certificates so sites with TLS issues don't immediately fail.
"""
options = webdriver.ChromeOptions()
options.add_argument("--headless")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
# Accept insecure certs (useful for scanning dev sites or sites with cert problems)
options.add_argument("--ignore-certificate-errors")
options.add_argument("--allow-insecure-localhost")
options.set_capability('acceptInsecureCerts', True)
# Use a temporary, writable directory for the user data cache and also set XDG cache
user_data_dir = os.path.join(tempfile.gettempdir(), 'selenium_cache_xss')
os.makedirs(user_data_dir, exist_ok=True)
os.environ['XDG_CACHE_HOME'] = tempfile.gettempdir()
options.add_argument(f"--user-data-dir={user_data_dir}")
try:
return webdriver.Chrome(options=options)
except Exception as e:
print("[-] Could not start Selenium Chrome driver:", e)
print(" * Ensure Chrome and ChromeDriver are compatible and available on PATH.")
print(" * Ensure the process has write access to the cache/user-data directories or set XDG_CACHE_HOME to a writable dir.")
return None
def _heuristic_dom_scan(url):
"""Heuristic non-JS scan using static HTML analysis to detect DOM sink patterns."""
print("[*] Performing heuristic DOM analysis via static HTML fetch")
try:
r = requests.get(url, verify=False, timeout=12)
body = r.text
sinks = ['innerHTML', 'document.write', 'eval(', 'location.hash', 'location.href', 'document.location', 'window.location', 'setAttribute(']
found = [s for s in sinks if s in body]
if found:
print(f"[!] Heuristic: potential DOM sink patterns found: {', '.join(found)}")
print(" Note: this is not a definitive DOM-XSS proof. Use a JS-enabled browser for dynamic verification.")
else:
print("[-] Heuristic: no obvious DOM sink patterns found in page HTML.")
except Exception as e:
print(f"[-] Heuristic fetch failed: {e}")
def check_dom_xss(url, driver):
"""Appends a payload to the URL and checks for an alert, indicating DOM XSS.
Starts a heuristic static analysis in a separate thread immediately so we get
quick indications while Selenium runs (if available).
"""
# A simple payload that should trigger an alert if vulnerable.
payload = "<img src=x onerror=alert('VULNERABLE_DOM_XSS')>"
test_url = f"{url}#{payload}"
print(f"[*] Testing for DOM-based XSS with URL: {test_url}")
# Start heuristic scan in background (non-blocking)
try:
h_thread = threading.Thread(target=_heuristic_dom_scan, args=(url,))
h_thread.daemon = True
h_thread.start()
except Exception as e:
print(f"[-] Could not start heuristic background scan: {e}")
try:
if not driver:
print("[-] Selenium driver not available; relying on heuristic scan results.")
# Wait briefly for heuristic to complete or at least start producing output
h_thread.join(timeout=5)
return
driver.get(test_url)
# This line will raise an exception if an alert is present
driver.title
print("[-] No alert was triggered. Site does not appear to be vulnerable to this payload.")
except UnexpectedAlertPresentException:
print("[+] VULNERABILITY: DOM-based XSS detected! An alert was triggered by the payload.")
try:
alert = driver.switch_to.alert
alert.accept() # Close the alert to allow the script to finish
except Exception:
pass
except Exception as e:
msg = str(e)
print(f"[-] An error occurred during the test: {msg}")
# If it's an SSL or driver startup problem, note that heuristic is running
if 'SSL' in msg or 'ERR_SSL' in msg or 'certificate' in msg.lower() or 'permission' in msg.lower():
print(" * Selenium navigation failed; heuristic static scan is running in background.")
else:
print(" * Selenium encountered an error; heuristic static scan is running in background.")
finally:
# Give heuristic a short time to finish and return control
try:
h_thread.join(timeout=10)
if h_thread.is_alive():
print("[*] Heuristic scan still running; results will be printed when ready.")
except Exception:
pass
def main():
parser = argparse.ArgumentParser(description="Basic scanner for DOM-based XSS.")
parser.add_argument("url", help="The target URL or domain to check (e.g., example.com).")
args = parser.parse_args()
target_url = args.url
if not urlparse(target_url).scheme:
target_url = "http://" + target_url
driver = setup_driver()
if driver:
check_dom_xss(target_url, driver)
driver.quit()
if __name__ == "__main__":
main()