327 lines
11 KiB
Python
327 lines
11 KiB
Python
#!/usr/bin/env python
|
|
#!BruteXSS
|
|
#!Cross-Site Scripting Bruteforcer
|
|
#!Author: Shawar Khan
|
|
#!Site: https://shawarkhan.com
|
|
|
|
from string import whitespace
|
|
import httplib
|
|
import urllib
|
|
import socket
|
|
import urlparse
|
|
import os
|
|
import sys
|
|
import time
|
|
from colorama import init , Style, Back,Fore
|
|
import mechanize
|
|
import httplib
|
|
init()
|
|
banner = """
|
|
____ _ __ ______ ____
|
|
| __ ) _ __ _ _| |_ ___ \ \/ / ___/ ___|
|
|
| _ \| '__| | | | __/ _ \ \ /\___ \___ \
|
|
| |_) | | | |_| | || __/ / \ ___) |__) |
|
|
|____/|_| \__,_|\__\___| /_/\_\____/____/
|
|
|
|
BruteXSS - Cross-Site Scripting BruteForcer
|
|
|
|
Author: Shawar Khan - https://shawarkhan.com
|
|
|
|
Sponsored & Supported by Netsparker Web Application Security Scanner ( https://www.netsparker.com )
|
|
|
|
Note: Using incorrect payloads in the custom
|
|
wordlist may give you false positives so its
|
|
better to use the wordlist which is already
|
|
provided for positive results.
|
|
"""
|
|
def brutexss():
|
|
if os.name == 'nt':
|
|
os.system('cls')
|
|
else:
|
|
os.system('clear')
|
|
print banner
|
|
def again():
|
|
inp = raw_input("[?] [E]xit or launch [A]gain? (e/a)").lower()
|
|
if inp == 'a':
|
|
brutexss()
|
|
elif inp == 'e':
|
|
exit()
|
|
else:
|
|
print("[!] Incorrect option selected")
|
|
again()
|
|
grey = Style.DIM+Fore.WHITE
|
|
def wordlistimport(file,lst):
|
|
try:
|
|
with open(file,'r') as f: #Importing Payloads from specified wordlist.
|
|
print(Style.DIM+Fore.WHITE+"[+] Loading Payloads from specified wordlist..."+Style.RESET_ALL)
|
|
for line in f:
|
|
final = str(line.replace("\n",""))
|
|
lst.append(final)
|
|
except IOError:
|
|
print(Style.BRIGHT+Fore.RED+"[!] Wordlist not found!"+Style.RESET_ALL)
|
|
again()
|
|
def bg(p,status):
|
|
try:
|
|
b = ""
|
|
l = ""
|
|
lostatus = ""
|
|
num = []
|
|
s = len(max(p, key=len)) #list
|
|
if s < 10:
|
|
s = 10
|
|
for i in range(len(p)): num.append(i)
|
|
maxval = str(len(num)) #number
|
|
for i in range(s) : b = b + "-"
|
|
for i in range(len(maxval)):l = l + "-"
|
|
statuslen = len(max(status, key=len))
|
|
for i in range(statuslen) : lostatus = lostatus + "-"
|
|
if len(b) < 10 :
|
|
b = "----------"
|
|
if len(lostatus) < 14:
|
|
lostatus="--------------"
|
|
if len(l) < 2 :
|
|
l = "--"
|
|
los = statuslen
|
|
if los < 14:
|
|
los = 14
|
|
lenb=len(str(len(b)))
|
|
if lenb < 14:
|
|
lenb = 10
|
|
else:
|
|
lenb = 20
|
|
upb = ("+-%s-+-%s-+-%s-+")%(l,b,lostatus)
|
|
print(upb)
|
|
st0 = "Parameters"
|
|
st1 = "Status"
|
|
print("| Id | "+st0.center(s," ")+" | "+st1.center(los," ")+" |")
|
|
print(upb)
|
|
for n,i,d in zip(num,p,status):
|
|
string = (" %s | %s ")%(str(n),str(i));
|
|
lofnum = str(n).center(int(len(l))," ")
|
|
lofstr = i.center(s," ")
|
|
lofst = d.center(los," ")
|
|
if "Not Vulnerable" in lofst:
|
|
lofst = Fore.GREEN+d.center(los," ")+Style.RESET_ALL
|
|
else:
|
|
lofst = Fore.RED+d.center(los," ")+Style.RESET_ALL
|
|
print("| "+lofnum+" | "+lofstr+" | "+lofst+" |")
|
|
print(upb)
|
|
return("")
|
|
except(ValueError):
|
|
print(Style.BRIGHT+Fore.RED+"[!] Uh oh! No parameters in URL!"+Style.RESET_ALL)
|
|
again()
|
|
def complete(p,r,c,d):
|
|
print("[+] Bruteforce Completed.")
|
|
if c == 0:
|
|
print("[+] Given parameters are "+Style.BRIGHT+Fore.GREEN+"not vulnerable"+Style.RESET_ALL+" to XSS.")
|
|
elif c ==1:
|
|
print("[+] %s Parameter is "+Style.BRIGHT+Fore.RED+"vulnerable"+Style.RESET_ALL+" to XSS.")%c
|
|
else:
|
|
print("[+] %s Parameters are "+Style.BRIGHT+Fore.RED+"vulnerable"+Style.RESET_ALL+" to XSS.")%c
|
|
print("[+] Scan Result for %s:")%d
|
|
print bg(p,r)
|
|
again()
|
|
def GET():
|
|
try:
|
|
try:
|
|
grey = Style.DIM+Fore.WHITE
|
|
site = raw_input("[?] Enter URL:\n[?] > ") #Taking URL
|
|
if 'https://' in site:
|
|
pass
|
|
elif 'http://' in site:
|
|
pass
|
|
else:
|
|
site = "http://"+site
|
|
finalurl = urlparse.urlparse(site)
|
|
urldata = urlparse.parse_qsl(finalurl.query)
|
|
domain0 = '{uri.scheme}://{uri.netloc}/'.format(uri=finalurl)
|
|
domain = domain0.replace("https://","").replace("http://","").replace("www.","").replace("/","")
|
|
print (Style.DIM+Fore.WHITE+"[+] Checking if "+domain+" is available..."+Style.RESET_ALL)
|
|
connection = httplib.HTTPConnection(domain)
|
|
connection.connect()
|
|
print("[+] "+Fore.GREEN+domain+" is available! Good!"+Style.RESET_ALL)
|
|
url = site
|
|
paraname = []
|
|
paravalue = []
|
|
wordlist = raw_input("[?] Enter location of Wordlist (Press Enter to use default wordlist.txt)\n[?] > ")
|
|
if len(wordlist) == 0:
|
|
wordlist = 'wordlist.txt'
|
|
print(grey+"[+] Using Default wordlist..."+Style.RESET_ALL)
|
|
else:
|
|
pass
|
|
payloads = []
|
|
wordlistimport(wordlist,payloads)
|
|
lop = str(len(payloads))
|
|
grey = Style.DIM+Fore.WHITE
|
|
print(Style.DIM+Fore.WHITE+"[+] "+lop+" Payloads loaded..."+Style.RESET_ALL)
|
|
print("[+] Bruteforce start:")
|
|
o = urlparse.urlparse(site)
|
|
parameters = urlparse.parse_qs(o.query,keep_blank_values=True)
|
|
path = urlparse.urlparse(site).scheme+"://"+urlparse.urlparse(site).netloc+urlparse.urlparse(site).path
|
|
for para in parameters: #Arranging parameters and values.
|
|
for i in parameters[para]:
|
|
paraname.append(para)
|
|
paravalue.append(i)
|
|
total = 0
|
|
c = 0
|
|
fpar = []
|
|
fresult = []
|
|
progress = 0
|
|
for pn, pv in zip(paraname,paravalue): #Scanning the parameter.
|
|
print(grey+"[+] Testing '"+pn+"' parameter..."+Style.RESET_ALL)
|
|
fpar.append(str(pn))
|
|
for x in payloads: #
|
|
validate = x.translate(None, whitespace)
|
|
if validate == "":
|
|
progress = progress + 1
|
|
else:
|
|
sys.stdout.write("\r[+] %i / %s payloads injected..."% (progress,len(payloads)))
|
|
sys.stdout.flush()
|
|
progress = progress + 1
|
|
enc = urllib.quote_plus(x)
|
|
data = path+"?"+pn+"="+pv+enc
|
|
page = urllib.urlopen(data)
|
|
sourcecode = page.read()
|
|
if x in sourcecode:
|
|
print(Style.BRIGHT+Fore.RED+"\n[!]"+" XSS Vulnerability Found! \n"+Fore.RED+Style.BRIGHT+"[!]"+" Parameter:\t%s\n"+Fore.RED+Style.BRIGHT+"[!]"+" Payload:\t%s"+Style.RESET_ALL)%(pn,x)
|
|
fresult.append(" Vulnerable ")
|
|
c = 1
|
|
total = total+1
|
|
progress = progress + 1
|
|
break
|
|
else:
|
|
c = 0
|
|
if c == 0:
|
|
print(Style.BRIGHT+Fore.GREEN+"\n[+]"+Style.RESET_ALL+Style.DIM+Fore.WHITE+" '%s' parameter not vulnerable."+Style.RESET_ALL)%pn
|
|
fresult.append("Not Vulnerable")
|
|
progress = progress + 1
|
|
pass
|
|
progress = 0
|
|
complete(fpar,fresult,total,domain)
|
|
except(httplib.HTTPResponse, socket.error) as Exit:
|
|
print(Style.BRIGHT+Fore.RED+"[!] Site "+domain+" is offline!"+Style.RESET_ALL)
|
|
again()
|
|
except(KeyboardInterrupt) as Exit:
|
|
print("\nExit...")
|
|
def POST():
|
|
try:
|
|
try:
|
|
try:
|
|
br = mechanize.Browser()
|
|
br.addheaders = [('User-agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.11)Gecko/20071127 Firefox/2.0.0.11')]
|
|
br.set_handle_robots(False)
|
|
br.set_handle_refresh(False)
|
|
site = raw_input("[?] Enter URL:\n[?] > ") #Taking URL
|
|
if 'https://' in site:
|
|
pass
|
|
elif 'http://' in site:
|
|
pass
|
|
else:
|
|
site = "http://"+site
|
|
finalurl = urlparse.urlparse(site)
|
|
urldata = urlparse.parse_qsl(finalurl.query)
|
|
domain0 = '{uri.scheme}://{uri.netloc}/'.format(uri=finalurl)
|
|
domain = domain0.replace("https://","").replace("http://","").replace("www.","").replace("/","")
|
|
print (Style.DIM+Fore.WHITE+"[+] Checking if "+domain+" is available..."+Style.RESET_ALL)
|
|
connection = httplib.HTTPConnection(domain)
|
|
connection.connect()
|
|
print("[+] "+Fore.GREEN+domain+" is available! Good!"+Style.RESET_ALL)
|
|
path = urlparse.urlparse(site).scheme+"://"+urlparse.urlparse(site).netloc+urlparse.urlparse(site).path
|
|
url = site
|
|
param = str(raw_input("[?] Enter post data: > "))
|
|
wordlist = raw_input("[?] Enter location of Wordlist (Press Enter to use default wordlist.txt)\n[?] > ")
|
|
if len(wordlist) == 0:
|
|
wordlist = 'wordlist.txt'
|
|
print("[+] Using Default wordlist...")
|
|
else:
|
|
pass
|
|
payloads = []
|
|
wordlistimport(wordlist,payloads)
|
|
lop = str(len(payloads))
|
|
grey = Style.DIM+Fore.WHITE
|
|
print(Style.DIM+Fore.WHITE+"[+] "+lop+" Payloads loaded..."+Style.RESET_ALL)
|
|
print("[+] Bruteforce start:")
|
|
params = "http://www.site.com/?"+param
|
|
finalurl = urlparse.urlparse(params)
|
|
urldata = urlparse.parse_qsl(finalurl.query)
|
|
o = urlparse.urlparse(params)
|
|
parameters = urlparse.parse_qs(o.query,keep_blank_values=True)
|
|
paraname = []
|
|
paravalue = []
|
|
for para in parameters: #Arranging parameters and values.
|
|
for i in parameters[para]:
|
|
paraname.append(para)
|
|
paravalue.append(i)
|
|
fpar = []
|
|
fresult = []
|
|
total = 0
|
|
progress = 0
|
|
pname1 = [] #parameter name
|
|
payload1 = []
|
|
for pn, pv in zip(paraname,paravalue): #Scanning the parameter.
|
|
print(grey+"[+] Testing '"+pn+"' parameter..."+Style.RESET_ALL)
|
|
fpar.append(str(pn))
|
|
for i in payloads:
|
|
validate = i.translate(None, whitespace)
|
|
if validate == "":
|
|
progress = progress + 1
|
|
else:
|
|
progress = progress + 1
|
|
sys.stdout.write("\r[+] %i / %s payloads injected..."% (progress,len(payloads)))
|
|
sys.stdout.flush()
|
|
pname1.append(pn)
|
|
payload1.append(str(i))
|
|
d4rk = 0
|
|
for m in range(len(paraname)):
|
|
d = paraname[d4rk]
|
|
d1 = paravalue[d4rk]
|
|
tst= "".join(pname1)
|
|
tst1 = "".join(d)
|
|
if pn in d:
|
|
d4rk = d4rk + 1
|
|
else:
|
|
d4rk = d4rk +1
|
|
pname1.append(str(d))
|
|
payload1.append(str(d1))
|
|
data = urllib.urlencode(dict(zip(pname1,payload1)))
|
|
r = br.open(path, data)
|
|
sourcecode = r.read()
|
|
pname1 = []
|
|
payload1 = []
|
|
if i in sourcecode:
|
|
print(Style.BRIGHT+Fore.RED+"\n[!]"+" XSS Vulnerability Found! \n"+Fore.RED+Style.BRIGHT+"[!]"+" Parameter:\t%s\n"+Fore.RED+Style.BRIGHT+"[!]"+" Payload:\t%s"+Style.RESET_ALL)%(pn,i)
|
|
fresult.append(" Vulnerable ")
|
|
c = 1
|
|
total = total+1
|
|
progress = progress + 1
|
|
break
|
|
else:
|
|
c = 0
|
|
if c == 0:
|
|
print(Style.BRIGHT+Fore.GREEN+"\n[+]"+Style.RESET_ALL+Style.DIM+Fore.WHITE+" '%s' parameter not vulnerable."+Style.RESET_ALL)%pn
|
|
fresult.append("Not Vulnerable")
|
|
progress = progress + 1
|
|
pass
|
|
progress = 0
|
|
complete(fpar,fresult,total,domain)
|
|
except(httplib.HTTPResponse, socket.error) as Exit:
|
|
print(Style.BRIGHT+Fore.RED+"[!] Site "+domain+" is offline!"+Style.RESET_ALL)
|
|
again()
|
|
except(KeyboardInterrupt) as Exit:
|
|
print("\nExit...")
|
|
except (mechanize.HTTPError,mechanize.URLError) as e:
|
|
print(Style.BRIGHT+Fore.RED+"\n[!] HTTP ERROR! %s %s"+Style.RESET_ALL)%(e.code,e.reason)
|
|
try:
|
|
methodselect = raw_input("[?] Select method: [G]ET or [P]OST (G/P): ").lower()
|
|
if methodselect == 'g':
|
|
GET()
|
|
elif methodselect == 'p':
|
|
POST()
|
|
else:
|
|
print("[!] Incorrect method selected.")
|
|
again()
|
|
except(KeyboardInterrupt) as Exit:
|
|
print("\nExit...")
|
|
|
|
brutexss()
|