Skip to content

Commit 392f0ff

Browse files
committed
added xss vulnerability scanner
1 parent 3ad3f8b commit 392f0ff

File tree

4 files changed

+104
-0
lines changed

4 files changed

+104
-0
lines changed

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
2020
- [How to Make a Subdomain Scanner in Python](https://www.thepythoncode.com/article/make-subdomain-scanner-python). ([code](ethical-hacking/subdomain-scanner))
2121
- [How to Use Steganography to Hide Secret Data in Images in Python](https://www.thepythoncode.com/article/hide-secret-data-in-images-using-steganography-python). ([code](ethical-hacking/steganography))
2222
- [How to Brute-Force SSH Servers in Python](https://www.thepythoncode.com/article/brute-force-ssh-servers-using-paramiko-in-python). ([code](ethical-hacking/bruteforce-ssh))
23+
- [How to Build a XSS Vulnerability Scanner in Python](https://www.thepythoncode.com/article/make-a-xss-vulnerability-scanner-in-python). ([code](ethical-hacking/xss-vulnerability-scanner))
2324

2425
- ### [Machine Learning](https://www.thepythoncode.com/topic/machine-learning)
2526
- ### [Natural Language Processing](https://www.thepythoncode.com/topic/nlp)

Diff for: ethical-hacking/xss-vulnerability-scanner/README.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# [How to Build a XSS Vulnerability Scanner in Python](https://www.thepythoncode.com/article/make-a-xss-vulnerability-scanner-in-python)
2+
To run this:
3+
- `pip3 install -r requirements.txt`
4+
- To detect XSS on `https://www.example.com`:
5+
```
6+
python xss_scanner https://www.example.com
7+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
requests
2+
bs4
+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import requests
2+
from pprint import pprint
3+
from bs4 import BeautifulSoup as bs
4+
from urllib.parse import urljoin
5+
6+
7+
def get_all_forms(url):
8+
"""Given a `url`, it returns all forms from the HTML content"""
9+
soup = bs(requests.get(url).content, "html.parser")
10+
return soup.find_all("form")
11+
12+
13+
def get_form_details(form):
14+
"""
15+
This function extracts all possible useful information about an HTML `form`
16+
"""
17+
details = {}
18+
# get the form action (target url)
19+
action = form.attrs.get("action").lower()
20+
# get the form method (POST, GET, etc.)
21+
method = form.attrs.get("method", "get").lower()
22+
# get all the input details such as type and name
23+
inputs = []
24+
for input_tag in form.find_all("input"):
25+
input_type = input_tag.attrs.get("type", "text")
26+
input_name = input_tag.attrs.get("name")
27+
inputs.append({"type": input_type, "name": input_name})
28+
# put everything to the resulting dictionary
29+
details["action"] = action
30+
details["method"] = method
31+
details["inputs"] = inputs
32+
return details
33+
34+
35+
def submit_form(form_details, url, value):
36+
"""
37+
Submits a form given in `form_details`
38+
Params:
39+
form_details (list): a dictionary that contain form information
40+
url (str): the original URL that contain that form
41+
value (str): this will be replaced to all text and search inputs
42+
Returns the HTTP Response after form submission
43+
"""
44+
# construct the full URL (if the url provided in action is relative)
45+
target_url = urljoin(url, form_details["action"])
46+
# get the inputs
47+
inputs = form_details["inputs"]
48+
data = {}
49+
for input in inputs:
50+
# replace all text and search values with `value`
51+
if input["type"] == "text" or input["type"] == "search":
52+
input["value"] = value
53+
input_name = input.get("name")
54+
input_value = input.get("value")
55+
if input_name and input_value:
56+
# if input name and value are not None,
57+
# then add them to the data of form submission
58+
data[input_name] = input_value
59+
60+
if form_details["method"] == "post":
61+
return requests.post(target_url, data=data)
62+
else:
63+
# GET request
64+
return requests.get(target_url, params=data)
65+
66+
67+
def scan_xss(url):
68+
"""
69+
Given a `url`, it prints all XSS vulnerable forms and
70+
returns True if any is vulnerable, False otherwise
71+
"""
72+
# get all the forms from the URL
73+
forms = get_all_forms(url)
74+
print(f"[+] Detected {len(forms)} forms on {url}.")
75+
js_script = "<Script>alert('hi')</scripT>"
76+
# returning value
77+
is_vulnerable = False
78+
# iterate over all forms
79+
for form in forms:
80+
form_details = get_form_details(form)
81+
content = submit_form(form_details, url, js_script).content.decode()
82+
if js_script in content:
83+
print(f"[+] XSS Detected on {url}")
84+
print(f"[*] Form details:")
85+
pprint(form_details)
86+
is_vulnerable = True
87+
# won't break because we want to print other available vulnerable forms
88+
return is_vulnerable
89+
90+
91+
if __name__ == "__main__":
92+
import sys
93+
url = sys.argv[1]
94+
print(scan_xss(url))

0 commit comments

Comments
 (0)