diff --git a/README b/README
new file mode 100755
index 00000000..5acbdbb2
--- /dev/null
+++ b/README
@@ -0,0 +1,96 @@
+*************************************
+* Wfuzz 1.4c - The web bruteforcer *
+* Coded by: *
+* Christian Martorella *
+* - cmartorella@edge-security.com *
+* Carlos del ojo *
+* - deepbit@gmail.com *
+*************************************
+
+What is this?
+-------------
+
+Wfuzz is a tool designed to brutefore web applications, it's very flexible, it supports:
+
+ -Recursion (When doing directory discovery)
+ -Post data bruteforcing
+ -Header bruteforcing
+ -Output to HTML (easy for just clicking the links and checking the page, even with postdata!)
+ -Colored output
+ -Hide results by return code, word numbers, line numbers, etc.
+ -Url encoding
+ -Cookies
+ -Multithreading
+ -Proxy support
+ -All parameter fuzzing
+
+It was created to facilitate the task in web applications assessments, it's a tool by pentesters for pentesters ;)
+
+How does it works?
+------------------
+
+The tool is based on dictionaries or ranges, then you choose where you want to bruteforce just by replacing the value by the word FUZZ.
+
+Examples:
+
+ - wfuzz.py -c -z file -f wordlists/commons.txt --hc 404 --html http://www.mysite.com/FUZZ 2> results.html
+
+ This will bruteforce the site http://www.mysyte.com/FUZZ in search of resources i
+ (directories, scripts, files,etc), it will hide from the output the return code 404
+ (for easy reading results), it will use the dictionary commons.txt for the bruteforce
+ , and also will output the results to the results.html file (with a cool format to work).
+
+
+ - wfuzz.py -c -z range -r 1-100 --hc 404 http://www.mysite.com/list.asp?id=FUZZ
+ In this example instead of using a file as dictionary, it will use a range from 1-100,
+ and will bruteforce the parameter "id".
+
+ - wfuzz.py -c -z file -f wordlists/commons.txt --hc 404 --html -d "id=1&catalogue=FUZZ"
+ http://www.mysite.com/check.asp 2> results.html
+ Here you can see the use of POST data, with the option "-d".
+
+ - wfuzz.py -c -z file -f wordlists/commons.txt --hc 404 -R 2 http://www.mysite.com/FUZZ
+ Example of path discovery, using a recursive level of 2 paths.
+
+Platforms:
+----------
+
+wfuzz was tested on Linux, Os X and Windows.
+On windows the colored output, it doesn't work, we are working towards fixing this problem.
+
+
+Dependencies:
+------------
+
+On *nix systems, need pycurl to work.
+On Windows just run the wfuzz.exe
+
+Thanks:
+-------
+
+Shouts goes to: Trompeti an all the S21sec Team. (www.s21sec.com)
+
+Special thanks to DarkRaver for the tool Dirb, part of wfuzz is based on the functionallity of dirb. (www.open-labs.org) and most of the wordlist are from his tool.
+
+Andres Andreu, all Injection payloads are taken from wsFuzzer (www.neurofuzz.com)
+Stay tunned for the GUI it rocks..
+
+Changelog 1.4c:
+==============
+-Fixed Headers parsing, thanks to Osama
+-Fixed encoding naming problems, thanks to Osama
+-Added support to Hexa-Random payload (hexa-rand), thanks to Kaerast
+
+Changelog 1.4:
+==============
+-More encodings:
+-Performance improving
+-Some bugs fixed
+
+Changelog 1.3:
+=========
+-Creada funcion select_encoding
+-Multiple encoding, it's possible to encode both dictionries with different encodings.
+-Hidecode XXX (cuando da muchos errores, pero puede servir)
+-Word count fixed
+-More encoders (binascii,md5,sha1)
diff --git a/TextParser.py b/TextParser.py
new file mode 100644
index 00000000..c4026fa6
--- /dev/null
+++ b/TextParser.py
@@ -0,0 +1,139 @@
+#Covered by GPL V2.0
+#Coded by Carlos del Ojo Elias (deepbit@gmail.com)
+
+import sys
+import re
+
+
+class TextParser:
+ def __init__ (self):
+ self.string=""
+ self.oldindex=0
+ self.newindex=0
+ self.type=""
+ self.lastFull_line=None
+ self.lastline = None
+ pass
+
+ def __del__ (self):
+ if self.type=="file":
+ self.fd.close()
+
+ def setSource (self,t,*args):
+ '''Se especifica el tipo de entrada. Puede ser fichero o entrada estandard
+
+ Ejemplos: setSource("file","/tmp/file")
+ setSource("stdin")\n'''
+
+ if t=="file":
+ self.type=t
+ self.fd=file(args[0],"r")
+ elif t=="stdin":
+ if self.type=="file":
+ self.fd.close()
+ self.type=t
+ elif t=="string":
+ if self.type=="file":
+ self.fd.close()
+ self.type=t
+ self.string=args[0]
+ self.oldindex=0
+ self.newindex=0
+ else:
+ print "Bad argument -- TextParser.setSource()\n"
+ sys.exit (-1)
+
+
+ def seekinit(self):
+ self.oldindex=0;
+ self.newindex=0;
+
+
+ def readUntil (self,pattern,caseSens=True):
+ "Lee lineas hasta que el patron (pattern) conincide en alguna linea"
+
+ while True:
+ if (self.readLine() == 0):
+ return False
+ if (self.search(pattern,caseSens) == True):
+ break
+
+ return True
+
+
+
+ def search (self,pattern,caseSens=True,debug=0):
+ "Intenta hacer Matching entre el pattern pasado por parametro y la ultima linea leida"
+
+ if not caseSens:
+ self.regexp=re.compile(pattern,re.IGNORECASE)
+ else:
+ self.regexp=re.compile(pattern)
+ self.matches=self.regexp.findall(self.lastline)
+ j=0
+ for i in self.matches:
+ if not type(i)==type(()):
+ self.matches[j]=tuple([self.matches[j]])
+ j+=1
+
+# DEBUG PARA MATCHING
+ if (debug==1):
+ print "[",self.lastline,"-",pattern,"]"
+ print len(self.matches)
+ print self.matches
+
+ if len(self.matches)==0:
+ return False
+ else:
+ return True
+
+
+ def __getitem__ (self,key):
+ "Para acceder a cada uno de los patrones que coinciden, esta preparado paragrupos de patrones, no para solo un patron"
+
+ return self.matches[key]
+
+ def skip (self,lines):
+ "Salta las lines que se indiquen en el parametro"
+
+ for i in range(lines):
+ if (self.readLine() == 0):
+ return False
+
+ return True
+
+ def readLine(self):
+ "Lee la siguiente linea eliminando retornos de carro"
+
+ if self.type=="file":
+ self.lastFull_line=self.fd.readline()
+ elif self.type=="stdin":
+ self.lastFull_line=raw_input()
+ elif self.type=="string":
+ if self.newindex==-1:
+ return 0
+
+ if self.oldindex>=0:
+ self.newindex=self.string.find("\n",self.oldindex,len(self.string))
+ if self.newindex==-1:
+ self.lastFull_line=self.string[self.oldindex:len(self.string)]
+ else:
+ self.lastFull_line=self.string[self.oldindex:self.newindex+1]
+
+ self.oldindex=self.newindex+1
+ else:
+ self.lastFull_line=''
+
+ bytes_read = len(self.lastFull_line)
+
+ s=self.lastFull_line
+ self.lastline=s
+
+ if s[-2:] == '\r\n':
+ self.lastline = s[:-2]
+ elif s[-1:] == '\r' or s[-1:] == '\n':
+ self.lastline = s[:-1]
+
+ return bytes_read
+
+
diff --git a/dictio.py b/dictio.py
new file mode 100644
index 00000000..b5aecc3f
--- /dev/null
+++ b/dictio.py
@@ -0,0 +1,51 @@
+#!/usr/bin/python
+
+#Covered by GPL V2.0
+
+from encoders import *
+from payloads import *
+
+# generate_dictio evolution
+class dictionary:
+ def __init__(self,dicc=None):
+ if dicc:
+ self.__payload=dicc.getpayload()
+ self.__encoder=dicc.getencoder()
+ else:
+ self.__payload=payload()
+ self.__encoder=encoder()
+ self.iter=self.__payload.__iter__()
+
+ def count (self):
+ return self.__payload.count()
+
+ def setpayload(self,payl):
+ self.__payload=payl
+ self.iter=self.__payload.__iter__()
+
+ def setencoder(self,encd):
+ self.__encoder=encd
+
+ def getpayload (self):
+ return self.__payload
+
+ def getencoder (self):
+ return self.__encoder
+
+ def generate_all(self):
+ dicc=[]
+ for i in self.__payload:
+ dicc.append(self.__encoder.encode(i))
+ return dicc
+
+ def __iter__(self):
+ self.restart()
+ return self
+
+ def next(self):
+ pl=self.iter.next()
+ return self.__encoder.encode(pl)
+
+ def restart(self):
+ self.iter=self.__payload.__iter__()
+
diff --git a/encoders.py b/encoders.py
new file mode 100644
index 00000000..fc034563
--- /dev/null
+++ b/encoders.py
@@ -0,0 +1,301 @@
+import urllib
+import base64
+import re
+import binascii
+import random
+import hashlib
+
+
+# SUPERCLASS
+
+class encoder:
+ def __init__(self):
+ pass
+
+ def encode (self,string):
+ return string
+
+
+#######################################################
+######################################################
+######## Inheritances
+#######################################################
+######################################################
+
+class encoder_urlencode (encoder):
+ text="urlencode"
+ def __init__(self):
+ encoder.__init__(self)
+
+ def encode(self,string):
+ return urllib.quote(string)
+
+ def decode(self,string):
+ try:
+ res=urllib.unquote(clear)
+ return res
+ except:
+ return 1
+
+class encoder_double_urlencode (encoder):
+ text="double urlencode"
+ def __init__(self):
+ encoder.__init__(self)
+
+ def encode(self,string):
+ return urllib.quote(urllib.quote(string))
+
+class encoder_base64 (encoder):
+ text="base64"
+ def __init__(self):
+ encoder.__init__(self)
+
+ def encode(self,string):
+ return base64.standard_b64encode(string)
+
+ def decode(self,string):
+ import base64
+ try:
+ res=base64.decodestring(string)
+ return res
+ except:
+ return 1
+
+class encoder_uri_hex (encoder):
+ text="uri hexadecimal"
+ def __init__(self):
+ encoder.__init__(self)
+
+ def encode(self,string):
+ strt = ""
+ con = "%%%02x"
+ s=re.compile(r"/|;|=|:|&|@|\\|\?")
+ for c in string:
+ if s.search(c):
+ strt += c
+ continue
+ strt += con % ord(c)
+ return strt
+
+
+class encoder_random_upper (encoder):
+ text="random Uppercase"
+ def __init__(self):
+ encoder.__init__(self)
+
+ def encode(self,string):
+ strt = ""
+ for c in string:
+ x = int(random.uniform(0,10))
+ x = x % 2
+ if x == 1:
+ strt += c.upper()
+ else:
+ strt += c
+ return strt
+
+
+class encoder_doble_nibble_hex (encoder):
+ text="double nibble Hexa"
+ def __init__(self):
+ encoder.__init__(self)
+
+ def encode(self,string):
+ strt = ""
+ fin = ""
+ con = "%%%02x"
+# first get it in straight hex
+ s=re.compile(r"/|;|=|:|&|@|\\|\?")
+ enc=encoder_uri_hex()
+ strt = enc.encode(string)
+ for c in strt:
+ if not c == "%":
+ if s.search(c):
+ fin += c
+ continue
+ fin += con % ord(c)
+ else:
+ fin += c
+ return fin
+
+class encoder_sha1 (encoder):
+ text="sha1"
+ def __init__(self):
+ encoder.__init__(self)
+
+ def encode(self,string):
+ s=hashlib.sha1()
+ s.update(string)
+ res =s.hexdigest()
+ return res
+
+class encoder_md5 (encoder):
+ text="md5"
+ def __init__(self):
+ encoder.__init__(self)
+
+ def encode(self,string):
+ m=hashlib.new('md5')
+ m.update(string)
+ res = m.hexdigest()
+ return res
+
+class encoder_binascii (encoder):
+ text="binary Ascii"
+ def __init__(self):
+ encoder.__init__(self)
+
+ def encode(self,string):
+ res = binascii.hexlify(string)
+ return res
+
+ def decode(self,string):
+ import binascii
+ try:
+ res = binascii.unhexlify(clear)
+ return res
+ except:
+ return 1
+
+class encoder_html (encoder):
+ text="html encoder"
+ def __init__(self):
+ encoder.__init__(self)
+
+ def encode(self,string):
+ res=string
+ res=res.replace("<","<")
+ res=res.replace(">",">")
+ res=res.replace("\"",""")
+ res=res.replace("'","'")
+ #res=res.replace("&","&")
+ return res
+
+class encoder_html_decimal (encoder):
+ text="html encoder decimal"
+ def __init__(self):
+ encoder.__init__(self)
+
+ def encode(self,string):
+ new=""
+ for x in string:
+ new+=""+str(ord(x))+";"
+ return new
+
+class encoder_html_hexadecimal (encoder):
+ text="html encoder Hexa"
+ def __init__(self):
+ encoder.__init__(self)
+
+ def encode(self,string):
+ new=""
+ for x in string:
+ val="%02x" % ord(x)
+ new+=""+str(val)+";"
+ return new
+
+class encoder_utf8_binary (encoder):
+ text="utf8 binary"
+ def __init__(self):
+ encoder.__init__(self)
+
+ def encode(self,string):
+ new=""
+ for x in string:
+ val="%02x" % ord(x)
+ new+="\\x"+str(val)
+ return new
+
+class encoder_utf8 (encoder):
+ text="utf8"
+ def __init__(self):
+ encoder.__init__(self)
+
+ def encode(self,string):
+ new=""
+ for x in string:
+ val="%02x" % ord(x)
+ if len(val)==2:
+ new+="\\u00"+str(val)
+ else:
+ new+="\\u"+str(val)
+ return new
+
+class encoder_uri_unicode (encoder):
+ text="uri unicode"
+ def __init__(self):
+ encoder.__init__(self)
+
+ def encode(self,string):
+ new=""
+ for x in string:
+ val="%02x" % ord(x)
+ if len(val)==2:
+ new+="%u00"+str(val)
+ else:
+ new+="%u"+str(val)
+ return new
+
+class encoder_mysqlchar (encoder):
+ text="mysql char"
+ def __init__(self):
+ encoder.__init__(self)
+
+ def encode(self,string):
+ new="CHAR("
+ for x in string:
+ val=str(ord(x))
+ new+=str(val)+","
+ new=new.strip(",")
+ new+=")"
+ return new
+
+ def decode(self,string):
+ temp=string.strip("CHAR").strip("(").strip(")").split(",")
+ new=""
+ for x in temp:
+ new+=chr(int(x))
+ return new
+
+class encoder_mssqlchar(encoder):
+ text="mssql Char"
+ def __init__(self):
+ encoder.__init__(self)
+
+ def encode(self,string):
+ new=""
+ for x in string:
+ val=str(ord(x))
+ new+="CHAR("+str(val)+")+"
+ new=new.strip("+")
+ return new
+
+ def decode(self,string):
+ new=""
+ temp=string.split("+")
+ for x in temp:
+ x=x.strip("CHAR").strip(")").strip("(")
+ new+= chr(int(x))
+ return new
+
+class encoder_oraclechar(encoder):
+ text="oracle Char"
+ def __init__(self):
+ encoder.__init__(self)
+ def encode(self,string):
+ new=""
+ for x in string:
+ val=str(ord(x))
+ new+="chr("+val+")||"
+ new=new.strip("||")
+ return new
+
+ def decode(self,string):
+ new=""
+ temp=string.split("||")
+ for x in temp:
+ x=x.strip("chr").strip(")").strip("(")
+ new+= chr(int(x))
+ return new
+
+
diff --git a/payloads.py b/payloads.py
new file mode 100644
index 00000000..a9c01c16
--- /dev/null
+++ b/payloads.py
@@ -0,0 +1,209 @@
+import encoders
+import copy
+import random
+
+
+####### SUPERCLASS
+
+class payload:
+ def __init__(self):
+ self.__count=0
+ pass
+
+ def __iter__ (self):
+ return payload_iterator()
+
+
+ def count(self):
+ return self.__count
+
+class payload_iterator:
+ def __init__(self):
+ pass
+
+ def next (self):
+ raise StopIteration
+
+
+######################################
+######################################
+######## Inheritances
+######################################
+######################################
+
+class payload_file (payload):
+ def __init__(self,file):
+ payload.__init__(self)
+ self.file=file
+ f=open(file,"r")
+ self.__count=len(f.readlines())
+ f.close()
+
+
+ def count(self):
+ return self.__count
+
+ def __iter__ (self):
+ return file_iterator(self.file)
+
+class file_iterator (payload_iterator):
+ def __init__(self,file):
+ payload_iterator.__init__(self)
+ self.file=open (file,"r")
+
+ def next (self):
+ line=self.file.next().strip()
+
+ return line
+
+################### RANGE PAYLOAD
+
+
+class payload_range (payload):
+ def __init__(self,range,width=0): ## range example --> "23-56"
+ payload.__init__(self)
+ try:
+ ran=range.split("-")
+ self.minimum=int(ran[0])
+ self.maximum=int(ran[1])
+ self.__count=self.maximum - self.minimum
+ self.width=width
+ except:
+ raise Exception, "Bad range format (eg. \"23-56\")"
+
+
+ def count(self):
+ return self.__count
+
+ def __iter__ (self):
+ return range_iterator(self.minimum,self.maximum,self.width)
+
+
+class range_iterator (payload_iterator):
+ def __init__(self,min,max,width):
+ payload_iterator.__init__(self)
+ self.minimum=min
+ self.maximum=max
+ self.width=width
+ self.current=self.minimum
+
+ def next (self):
+ if self.current>self.maximum:
+ raise StopIteration
+ if self.width:
+ payl="%0"+str(self.width)+"d"
+ payl=payl % (self.current)
+ else:
+ payl=str(self.current)
+
+ self.current+=1
+ return payl
+
+
+################### HEXRANGE PAYLOAD
+
+
+class payload_hexrange (payload):
+ def __init__(self,range): ## range example --> "0-ffa"
+ payload.__init__(self)
+ try:
+ ran=range.split("-")
+ self.minimum=int(ran[0],16)
+ self.maximum=int(ran[1],16)
+ self.__count=self.maximum - self.minimum
+ except:
+ raise Exception, "Bad range format (eg. \"0-ffa\")"
+
+ def __iter__ (self):
+ return hexrange_iterator(self.minimum,self.maximum)
+
+ def count(self):
+ return self.__count
+
+class hexrange_iterator (payload_iterator):
+ def __init__(self,min,max):
+ payload_iterator.__init__(self)
+ self.minimum=min
+ self.maximum=max
+ self.current=self.minimum
+
+ def next (self):
+ if self.current>self.maximum:
+ raise StopIteration
+
+ lgth=len(hex(self.maximum).replace("0x",""))
+ pl="%"+str(lgth)+"s"
+ num=hex(self.current).replace("0x","")
+ pl= pl % (num)
+ payl=pl.replace(" ","0")
+
+ self.current+=1
+
+ return payl
+
+class payload_hexrand (payload):
+ def __init__(self,range): ## range example --> "0-ffa"
+ payload.__init__(self)
+ try:
+ ran=range.split("-")
+ self.minimum=int(ran[0],16)
+ self.maximum=int(ran[1],16)
+ self.__count=self.maximum - self.minimum
+ except:
+ raise Exception, "Bad range format (eg. \"0-ffa\")"
+
+ def __iter__ (self):
+ return hexrand_iterator(self.minimum,self.maximum)
+
+ def count(self):
+ return self.__count
+
+
+
+class hexrand_iterator (payload_iterator):
+ def __init__(self,min,max):
+ payload_iterator.__init__(self)
+ self.minimum=min
+ self.maximum=max
+ self.current=self.minimum
+
+ def next (self):
+ self.current = random.SystemRandom().randint(self.minimum,self.maximum)
+
+ lgth=len(hex(self.maximum).replace("0x",""))
+ pl="%"+str(lgth)+"s"
+ num=hex(self.current).replace("0x","")
+ pl= pl % (num)
+ payl=pl.replace(" ","0")
+
+ return payl
+
+######################### PAYLOAD LIST
+
+
+class payload_list (payload):
+ def __init__(self,list):
+ payload.__init__(self)
+ self.list=list
+ self.__count=len(list)
+
+ def __iter__ (self):
+ return plist_iterator(self.list)
+
+ def count(self):
+ return self.__count
+
+
+class plist_iterator (list):
+ def __init__(self,list):
+ self.list=list
+ self.current=0
+
+ def next (self):
+ try:
+ elem=self.list[self.current]
+ self.current+=1
+ return elem
+ except:
+ raise StopIteration
+
diff --git a/reqresp.py b/reqresp.py
new file mode 100644
index 00000000..dded29ac
--- /dev/null
+++ b/reqresp.py
@@ -0,0 +1,666 @@
+#Covered by GPL V2.0
+#Coded by Carlos del Ojo Elias (deepbit@gmail.com)
+
+
+from urlparse import *
+from time import gmtime, strftime
+import pycurl
+import gzip
+import StringIO
+import string
+import re
+import threading
+from time import localtime, strftime
+
+from xml.dom.minidom import Document
+
+try:
+ from TextParser import *
+except:
+ pass
+
+mutex=1
+Semaphore_Mutex=threading.BoundedSemaphore(value=mutex)
+REQLOG=False
+
+
+class Request:
+
+ def __init__ (self):
+
+ self.__host=None # www.google.com:80
+ self.__path=None # /index.php
+ self.__params=None # Mierdaza de index.php;lskjflkasjflkasjfdlkasdf?
+ self.schema="http" # http
+
+ ##### Variables calculadas por getters NO SE PUEDEN MODIFICAR
+ # self.urlWithoutPath # http://www.google.es
+ # self.pathWithVariables # /index.php?a=b&c=d
+ # self.urlWithoutVariables=None # http://www.google.es/index.php
+ # self.completeUrl="" # http://www.google.es/index.php?a=b
+ # self.postdata="" # Datos por POST, toto el string
+ ################
+
+ self.ContentType="application/x-www-form-urlencoded" # None es normal encoding
+ self.boundary="---------------------------D33PB1T0R3QR3SP0B0UND4RY2203"
+ self.multiPOSThead={}
+
+ self.__variablesGET={}
+ self.__GETorder=[]
+
+ self.__variablesPOST={}
+ self.__headers={} # diccionario, por ejemplo headers["Cookie"]
+
+ self.response=None # Apunta a la response que produce dicha request
+
+ ################### lo de debajo no se deberia acceder directamente
+
+ self.time=None # 23:00:00
+ self.ip=None # 192.168.1.1
+ self.method="GET" # GET o POST (EN MAYUSCULAS SI PUEDE SER)
+ self.protocol="HTTP/1.1" # HTTP/1.1
+ self.__performHead=""
+ self.__performBody=""
+
+ self.__authMethod=None
+ self.__userpass=""
+
+ self.description="" # For temporally store imformation
+
+ self.__proxy=None
+ self.__timeout=None
+ self.__totaltimeout=None
+
+ self.followLocation=False
+
+ def __str__(self):
+ str="[ URL: %s" % (self.completeUrl)
+ if self.method=="POST":
+ str+=" - POST: \"%s\"" % self.postdata
+ if "Cookie" in self.__headers:
+ str+=" - COOKIE: \"%s\"" % self.__headers["Cookie"]
+ str+=" ]"
+ return str
+
+ def getXML(self,obj):
+ r=obj.createElement("request")
+ r.setAttribute("method",self.method)
+ url=obj.createElement("URL")
+ url.appendChild(obj.createTextNode(self.completeUrl))
+ r.appendChild(url)
+ if self.method=="POST":
+ pd=obj.createElement("PostData")
+ pd.appendChild(obj.createTextNode(self.postdata))
+ r.appendChild(pd)
+ if "Cookie" in self.__headers:
+ ck=obj.createElement("Cookie")
+ ck.appendChild(obj.createTextNode(self.__headers["Cookie"]))
+ r.appendChild(ck)
+
+ return r
+
+
+ def __getattr__ (self,name):
+ if name=="urlWithoutVariables":
+ return urlunparse((self.schema,self.__host,self.__path,'','',''))
+ elif name=="pathWithVariables":
+ return urlunparse(('','',self.__path,'',self.getVARIABLESstring(self.__variablesGET,self.__GETorder),''))
+ elif name=="completeUrl":
+ return urlunparse((self.schema,self.__host,self.__path,self.__params,self.getVARIABLESstring(self.__variablesGET,self.__GETorder),''))
+ elif name=="urlWithoutPath":
+ return "%s://%s" % (self.schema,self.__headers["Host"])
+ elif name=="path":
+ return self.__path
+ elif name=="postdata":
+ if self.ContentType=="application/x-www-form-urlencoded":
+ return self.getVARIABLESstring(self.__variablesPOST,None)
+ elif self.ContentType=="multipart/form-data":
+ pd=""
+ for i,j in self.__variablesPOST.items():
+ pd+="--"+self.boundary+"\r\n"
+ pd+="%s\r\n\r\n%s\r\n" % ("\r\n".join(self.multiPOSThead[i]),j)
+ pd+="--"+self.boundary+"--\r\n"
+ return pd
+ else:
+ return self.__uknPostData
+ else:
+ raise AttributeError
+
+ def getVARIABLESstring(self,vars,sort):
+ str=[]
+
+ if not sort:
+ for i,j in vars.items():
+ str.append(i+"="+j)
+ else:
+ for i in sort:
+ str.append(i+"="+vars[i])
+
+ return "&".join(str)
+
+
+ def readUrlEncodedVariables(self,str):
+ dicc=[]
+
+ for i in str.split("&"):
+ if i:
+ list=i.split("=",1)
+ if len (list)==1:
+ dicc.append([list[0],""])
+ elif len (list)==2:
+ dicc.append([list[0],list[1]])
+
+
+
+ return dicc
+
+ def setUrl (self, urltmp):
+
+ self.__variablesGET={}
+
+ self.schema,self.__host,self.__path,self.__params,variables,f=urlparse(urltmp)
+
+ self.__headers["Host"]=self.__host.lstrip()
+
+ if len(variables)>0:
+ dicc=self.readUrlEncodedVariables(variables)
+ [self.addVariableGET(i,j) for i,j in dicc]
+
+
+ def setProxy (self,prox):
+ self.__proxy=prox
+
+ def setFollowLocation(self,value):
+ self.followLocation=value
+
+
+ def setConnTimeout (self,time):
+ self.__timeout=time
+
+ def setTotalTimeout (self,time):
+ self.__totaltimeout=time
+############## Autenticacion ###########################
+ def setAuth (self,method,string):
+ self.__authMethod=method
+ self.__userpass=string
+
+ def getAuth (self):
+ return self.__authMethod, self.__userpass
+
+############## TRATAMIENTO VARIABLES GET & POST #########################
+
+ def variablesGET(self):
+ return self.__variablesGET.keys()
+
+ def variablesPOST(self):
+ return self.__variablesPOST.keys()
+
+ def addVariablePOST (self,key,value):
+ self.method="POST"
+ self.__variablesPOST[key]=value
+ self.__headers["Content-Length"]=str(len(self.postdata))
+
+ def addVariableGET (self,key,value):
+ if not key in self.__variablesGET:
+ self.__GETorder.append(key)
+ self.__variablesGET[key]=value
+
+ def getVariableGET (self,key):
+ if self.__variablesGET.has_key(str(key)):
+ return self.__variablesGET[str(key)]
+ else:
+ return None
+
+ def getVariablePOST (self,key):
+ if self.__variablesPOST.has_key(str(key)):
+ return self.__variablesPOST[str(key)]
+ else:
+ return None
+
+ def setPostData (self,pd):
+ self.__variablesPOST={}
+ self.method="POST"
+ self.parsePOSTDATA(pd)
+
+ def addPostdata (self,str):
+ self.method="POST"
+ self.postdata=self.postdata+str
+ variables=str.split("&")
+ for i in variables:
+ tmp=i.split("=",1)
+ if len(tmp)==2:
+ self.addVariablePOST(tmp[0],tmp[1])
+ else:
+ self.addVariablePOST(tmp[0],'')
+
+
+
+
+############################################################################
+
+ def addHeader (self,key,value):
+ k=string.capwords(key,"-")
+ if k!="Accept-Encoding":
+ self.__headers[k]=value.strip()
+
+
+ def __getitem__ (self,key):
+ k=string.capwords(key,"-")
+ if self.__headers.has_key(k):
+ return self.__headers[k]
+ else:
+ return ""
+
+ def __getHeaders (self):
+ list=[]
+ for i,j in self.__headers.items():
+ list+=["%s: %s" % (i,j)]
+ return list
+
+ def getHeaders (self):
+ list=[]
+ for i,j in self.__headers.items():
+ list+=["%s: %s" % (i,j)]
+ return list
+
+
+
+ def perform(self):
+ global REQLOG
+ if REQLOG:
+ Semaphore_Mutex.acquire()
+ f=open("/tmp/REQLOG","a")
+ f.write( strftime("\r\n\r\n############################ %a, %d %b %Y %H:%M:%S\r\n", localtime()))
+ f.write(self.getAll())
+ f.close()
+ Semaphore_Mutex.release()
+
+
+ self.__performHead=""
+ self.__performBody=""
+ self.__headersSent=""
+
+ conn=pycurl.Curl()
+ conn.setopt(pycurl.SSL_VERIFYPEER,False)
+ conn.setopt(pycurl.SSL_VERIFYHOST,1)
+ conn.setopt(pycurl.URL,self.completeUrl)
+
+ if self.__authMethod or self.__userpass:
+ if self.__authMethod=="basic":
+ conn.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_BASIC)
+ elif self.__authMethod=="ntlm":
+ conn.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_NTLM)
+ elif self.__authMethod=="digest":
+ conn.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_DIGEST)
+ conn.setopt(pycurl.USERPWD, self.__userpass)
+
+ if self.__timeout:
+ conn.setopt(pycurl.CONNECTTIMEOUT, self.__timeout)
+ conn.setopt(pycurl.NOSIGNAL, 1)
+
+ if self.__totaltimeout:
+ conn.setopt(pycurl.TIMEOUT, self.__totaltimeout)
+ conn.setopt(pycurl.NOSIGNAL, 1)
+
+ conn.setopt(pycurl.WRITEFUNCTION, self.body_callback)
+ conn.setopt(pycurl.HEADERFUNCTION, self.header_callback)
+ #conn.setopt(pycurl.DEBUGFUNCTION, self.sent_header_callback)
+ #conn.setopt(pycurl.VERBOSE, 1)
+
+ if self.__proxy!=None:
+ conn.setopt(pycurl.PROXY,self.__proxy)
+ if self.__headers.has_key("Proxy-Connection"):
+ del self.__headers["Proxy-Connection"]
+
+ conn.setopt(pycurl.HTTPHEADER,self.__getHeaders())
+ if self.method=="POST":
+ conn.setopt(pycurl.POSTFIELDS,self.postdata)
+ conn.perform()
+
+ rp=Response()
+ rp.parseResponse(self.__performHead)
+ rp.addContent(self.__performBody)
+
+ if self.schema=="https" and self.__proxy:
+ self.response=Response()
+ self.response.parseResponse(rp.getContent())
+ else:
+ self.response=rp
+
+
+
+ if self.followLocation:
+ if self.response.getLocation():
+ a=Request()
+ url=urlparse(self.response.getLocation())
+ if not url[0] or not url[1]:
+ sc=url[0]
+ h=url[1]
+ if not sc:
+ sc=self.schema
+ if not h:
+ h=self.__host
+ a.setUrl(urlunparse((sc,h)+url[2:]))
+ else:
+ a.setUrl(self.response.getLocation())
+ a.setProxy(self.__proxy)
+
+ ck=""
+
+ if "Cookie" in self.__headers:
+ ck=self.__headers["Cookie"]
+ if self.response.getCookie():
+ if ck:
+ ck+=";"+self.response.getCookie()
+ else:
+ ck=self.response.getCookie()
+
+ if ck:
+ self.addHeader("Cookie",ck)
+
+
+ a.perform()
+ self.response=a.response
+
+
+
+ ######### ESTE conjunto de funciones no es necesario para el uso habitual de la clase
+
+ def getPostData (self):
+ return self.postdata
+
+ def getAll (self):
+ "Devuelve el texto de la request completa (lo que escrbirias por telnet"
+ pd=self.postdata
+ string=str(self.method)+" "+str(self.pathWithVariables)+" "+str(self.protocol)+"\n"
+ for i,j in self.__headers.items():
+ string+=i+": "+j+"\n"
+ string+="\n"+pd
+
+ return string
+
+ ##########################################################################
+
+ def sent_header_callback(self,type,data):
+ if type==pycurl.INFOTYPE_HEADER_OUT:
+ tp=TextParser()
+ tp.setSource("string",data)
+
+ while (tp.readUntil("^([^:]+): (.*)$")):
+ self.addHeader(tp[0][0],tp[0][1])
+
+
+
+ def header_callback(self,data):
+ self.__performHead+=data
+
+ def body_callback(self,data):
+ self.__performBody+=data
+
+ def Substitute(self,src,dst):
+ a=self.getAll()
+ rx=re.compile(src)
+ b=rx.sub(dst,a)
+ del rx
+ self.parseRequest(b,self.schema)
+
+ def parseRequest (self,rawRequest,prot="http"):
+ ''' Aun esta en fase BETA y por probar'''
+ tp=TextParser()
+ tp.setSource("string",rawRequest)
+
+ self.__variablesPOST={}
+ self.__headers={} # diccionario, por ejemplo headers["Cookie"]
+
+
+ tp.readLine()
+ try:
+ tp.search("(\w+) (.*) (HTTP\S*)")
+ self.method=tp[0][0]
+ self.protocol=tp[0][2]
+ except Exception,a:
+ print rawRequest
+ raise a
+
+ pathTMP=tp[0][1]
+ pathTMP=('','')+urlparse(pathTMP)[2:]
+ pathTMP=urlunparse(pathTMP)
+ # print pathTMP
+ # pathTMP=pathTMP.replace("//","/")
+ self.time=strftime("%H:%M:%S", gmtime())
+
+ while True:
+ tp.readLine()
+ if (tp.search("^([^:]+): (.*)$")):
+ self.addHeader(tp[0][0],tp[0][1])
+ else:
+ break
+
+ self.setUrl(prot+"://"+self.__headers["Host"]+pathTMP)
+
+ if self.method.upper()=="POST":
+
+ pd=""
+ while tp.readLine():
+ pd+=tp.lastFull_line
+
+
+ if "Content-Type" in self.__headers:
+ values=self.__headers["Content-Type"].split(";")
+ if values[0].strip().lower()=="application/x-www-form-urlencoded":
+ self.ContentType=values[0]
+ elif values[0].strip().lower()=="multipart/form-data":
+ self.ContentType=values[0]
+ self.boundary=values[1].split("=")[1].strip()
+
+ self.parsePOSTDATA(pd)
+
+
+ def parsePOSTDATA(self,pd):
+
+ if self.ContentType=="application/x-www-form-urlencoded":
+ dicc=self.readUrlEncodedVariables(pd)
+ [self.addVariablePOST(i,j) for i,j in dicc]
+
+ elif self.ContentType=="multipart/form-data":
+ self.multiPOSThead={}
+ dicc={}
+ tp=TextParser()
+ tp.setSource("string",pd)
+ # print self.boundary
+ # print tp.readUntil("%s$" % (self.boundary))
+
+ while True:
+ headers=[]
+ if not tp.readUntil("name=\"([^\"]+)\""):
+ break
+ var=tp[0][0]
+ headers.append(tp.lastFull_line.strip())
+ while True:
+ tp.readLine()
+ if tp.search("^([^:]+): (.*)$"):
+ headers.append(tp.lastFull_line.strip())
+ else:
+ break
+
+ value=""
+ while True:
+ tp.readLine()
+ if not tp.search(self.boundary):
+ value+=tp.lastFull_line
+ else:
+ break
+
+ if value[-2:]=="\r\n":
+ value=value[:-2]
+
+
+ dicc[var]=value
+ self.multiPOSThead[var]=headers
+
+ if tp.search(self.boundary+"--"):
+ break
+
+
+ self.__variablesPOST.update(dicc)
+# print pd
+# print dicc
+# print self.__variablesPOST
+
+ else:
+ self.__uknPostData=pd
+
+class Response:
+
+ def __init__ (self,protocol="",code="",message=""):
+ self.protocol=protocol # HTTP/1.1
+ self.code=code # 200
+ self.message=message # OK
+ self.__headers=[] # bueno pues las cabeceras igual que en la request
+ self.__content="" # contenido de la response (si i solo si Content-Length existe)
+ self.md5="" # hash de los contenidos del resultado
+ self.charlen="" # Cantidad de caracteres de la respuesta
+
+ def addHeader (self,key,value):
+ k=string.capwords(key,"-")
+ self.__headers+=[(k,value)]
+
+ def delHeader (self,key):
+ for i in self.__headers:
+ if i[0].lower()==key.lower():
+ self.__headers.remove(i)
+
+
+ def addContent (self,text):
+ self.__content=self.__content+text
+
+ def __getitem__ (self,key):
+ for i,j in self.__headers:
+ if key==i:
+ return j
+ print "Error al obtener header!!!"
+
+ def getCookie (self):
+ str=[]
+ for i,j in self.__headers:
+ if i.lower()=="set-cookie":
+ str.append(j.split(";")[0])
+ return "; ".join(str)
+
+
+ def has_header (self,key):
+ for i,j in self.__headers:
+ if i.lower()==key.lower():
+ return True
+ return False
+
+ def getLocation (self):
+ for i,j in self.__headers:
+ if i.lower()=="location":
+ return j
+ return None
+
+ def header_equal (self,header,value):
+ for i,j in self.__headers:
+ if i==header and j.lower()==value.lower():
+ return True
+ return False
+
+ def getHeaders (self):
+ return self.__headers
+
+
+ def getContent (self):
+ return self.__content
+
+ def getAll (self):
+ string=str(self.protocol)+" "+str(self.code)+" "+str(self.message)+"\r\n"
+ for i,j in self.__headers:
+ string+=i+": "+j+"\r\n"
+ string+="\r\n"+self.getContent()
+ return string
+
+ def Substitute(self,src,dst):
+ a=self.getAll()
+ b=a.replace(src,dst)
+ self.parseResponse(b)
+
+ def getAll_wpost (self):
+ string=str(self.protocol)+" "+str(self.code)+" "+str(self.message)+"\r\n"
+ for i,j in self.__headers:
+ string+=i+": "+j+"\r\n"
+ return string
+
+
+ def parseResponse (self,rawResponse,type="curl"):
+ self.__content=""
+ self.__headers=[]
+
+ tp=TextParser()
+ tp.setSource("string",rawResponse)
+
+ while True:
+ tp.readUntil("(HTTP\S*) ([0-9]+)")
+
+ try:
+ self.protocol=tp[0][0]
+ except:
+ self.protocol="unknown"
+
+ try:
+ self.code=tp[0][1]
+ except:
+ self.code="0"
+
+ if self.code!="100":
+ break
+
+
+ self.code=int(self.code)
+
+ while True:
+ tp.readLine()
+ if (tp.search("^([^:]+): ?(.*)$")):
+ self.addHeader(tp[0][0],tp[0][1])
+ else:
+ break
+
+ while tp.skip(1):
+ self.addContent(tp.lastFull_line)
+
+ if type=='curl':
+ self.delHeader("Transfer-Encoding")
+
+ if self.header_equal("Transfer-Encoding","chunked"):
+ result=""
+ content=StringIO.StringIO(self.__content)
+ hexa=content.readline()
+ nchunk=int(hexa.strip(),16)
+
+ while nchunk:
+ result+=content.read(nchunk)
+ content.readline()
+ hexa=content.readline()
+ nchunk=int(hexa.strip(),16)
+
+ self.__content=result
+
+ if self.header_equal("Content-Encoding","gzip"):
+ compressedstream = StringIO.StringIO(self.__content)
+ gzipper = gzip.GzipFile(fileobj=compressedstream)
+ body=gzipper.read()
+ self.__content=body
+ self.delHeader("Content-Encoding")
+
+
+
+class ReqrespException(Exception):
+ def __init__ (self,value):
+ self.__value=value
+
+ def __str__ (self):
+ return self.GetError()
+
+ def GetError(self):
+ if self.__value==1:
+ return "Attribute not modificable"
diff --git a/wfuzz.py b/wfuzz.py
new file mode 100644
index 00000000..e03b2a5d
--- /dev/null
+++ b/wfuzz.py
@@ -0,0 +1,769 @@
+#!/usr/bin/python
+
+#Covered by GPL V2.0
+
+import copy
+from reqresp import *
+import binascii
+import sys
+import threading
+import getopt
+import time
+import os
+from encoders import *
+from payloads import *
+from dictio import dictionary
+import re
+import hashlib
+
+ENCODERS={}
+encs=dir(encoders)
+for i in encs:
+ try:
+ if i[:8]=='encoder_':
+ ENCODERS[getattr(encoders,i).text.lower()]=i
+ except:
+ pass
+
+# Generate_fuzz evolution
+class requestGenerator:
+ def __init__(self,reqresp,varsSet,dictio,dictio2=None,proxy=None):
+
+ self.reqsgenerated=0
+
+ self.request=reqresp
+ self.proxy=proxy
+ self.allvars=False
+ self.allpost=False
+ self.allheaders=False
+ self.final=False
+ self.child=None
+
+ self.kk=varsSet
+ if varsSet=="allvars":
+ self.allvars=True
+ self.varSET=self.request.variablesGET()
+ elif varsSet=="allpost":
+ self.allpost=True
+ self.varSET=self.request.variablesPOST()
+ elif varsSet=="allheaders":
+ self.allheaders=True
+ self.varSET=self.request.getHeaders()
+ elif varsSet!="None":
+ raise Exception,"Unknown variable set: "+varsSet
+
+
+ #################### Importante aqui se guarda un nuevo diccionario, mediante el constructor por copia
+ # Esto se hace para que cada diccionario de cada requestGenerator tenga su propio iterador! y no usen
+ # todos el mismo :D
+ ####################
+
+ self.dictio=dictionary(dictio)
+ if dictio2:
+ self.dictio2=dictionary(dictio2)
+ else:
+ self.dictio2=None
+
+ self.currentDictio1=None
+
+ self.currentVarSet=0
+
+ def count (self):
+ sr=0
+ if self.child:
+ sr=self.child.count()
+ if self.allvars or self.allpost or self.allheaders:
+ return self.dictio.count()*len( self.varSET)+sr
+ elif not self.dictio2:
+ return self.dictio.count()+sr
+ else:
+ return self.dictio.count()*self.dictio2.count()+sr
+
+ def append (self,rg):
+ if self.child:
+ self.child.append(rg)
+ else:
+ self.child=rg
+
+ def __iter__ (self):
+ self.restart()
+ return self
+
+ def restart (self):
+ self.dictio.restart()
+ if self.dictio2:
+ self.dictio2.restart()
+ self.final=False
+
+ if self.child:
+ self.child.restart()
+
+ def moreRequests (self):
+ if not self.child:
+ return not self.final
+ else:
+ return self.final or self.child.moreRequests()
+
+ def generated(self):
+ return self.reqsgenerated
+
+ def next (self):
+ try :
+ if self.dictio2:
+ if not self.currentDictio1:
+ self.currentDictio1=self.dictio.next()
+ try:
+ self.currentDictio2=self.dictio2.next()
+ except :
+ self.currentDictio1=self.dictio.next()
+ self.dictio2.restart()
+ self.currentDictio2=self.dictio2.next()
+ self.reqsgenerated+=1
+ return self.generate_request(self.request,self.currentDictio1,self.currentDictio2)
+
+ elif self.allvars or self.allpost or self.allheaders:
+ if not self.varSET:
+ raise StopIteration
+
+ if not self.currentDictio1:
+ self.currentDictio1=self.dictio.next()
+
+ if self.currentVarSet>=len(self.varSET):
+ self.currentDictio1=self.dictio.next()
+ self.currentVarSet=0
+
+ var=self.varSET[self.currentVarSet]
+ self.currentVarSet+=1
+
+ self.reqsgenerated+=1
+ return self.generate_request(self.request,self.currentDictio1,"",var)
+
+ else:
+ self.reqsgenerated+=1
+ return self.generate_request(self.request,self.dictio.next())
+ except Exception,e:
+ if self.child:
+ return self.child.next()
+ else:
+ self.final=True
+ raise e
+
+
+ def generate_request(self,req,payload1,payload2="",variable=""):
+ if self.allvars==True:
+ copycat=copy.deepcopy(req)
+ copycat.setProxy(self.proxy)
+ copycat.addVariableGET(variable,payload1)
+ copycat.description=variable + "=" + payload1
+ return copycat
+
+ elif self.allpost==True:
+ copycat=copy.deepcopy(req)
+ copycat.setProxy(self.proxy)
+ copycat.addVariablePOST(variable,payload1)
+ copycat.description=variable + "=" + payload1
+ return copycat
+
+ elif self.allheaders==True:
+ copycat=copy.deepcopy(req)
+ copycat.setProxy(self.proxy)
+ copycat.addHeader(variable,payload1)
+ copycat.description=variable + "=" + payload1
+ return copycat
+
+ else:
+ rawReq=req.getAll()
+ schema=req.schema
+ method,userpass=req.getAuth()
+
+ if rawReq.count('FUZZ'):
+ a=Request()
+ res=rawReq.replace("FUZZ",payload1)
+ if rawReq.count('FUZ2Z'):
+ res=res.replace("FUZ2Z",payload2)
+ a.parseRequest(res,schema)
+ temp=a.completeUrl
+ #a.setUrl(temp.replace("FUZZ",payload1))
+ # a.completeUrl=self.request.completeUrl.replace("FUZZ",payload1)
+ if self.request.completeUrl.count("FUZ2Z"):
+ a.setUrl(temp.replace("FUZ2Z",payload2))
+ #a.completeUrl=a.completeUrl.replace("FUZ2Z",payload2)
+
+ if self.request.description:
+ a.description=self.request.description+"/"+payload1
+ else:
+ a.description=payload1
+ if rawReq.count('FUZ2Z'):
+ a.description+=" - "+payload2
+ if method != 'None':
+ a.setAuth(method,userpass)
+ a.setProxy(self.proxy)
+ return a
+
+ elif method and (userpass.count('FUZZ') ):
+ copycat=copy.deepcopy(req)
+ userpass=userpass.replace("FUZZ",payload1)
+ if userpass.count('FUZ2Z'):
+ userpass=userpass.replace("FUZ2Z",payload2)
+ copycat.setAuth(method,userpass)
+ copycat.description=userpass
+ copycat.setProxy(self.proxy)
+ return copycat
+
+ else:
+ return req
+
+
+class FuzzResult:
+
+ def __init__(self,request,saveMemory=True):
+
+ global OS
+
+ #######################################
+ self.len=0
+ self.lines=0
+ self.words=0
+ self.code=0
+ self.md5=""
+
+ ### Used only when saveMemory = False
+ self.respHeaders=[]
+ self.html=""
+ self.rawrequest=""
+ self.completeUrl=""
+ self.descrip=request.description
+ ########################################
+ request.setConnTimeout(10)
+ request.setTotalTimeout(10)
+ i=5
+ x=True
+ import time
+ while i:
+ try:
+
+ #time.sleep(0.1)
+ starttime=time.time()
+ request.perform()
+ stoptime=time.time()
+ diff=stoptime-starttime
+ break
+ except :
+ i-=1
+ x=False
+ if not i:
+ if __name__=="__main__":
+ global nreq
+ nreq+=1
+ limpialinea()
+ if "XXX" in hidecodes:
+ pass
+ else:
+ sys.stdout.write ("%05d: C=XXX %4d L\t %5d W\t %s\r\n" %(nreq,0,0,"Error in "+request.description[-50:]))
+ sys.stdout.flush()
+
+ if html:
+ sys.stderr.write ("\r\n
%05d XXX %4dL %5dW %s \r\n" %(nreq,0,0,request.completeUrl,"Error in "+request.completeUrl))
+ raise a
+ return
+
+
+ if not saveMemory:
+ self.completeUrl=request.completeUrl
+ self.req=request
+ self.respHeaders=request.response.getHeaders()
+ self.len=len(request.response.getContent())
+ self.lines=request.response.getContent().count("\n")
+ self.words=len(re.findall("\S+",request.response.getContent()))
+ self.code=int(request.response.code)
+ self.timer=str(diff)[:8]
+ self.timestamp=time.strftime('%X',time.gmtime(starttime))
+ self.cookie=request.response.getCookie()
+ if request.response.has_header('Location'):
+ self.location=request.response['Location']
+ else:
+ self.location=""
+ m=hashlib.md5()
+ m.update(request.response.getContent())
+
+ self.md5=m.hexdigest()
+
+
+ if __name__=="__main__":
+
+
+ if str(self.code) in hidecodes or str(self.lines) in hidelines or str(self.words) in hidewords or str(self.len) in hidechars:
+ fl=""
+ else:
+ fl="\r\n"
+ nreq+=1
+
+ imprimeResult (nreq,self.code,self.lines,self.words,request.description[-50:],fl,self.len)
+ del request
+
+ if html:
+ if str(self.code) in hidecodes or str(self.lines) in hidelines or str(self.words) in hidewords or str(self.len) in hidechars:
+ return
+ imprimeResultHtml (nreq,self.code,self.lines,self.words,request,self.len)
+
+
+ def __getitem__ (self,key):
+ for i,j in self.respHeaders:
+ if key==i:
+ return j
+ print "Error al obtener header!!!"
+
+
+ def has_header (self,key):
+ for i,j in self.respHeaders:
+ if i==key:
+ return True
+ return False
+
+
+
+#####################################################################################################
+#####################################################################################################
+#####################################################################################################
+
+
+class Fuzzer:
+ def __init__(self,genreq,ignore,threads=20):
+ self.genReq=genreq
+ self.results=[]
+ self.threads=threads
+ self.run=True
+ self.threads_list=[]
+ self.nres=0
+ self.mutex=1
+ self.Semaphore_Mutex=threading.BoundedSemaphore(value=self.mutex)
+ self.ignore=ignore
+
+ def count (self):
+ return self.genReq.count()
+
+ def Launch (self):
+ for i in range (0,self.threads):
+ th=threading.Thread(target=self.attack, kwargs={})
+ th.start()
+ self.threads_list.append(th)
+
+ def attack (self):
+ rq=self.getNewReq()
+ while rq and self.run:
+ try :
+ res=FuzzResult(rq,False)
+ #if (str(res.code) not in self.ignore):
+ self.agregaresultado(res)
+ except :
+ pass
+ rq=self.getNewReq()
+
+ def agregaresultado (self,res):
+ self.Semaphore_Mutex.acquire()
+ self.results.append(res)
+ self.nres+=1
+ self.Semaphore_Mutex.release()
+
+ def numResults (self):
+ nres=len(self.results)
+ return self.nres
+
+ def getResult(self,n):
+ return self.results[n]
+
+ def getResults(self):
+ return self.results
+
+ def getNewReq(self):
+ self.Semaphore_Mutex.acquire()
+ try:
+ res=self.genReq.next()
+ except :
+ res=None
+ self.Semaphore_Mutex.release()
+ return res
+
+ def cleanthreads(self):
+ if self.genReq.moreRequests():
+ return None
+ for i in self.threads_list:
+ i.join()
+ return True
+
+ def stop(self):
+ self.run=False
+ for i in self.threads_list:
+ i.join()
+
+ def resum(self):
+ self.run=True
+
+ def delete(self):
+ del self.results
+ self.results=[]
+
+
+
+#############################################################################################################
+#############################################################################################################
+################# INTERFACE CONOSLA ####################
+#############################################################################################################
+#############################################################################################################
+
+
+OS=os.name
+if OS=="nt":
+ import WConio
+
+mutex=1
+printMutex=threading.BoundedSemaphore(value=mutex)
+
+
+def imprimeResult (nreq,code,lines,words,fuzzs,finalLine,len):
+ global printMutex
+
+ printMutex.acquire()
+
+ limpialinea()
+ sys.stdout.write ("%05d: C=" % (nreq) )
+
+ cc=""
+ wc=8
+ if code>=400 and code<500:
+ if color:
+ cc="\x1b[31m"
+ wc=12
+ elif code>=300 and code<400:
+ if color:
+ cc="\x1b[36m"
+ wc=11
+ elif code>=200 and code<300:
+ if color:
+ cc="\x1b[32m"
+ wc=10
+ else:
+ if color:
+ cc="\x1b[35m"
+ wc=1
+ if OS!='nt':
+ sys.stdout.write (cc)
+ else:
+ WConio.textcolor(wc)
+
+
+ sys.stdout.write ("%03d" % (code))
+
+ if OS!='nt':
+ sys.stdout.write ("\x1b[37m")
+ else:
+ WConio.textcolor(8)
+
+ sys.stdout.write (" %4d L\t %5d W\t %5d Ch\t \"%s\"%s" %(lines,words,len,fuzzs,finalLine))
+
+ sys.stdout.flush()
+
+
+ printMutex.release()
+
+def limpialinea():
+ sys.stdout.write ("\r")
+ if OS!='nt':
+ sys.stdout.write ("\x1b[0K")
+ else:
+ WConio.clreol()
+
+def imprimeResultHtml (nreq,code,lines,words,req):
+
+ htmlc=""
+ if code>=400 and code<500:
+ htmlc=""
+ elif code>=300 and code<400:
+ htmlc=""
+ elif code>=200 and code<300:
+ htmlc=""
+
+ if req.method.lower()=="get":
+ sys.stderr.write ("\r\n%05d %s%d %4dL %5dW %s \r\n" %(nreq,htmlc,code,lines,words,req.completeUrl,req.completeUrl))
+ else:
+ inputs=""
+ postvars=req.variablesPOST()
+ for i in postvars:
+ inputs+=" " % (i,req.getVariablePOST(i))
+
+ sys.stderr.write ("\r\n%05d \r\n%s%d \r\n%4dL \r\n%5dW \r\n \r\n \r\n" %(nreq,htmlc,code,lines,words,req.description,req.completeUrl,inputs))
+
+
+
+def select_encoding(typ):
+ typ=typ.lower()
+
+ if not typ in ENCODERS:
+ print typ+" encoding does not exists (-e help for a list of available encodings)"
+ sys.exit(-1)
+
+ return getattr (encoders,ENCODERS[typ])()
+
+
+if __name__=="__main__":
+
+ color=False
+ hidecodes=[]
+ hidewords=[]
+ hidelines=[]
+ hidechars=[]
+ ths=20
+ postdata=False
+ html=False
+ postdata_data=""
+ nreq=0
+
+ rlevel=0
+ current_depth=0
+
+ banner='''
+*************************************
+* Wfuzz 1.4c - The Web Bruteforcer *
+* Coded by: *
+* Christian Martorella *
+* - cmartorella@edge-security.com *
+* Carlos del ojo *
+* - deepbit@gmail.com *
+*************************************
+'''
+ usage='''
+Usage: %s [options] \r\n
+Options:
+-c : Output with colors
+-x addr : use Proxy (ip:port)
+-d postdata : Use post data (ex: "id=FUZZ&catalogue=1")
+-H headers : Use headers (ex:"Host:www.mysite.com,Cookie:id=1312321&user=FUZZ")
+-z payload type : Specify type of payload (file,range,hexa-range,hexa-rand)
+-r N1-N2 : Specify range limits
+-f path : Specify file path (comma sepparated, if multiple FUZZ vars)
+-t N : Specify the number of threads (20 default)
+-e encoding : Encoding for payload (-e help for a list of encodings)
+-b cookie : Specify a cookie for the requests
+-R depth : Recursive path discovery
+-V alltype : All parameters bruteforcing (allvars and allpost). No need for FUZZ keyword.
+
+--basic auth : in format "user:pass" or "FUZZ:FUZZ"
+--ntlm auth : in format "domain\user:pass" or "domain\FUZ2Z:FUZZ"
+--digest auth : in format "user:pass" or "FUZZ:FUZZ"
+
+--hc N[,N]+ : Hide resposnes with the specified[s] code
+--hl N[,N]+ : Hide responses with the specified[s] number of lines
+--hw N[,N]+ : Hide responses with the specified[s] number of words
+--hh N[,N]+ : Hide responses with the specified[s] number of chars
+--html : Output in HTML format by stderr \r\n
+
+Keyword: FUZZ,FUZ2Z wherever you put these words wfuzz will replace them by the payload selected.
+
+Examples in the README.
+''' % (sys.argv[0])
+
+
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "cx:b:e:R:d:z:r:f:t:w:V:H:",['hc=','hh=','hl=','hw=','ntlm=','basic=','digest=','html'])
+ optsd=dict(opts)
+ if "-e" in optsd:
+ if optsd["-e"] == "help":
+ print "Available encodings:"
+ for i in ENCODERS.keys():
+ print " - "+i
+ sys.exit(0)
+ url=args[0]
+ if not "-z" in optsd:
+ raise Exception
+ except Exception,qw:
+ if str(qw) == "0":
+ sys.exit(-1)
+ print banner
+ print usage
+ sys.exit(-1)
+
+ if "-c" in optsd:
+ color=True
+
+ if "--html" in optsd:
+ html=True
+ if "--hc" in optsd:
+ hidecodes=optsd["--hc"].split(",")
+ if "--hw" in optsd:
+ hidewords=optsd["--hw"].split(",")
+ if "--hl" in optsd:
+ hidelines=optsd["--hl"].split(",")
+ if "--hh" in optsd:
+ hidechars=optsd["--hh"].split(",")
+
+ payloadtype=optsd ["-z"]
+ d2=None
+
+ if optsd ["-z"].lower()=="file":
+ try:
+ list=optsd["-f"].split(",")
+ except:
+ print banner
+ print usage
+ print"You need to set the \"-f\" option"
+ sys.exit()
+ dic1=payload_file(list[0])
+ if len (list)==2:
+ dic2=payload_file(list[1])
+ d2=dictionary()
+ d2.setpayload(dic2)
+
+ elif optsd ["-z"].lower()=="range":
+ dic1=payload_range(optsd["-r"],len(optsd["-r"].split("-")[1]))
+ elif optsd ["-z"].lower()=="hexa-range":
+ dic1=payload_hexrange(optsd["-r"])
+ elif optsd ["-z"].lower()=="hexa-rand":
+ dic1=payload_hexrand(optsd["-r"])
+
+ else:
+ print "Bad argument: -z dicttype : Specify type od dictionary (file,range,hexa-range,hexa-rand)"
+ sys.exit (-1)
+
+ d1=dictionary()
+ d1.setpayload(dic1)
+
+
+ if "-e" in optsd:
+ encodings=optsd["-e"].split(",")
+ if len(encodings) == 2:
+
+ if len(optsd["-f"].split(",")) == 2:
+ enc=select_encoding(encodings[0])
+ print encodings[0] + list[0]
+ d1.setencoder(enc)
+ enc=select_encoding(encodings[1])
+ print encodings[1] + list[1]
+ d2.setencoder(enc)
+ else:
+ enc=select_encoding(encodings[0])
+ d1.setencoder(enc)
+ elif len(encodings) ==1:
+ enc=select_encoding(encodings[0])
+ d1.setencoder(enc)
+
+
+
+ a=Request()
+ a.setUrl(url)
+
+ if "--basic" in optsd:
+ a.setAuth("basic",optsd["--basic"])
+
+ if "--digest" in optsd:
+ a.setAuth("digest",optsd["--digest"])
+
+ if "--ntlm" in optsd:
+ a.setAuth("ntlm",optsd["--ntlm"])
+
+ if "-d" in optsd:
+ a.addPostdata(optsd["-d"])
+ print "test"
+
+ if "-b" in optsd:
+ a.addHeader("Cookie",optsd["-b"])
+
+
+ proxy=None
+ if "-x" in optsd:
+ proxy=optsd["-x"]
+
+ if "-t" in optsd:
+ ths=int(optsd["-t"])
+
+ if "-R" in optsd:
+ rlevel=int(optsd["-R"])
+
+ if "-V" in optsd:
+ varset=str(optsd["-V"])
+ else:
+ varset="None"
+ if "-H" in optsd:
+ headers=str(optsd["-H"]).split(",")
+ for x in headers:
+ splitted=x.partition(":")
+ a.addHeader(splitted[0],splitted[2])
+
+ rh=requestGenerator(a,varset,d1,d2,proxy)
+
+ if html:
+ sys.stderr.write("Fuzzing %s \r\n\r\n#request Code #lines #words Url \r\n" % (url) )
+
+ fz=Fuzzer(rh,hidecodes,ths)
+
+ print banner
+ print "Target: " + url
+ print "Payload type: " + payloadtype + "\n"
+ print "Total requests: " + str(rh.count())
+
+ print "=================================================================="
+ print "ID Response Lines Word Chars Request "
+ print "==================================================================\r\n"
+ fz.Launch()
+ try:
+ while True:
+ if fz.cleanthreads():
+ limpialinea()
+ print "\r\n"
+
+ if rlevel:
+
+ current_depth+=1
+ results=fz.results
+
+ voidDicc=dictionary()
+ rh2=requestGenerator(Request(),"None",voidDicc)
+
+ for i in results:
+ if i.code==200 and i.req.completeUrl[-1]=='/':
+ i.req.setUrl(i.req.completeUrl+"FUZZ")
+ rhtemp=requestGenerator(i.req,"None",d1,None,proxy)
+ rh2.append(rhtemp)
+ elif i.code>=300 and i.code<400:
+ if i.has_header("Location") and i["Location"][-1]=='/':
+ i.req.setUrl(i["Location"]+"FUZZ")
+ print i.req
+ rhtemp=requestGenerator(i.req,"None",d1,None,proxy)
+ rh2.append(rhtemp)
+ elif i.code==401:
+ if i.req.completeUrl[-1]=='/':
+ i.req.setUrl(i.req.completeUrl+"FUZZ")
+ else:
+ i.req.setUrl(i.req.completeUrl+"/FUZZ")
+ rhtemp=requestGenerator(i.req,"None",d1,None,proxy)
+ rh2.append(rhtemp)
+
+
+ if rh2.moreRequests:
+ fz=Fuzzer(rh2,ths)
+ print "-------------- Recursion level",current_depth,"---------------"
+ print
+ fz.Launch()
+
+ rlevel-=1
+
+ continue
+
+ if html:
+ sys.stderr.write("
Wfuzz by EdgeSecurity\r\n")
+ sys.exit(0)
+
+
+ time.sleep(1)
+ except KeyboardInterrupt:
+ limpialinea()
+ sys.stdout.write("Stopping...\r\n")
+
+ fz.stop()
+
+ if html:
+ sys.stderr.write("