sqlmap/plugins/generic/search.py

636 lines
27 KiB
Python
Raw Normal View History

2019-05-08 13:47:52 +03:00
#!/usr/bin/env python
2012-07-20 22:17:35 +04:00
"""
2020-01-01 15:25:15 +03:00
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
2017-10-11 15:50:46 +03:00
See the file 'LICENSE' for copying permission
2012-07-20 22:17:35 +04:00
"""
2019-11-04 14:53:29 +03:00
import re
2012-07-20 22:17:35 +04:00
from lib.core.agent import agent
2012-10-25 11:56:36 +04:00
from lib.core.common import arrayizeValue
2012-07-20 22:17:35 +04:00
from lib.core.common import Backend
from lib.core.common import filterPairValues
from lib.core.common import getLimitRange
2013-01-22 14:16:18 +04:00
from lib.core.common import isInferenceAvailable
2012-07-20 22:17:35 +04:00
from lib.core.common import isNoneValue
from lib.core.common import isNumPosStrValue
from lib.core.common import isTechniqueAvailable
from lib.core.common import readInput
from lib.core.common import safeSQLIdentificatorNaming
from lib.core.common import safeStringFormat
from lib.core.common import unArrayizeValue
2012-07-20 22:17:35 +04:00
from lib.core.common import unsafeSQLIdentificatorNaming
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import paths
from lib.core.data import queries
from lib.core.enums import CHARSET_TYPE
from lib.core.enums import DBMS
from lib.core.enums import EXPECTED
from lib.core.enums import PAYLOAD
from lib.core.exception import SqlmapMissingMandatoryOptionException
from lib.core.exception import SqlmapUserQuitException
2012-07-20 22:17:35 +04:00
from lib.core.settings import CURRENT_DB
2013-01-19 03:04:01 +04:00
from lib.core.settings import METADB_SUFFIX
2020-01-27 19:32:31 +03:00
from lib.core.settings import UPPER_CASE_DBMSES
2012-07-20 22:17:35 +04:00
from lib.request import inject
2017-04-18 14:53:41 +03:00
from lib.utils.brute import columnExists
from lib.utils.brute import tableExists
from thirdparty import six
2012-07-20 22:17:35 +04:00
2019-05-29 17:42:04 +03:00
class Search(object):
2012-07-20 22:17:35 +04:00
"""
This class defines search functionalities for plugins.
"""
def __init__(self):
pass
def searchDb(self):
foundDbs = []
rootQuery = queries[Backend.getIdentifiedDbms()].search_db
2017-04-18 16:56:24 +03:00
dbList = conf.db.split(',')
2012-07-20 22:17:35 +04:00
if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
dbCond = rootQuery.inband.condition2
else:
dbCond = rootQuery.inband.condition
dbConsider, dbCondParam = self.likeOrExact("database")
for db in dbList:
values = []
2012-07-20 22:17:35 +04:00
db = safeSQLIdentificatorNaming(db)
2020-01-27 19:32:31 +03:00
if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES:
2012-07-20 22:17:35 +04:00
db = db.upper()
infoMsg = "searching database"
if dbConsider == "1":
2015-09-23 09:47:52 +03:00
infoMsg += "s LIKE"
2012-07-20 22:17:35 +04:00
infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(db)
logger.info(infoMsg)
if conf.excludeSysDbs:
exclDbsQuery = "".join(" AND '%s' != %s" % (unsafeSQLIdentificatorNaming(db), dbCond) for db in self.excludeDbsList)
infoMsg = "skipping system database%s '%s'" % ("s" if len(self.excludeDbsList) > 1 else "", ", ".join(db for db in self.excludeDbsList))
logger.info(infoMsg)
else:
exclDbsQuery = ""
dbQuery = "%s%s" % (dbCond, dbCondParam)
dbQuery = dbQuery % unsafeSQLIdentificatorNaming(db)
2012-12-05 13:45:17 +04:00
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
2012-07-20 22:17:35 +04:00
if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
query = rootQuery.inband.query2
else:
query = rootQuery.inband.query
2013-01-23 17:22:35 +04:00
query = query % (dbQuery + exclDbsQuery)
values = inject.getValue(query, blind=False, time=False)
2012-07-20 22:17:35 +04:00
if not isNoneValue(values):
2012-10-25 11:56:36 +04:00
values = arrayizeValue(values)
2012-07-20 22:17:35 +04:00
for value in values:
value = safeSQLIdentificatorNaming(value)
foundDbs.append(value)
if not values and isInferenceAvailable() and not conf.direct:
2013-01-15 21:14:58 +04:00
infoMsg = "fetching number of database"
2012-07-20 22:17:35 +04:00
if dbConsider == "1":
2015-09-23 09:47:52 +03:00
infoMsg += "s LIKE"
2012-07-20 22:17:35 +04:00
infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(db)
logger.info(infoMsg)
if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
query = rootQuery.blind.count2
else:
query = rootQuery.blind.count
2012-10-25 11:56:36 +04:00
2013-01-23 17:22:35 +04:00
query = query % (dbQuery + exclDbsQuery)
count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
2012-07-20 22:17:35 +04:00
if not isNumPosStrValue(count):
warnMsg = "no database"
if dbConsider == "1":
2015-09-23 09:47:52 +03:00
warnMsg += "s LIKE"
2012-07-20 22:17:35 +04:00
warnMsg += " '%s' found" % unsafeSQLIdentificatorNaming(db)
logger.warn(warnMsg)
continue
indexRange = getLimitRange(count)
for index in indexRange:
if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
query = rootQuery.blind.query2
else:
query = rootQuery.blind.query
2013-01-23 17:22:35 +04:00
query = query % (dbQuery + exclDbsQuery)
2012-07-20 22:17:35 +04:00
query = agent.limitQuery(index, query, dbCond)
value = unArrayizeValue(inject.getValue(query, union=False, error=False))
2012-07-20 22:17:35 +04:00
value = safeSQLIdentificatorNaming(value)
foundDbs.append(value)
2012-07-21 01:29:30 +04:00
conf.dumper.lister("found databases", foundDbs)
2012-07-20 22:17:35 +04:00
def searchTable(self):
bruteForce = False
if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
errMsg = "information_schema not available, "
errMsg += "back-end DBMS is MySQL < 5.0"
bruteForce = True
if bruteForce:
2020-02-26 19:33:47 +03:00
message = "do you want to use common table existence check? %s" % ("[Y/n/q]" if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI, DBMS.EXTREMEDB) else "[y/N/q]")
2017-04-19 15:46:27 +03:00
choice = readInput(message, default='Y' if 'Y' in message else 'N').upper()
2012-07-20 22:17:35 +04:00
2017-04-18 16:48:05 +03:00
if choice == 'N':
2017-04-18 16:56:24 +03:00
return
2017-04-18 16:48:05 +03:00
elif choice == 'Q':
raise SqlmapUserQuitException
2012-07-20 22:17:35 +04:00
else:
2017-04-18 16:48:05 +03:00
regex = '|'.join(conf.tbl.split(','))
2012-07-20 22:17:35 +04:00
return tableExists(paths.COMMON_TABLES, regex)
foundTbls = {}
2017-04-18 16:48:05 +03:00
tblList = conf.tbl.split(',')
2012-07-20 22:17:35 +04:00
rootQuery = queries[Backend.getIdentifiedDbms()].search_table
tblCond = rootQuery.inband.condition
dbCond = rootQuery.inband.condition2
tblConsider, tblCondParam = self.likeOrExact("table")
for tbl in tblList:
values = []
2012-07-20 22:17:35 +04:00
tbl = safeSQLIdentificatorNaming(tbl, True)
2020-01-27 19:32:31 +03:00
if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES:
2012-07-20 22:17:35 +04:00
tbl = tbl.upper()
2018-10-16 15:47:09 +03:00
conf.db = conf.db.upper() if conf.db else conf.db
2012-07-20 22:17:35 +04:00
infoMsg = "searching table"
2017-04-18 16:48:05 +03:00
if tblConsider == '1':
2015-09-23 09:47:52 +03:00
infoMsg += "s LIKE"
2012-07-20 22:17:35 +04:00
infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(tbl)
if conf.db == CURRENT_DB:
conf.db = self.getCurrentDb()
if dbCond and conf.db:
2017-04-18 16:56:24 +03:00
_ = conf.db.split(',')
2012-07-20 22:17:35 +04:00
whereDbsQuery = " AND (" + " OR ".join("%s = '%s'" % (dbCond, unsafeSQLIdentificatorNaming(db)) for db in _) + ")"
infoMsg += " for database%s '%s'" % ("s" if len(_) > 1 else "", ", ".join(db for db in _))
elif conf.excludeSysDbs:
whereDbsQuery = "".join(" AND '%s' != %s" % (unsafeSQLIdentificatorNaming(db), dbCond) for db in self.excludeDbsList)
2016-10-05 18:41:02 +03:00
msg = "skipping system database%s '%s'" % ("s" if len(self.excludeDbsList) > 1 else "", ", ".join(db for db in self.excludeDbsList))
logger.info(msg)
2013-01-23 18:34:20 +04:00
else:
whereDbsQuery = ""
2012-07-20 22:17:35 +04:00
logger.info(infoMsg)
tblQuery = "%s%s" % (tblCond, tblCondParam)
2013-02-15 16:54:42 +04:00
tblQuery = tblQuery % unsafeSQLIdentificatorNaming(tbl)
2012-07-20 22:17:35 +04:00
2012-12-05 13:45:17 +04:00
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
2012-07-20 22:17:35 +04:00
query = rootQuery.inband.query
2013-01-23 18:34:20 +04:00
2013-01-23 17:22:35 +04:00
query = query % (tblQuery + whereDbsQuery)
values = inject.getValue(query, blind=False, time=False)
2012-07-20 22:17:35 +04:00
if values and Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.FIREBIRD):
newValues = []
if isinstance(values, six.string_types):
values = [values]
for value in values:
dbName = "SQLite" if Backend.isDbms(DBMS.SQLITE) else "Firebird"
newValues.append(["%s%s" % (dbName, METADB_SUFFIX), value])
values = newValues
2012-07-20 22:17:35 +04:00
for foundDb, foundTbl in filterPairValues(values):
foundDb = safeSQLIdentificatorNaming(foundDb)
foundTbl = safeSQLIdentificatorNaming(foundTbl, True)
if foundDb is None or foundTbl is None:
continue
if foundDb in foundTbls:
foundTbls[foundDb].append(foundTbl)
else:
foundTbls[foundDb] = [foundTbl]
if not values and isInferenceAvailable() and not conf.direct:
if Backend.getIdentifiedDbms() not in (DBMS.SQLITE, DBMS.FIREBIRD):
if len(whereDbsQuery) == 0:
infoMsg = "fetching number of databases with table"
if tblConsider == "1":
2015-09-23 09:47:52 +03:00
infoMsg += "s LIKE"
infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(tbl)
logger.info(infoMsg)
2012-07-20 22:17:35 +04:00
query = rootQuery.blind.count
2013-01-23 17:22:35 +04:00
query = query % (tblQuery + whereDbsQuery)
count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
2012-07-20 22:17:35 +04:00
if not isNumPosStrValue(count):
warnMsg = "no databases have table"
if tblConsider == "1":
2015-09-23 09:47:52 +03:00
warnMsg += "s LIKE"
warnMsg += " '%s'" % unsafeSQLIdentificatorNaming(tbl)
logger.warn(warnMsg)
2012-07-20 22:17:35 +04:00
continue
2012-07-20 22:17:35 +04:00
indexRange = getLimitRange(count)
2012-07-20 22:17:35 +04:00
for index in indexRange:
query = rootQuery.blind.query
2013-01-23 17:22:35 +04:00
query = query % (tblQuery + whereDbsQuery)
query = agent.limitQuery(index, query)
2012-10-25 11:56:36 +04:00
foundDb = unArrayizeValue(inject.getValue(query, union=False, error=False))
foundDb = safeSQLIdentificatorNaming(foundDb)
2012-07-20 22:17:35 +04:00
if foundDb not in foundTbls:
foundTbls[foundDb] = []
2012-07-20 22:17:35 +04:00
if tblConsider == "2":
foundTbls[foundDb].append(tbl)
2012-07-20 22:17:35 +04:00
if tblConsider == "2":
continue
else:
2017-04-18 16:56:24 +03:00
for db in conf.db.split(',') if conf.db else (self.getCurrentDb(),):
2013-02-18 17:40:39 +04:00
db = safeSQLIdentificatorNaming(db)
2013-01-23 17:02:02 +04:00
if db not in foundTbls:
2013-02-18 17:40:39 +04:00
foundTbls[db] = []
else:
dbName = "SQLite" if Backend.isDbms(DBMS.SQLITE) else "Firebird"
foundTbls["%s%s" % (dbName, METADB_SUFFIX)] = []
2012-07-20 22:17:35 +04:00
for db in foundTbls:
2012-07-20 22:17:35 +04:00
db = safeSQLIdentificatorNaming(db)
infoMsg = "fetching number of table"
if tblConsider == "1":
2015-09-23 09:47:52 +03:00
infoMsg += "s LIKE"
2013-02-15 17:26:50 +04:00
infoMsg += " '%s' in database '%s'" % (unsafeSQLIdentificatorNaming(tbl), unsafeSQLIdentificatorNaming(db))
2012-07-20 22:17:35 +04:00
logger.info(infoMsg)
query = rootQuery.blind.count2
if Backend.getIdentifiedDbms() not in (DBMS.SQLITE, DBMS.FIREBIRD):
query = query % unsafeSQLIdentificatorNaming(db)
2012-07-20 22:17:35 +04:00
query += " AND %s" % tblQuery
2013-01-23 17:22:35 +04:00
count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
2012-07-20 22:17:35 +04:00
if not isNumPosStrValue(count):
warnMsg = "no table"
if tblConsider == "1":
2015-09-23 09:47:52 +03:00
warnMsg += "s LIKE"
2012-07-20 22:17:35 +04:00
warnMsg += " '%s' " % unsafeSQLIdentificatorNaming(tbl)
2013-02-15 17:21:51 +04:00
warnMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(db)
2012-07-20 22:17:35 +04:00
logger.warn(warnMsg)
continue
indexRange = getLimitRange(count)
for index in indexRange:
query = rootQuery.blind.query2
2018-10-16 15:47:09 +03:00
if " ORDER BY " in query:
query = query.replace(" ORDER BY ", "%s ORDER BY " % (" AND %s" % tblQuery))
elif query.endswith("'%s')"):
query = query[:-1] + " AND %s)" % tblQuery
else:
query += " AND %s" % tblQuery
if Backend.isDbms(DBMS.FIREBIRD):
query = safeStringFormat(query, index)
if Backend.getIdentifiedDbms() not in (DBMS.SQLITE, DBMS.FIREBIRD):
query = safeStringFormat(query, unsafeSQLIdentificatorNaming(db))
if not Backend.isDbms(DBMS.FIREBIRD):
query = agent.limitQuery(index, query)
2012-10-25 11:56:36 +04:00
foundTbl = unArrayizeValue(inject.getValue(query, union=False, error=False))
if not isNoneValue(foundTbl):
2013-02-05 14:23:22 +04:00
kb.hintValue = foundTbl
foundTbl = safeSQLIdentificatorNaming(foundTbl, True)
foundTbls[db].append(foundTbl)
2012-07-20 22:17:35 +04:00
for db in list(foundTbls.keys()):
2013-02-05 14:23:22 +04:00
if isNoneValue(foundTbls[db]):
2013-02-05 14:18:46 +04:00
del foundTbls[db]
if not foundTbls:
warnMsg = "no databases contain any of the provided tables"
logger.warn(warnMsg)
return
conf.dumper.dbTables(foundTbls)
self.dumpFoundTables(foundTbls)
2012-07-20 22:17:35 +04:00
def searchColumn(self):
bruteForce = False
self.forceDbmsEnum()
2012-07-20 22:17:35 +04:00
if Backend.isDbms(DBMS.MYSQL) and not kb.data.has_information_schema:
errMsg = "information_schema not available, "
errMsg += "back-end DBMS is MySQL < 5.0"
bruteForce = True
if bruteForce:
2020-02-26 19:33:47 +03:00
message = "do you want to use common column existence check? %s" % ("[Y/n/q]" if Backend.getIdentifiedDbms() in (DBMS.ACCESS, DBMS.MCKOI, DBMS.EXTREMEDB) else "[y/N/q]")
2017-04-18 16:48:05 +03:00
choice = readInput(message, default='Y' if 'Y' in message else 'N').upper()
2012-07-20 22:17:35 +04:00
2017-04-18 16:48:05 +03:00
if choice == 'N':
2012-07-20 22:17:35 +04:00
return
2017-04-18 16:48:05 +03:00
elif choice == 'Q':
raise SqlmapUserQuitException
2012-07-20 22:17:35 +04:00
else:
2014-01-13 13:05:49 +04:00
regex = '|'.join(conf.col.split(','))
2012-07-20 22:17:35 +04:00
conf.dumper.dbTableColumns(columnExists(paths.COMMON_COLUMNS, regex))
message = "do you want to dump entries? [Y/n] "
2017-04-18 16:48:05 +03:00
if readInput(message, default='Y', boolean=True):
2012-07-20 22:17:35 +04:00
self.dumpAll()
return
rootQuery = queries[Backend.getIdentifiedDbms()].search_column
foundCols = {}
dbs = {}
whereDbsQuery = ""
whereTblsQuery = ""
infoMsgTbl = ""
infoMsgDb = ""
2017-04-18 16:56:24 +03:00
colList = conf.col.split(',')
2014-01-13 13:05:49 +04:00
2018-02-13 17:53:50 +03:00
if conf.exclude:
2019-11-04 14:53:29 +03:00
colList = [_ for _ in colList if re.search(conf.exclude, _, re.I) is None]
2014-01-13 13:05:49 +04:00
origTbl = conf.tbl
origDb = conf.db
2012-07-20 22:17:35 +04:00
colCond = rootQuery.inband.condition
dbCond = rootQuery.inband.condition2
tblCond = rootQuery.inband.condition3
colConsider, colCondParam = self.likeOrExact("column")
for column in colList:
values = []
2012-07-20 22:17:35 +04:00
column = safeSQLIdentificatorNaming(column)
conf.db = origDb
conf.tbl = origTbl
2012-07-20 22:17:35 +04:00
2020-01-27 19:32:31 +03:00
if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES:
2012-07-20 22:17:35 +04:00
column = column.upper()
2018-10-16 15:47:09 +03:00
conf.db = conf.db.upper() if conf.db else conf.db
conf.tbl = conf.tbl.upper() if conf.tbl else conf.tbl
2012-07-20 22:17:35 +04:00
infoMsg = "searching column"
if colConsider == "1":
2015-09-23 09:47:52 +03:00
infoMsg += "s LIKE"
2012-07-20 22:17:35 +04:00
infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(column)
foundCols[column] = {}
if tblCond:
if conf.tbl:
_ = conf.tbl.split(',')
whereTblsQuery = " AND (" + " OR ".join("%s = '%s'" % (tblCond, unsafeSQLIdentificatorNaming(tbl)) for tbl in _) + ")"
infoMsgTbl = " for table%s '%s'" % ("s" if len(_) > 1 else "", ", ".join(unsafeSQLIdentificatorNaming(tbl) for tbl in _))
2012-07-20 22:17:35 +04:00
if conf.db == CURRENT_DB:
conf.db = self.getCurrentDb()
if dbCond:
if conf.db:
_ = conf.db.split(',')
whereDbsQuery = " AND (" + " OR ".join("%s = '%s'" % (dbCond, unsafeSQLIdentificatorNaming(db)) for db in _) + ")"
infoMsgDb = " in database%s '%s'" % ("s" if len(_) > 1 else "", ", ".join(unsafeSQLIdentificatorNaming(db) for db in _))
elif conf.excludeSysDbs:
whereDbsQuery = "".join(" AND %s != '%s'" % (dbCond, unsafeSQLIdentificatorNaming(db)) for db in self.excludeDbsList)
msg = "skipping system database%s '%s'" % ("s" if len(self.excludeDbsList) > 1 else "", ", ".join(unsafeSQLIdentificatorNaming(db) for db in self.excludeDbsList))
logger.info(msg)
else:
infoMsgDb = " across all databases"
2012-07-20 22:17:35 +04:00
logger.info("%s%s%s" % (infoMsg, infoMsgTbl, infoMsgDb))
colQuery = "%s%s" % (colCond, colCondParam)
colQuery = colQuery % unsafeSQLIdentificatorNaming(column)
2012-12-05 13:45:17 +04:00
if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:
2012-07-20 22:17:35 +04:00
if not all((conf.db, conf.tbl)):
# Enumerate tables containing the column provided if
# either of database(s) or table(s) is not provided
query = rootQuery.inband.query
2013-01-23 17:22:35 +04:00
query = query % (colQuery + whereDbsQuery + whereTblsQuery)
values = inject.getValue(query, blind=False, time=False)
2012-07-20 22:17:35 +04:00
else:
# Assume provided databases' tables contain the
# column(s) provided
values = []
2017-04-18 16:56:24 +03:00
for db in conf.db.split(','):
for tbl in conf.tbl.split(','):
2013-02-18 17:40:39 +04:00
values.append([safeSQLIdentificatorNaming(db), safeSQLIdentificatorNaming(tbl, True)])
2012-07-20 22:17:35 +04:00
if Backend.getIdentifiedDbms() in (DBMS.FIREBIRD,):
values = [(conf.db, value) for value in arrayizeValue(values)]
2012-07-20 22:17:35 +04:00
for db, tbl in filterPairValues(values):
db = safeSQLIdentificatorNaming(db)
2017-04-18 16:56:24 +03:00
tbls = tbl.split(',') if not isNoneValue(tbl) else []
2012-07-20 22:17:35 +04:00
for tbl in tbls:
tbl = safeSQLIdentificatorNaming(tbl, True)
if db is None or tbl is None:
continue
conf.db = db
conf.tbl = tbl
conf.col = column
self.getColumns(onlyColNames=True, colTuple=(colConsider, colCondParam), bruteForce=False)
if db in kb.data.cachedColumns and tbl in kb.data.cachedColumns[db]:
if db not in dbs:
dbs[db] = {}
if tbl not in dbs[db]:
dbs[db][tbl] = {}
dbs[db][tbl].update(kb.data.cachedColumns[db][tbl])
if db in foundCols[column]:
foundCols[column][db].append(tbl)
else:
foundCols[column][db] = [tbl]
kb.data.cachedColumns = {}
if not values and isInferenceAvailable() and not conf.direct:
2012-07-20 22:17:35 +04:00
if not conf.db:
infoMsg = "fetching number of databases with tables containing column"
if colConsider == "1":
2015-09-23 09:47:52 +03:00
infoMsg += "s LIKE"
2013-02-15 17:26:50 +04:00
infoMsg += " '%s'" % unsafeSQLIdentificatorNaming(column)
2012-07-20 22:17:35 +04:00
logger.info("%s%s%s" % (infoMsg, infoMsgTbl, infoMsgDb))
query = rootQuery.blind.count
2013-01-23 17:22:35 +04:00
query = query % (colQuery + whereDbsQuery + whereTblsQuery)
count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
2012-07-20 22:17:35 +04:00
if not isNumPosStrValue(count):
warnMsg = "no databases have tables containing column"
if colConsider == "1":
2015-09-23 09:47:52 +03:00
warnMsg += "s LIKE"
2013-02-15 17:26:50 +04:00
warnMsg += " '%s'" % unsafeSQLIdentificatorNaming(column)
2012-07-20 22:17:35 +04:00
logger.warn("%s%s" % (warnMsg, infoMsgTbl))
continue
indexRange = getLimitRange(count)
for index in indexRange:
query = rootQuery.blind.query
2013-01-23 17:22:35 +04:00
query = query % (colQuery + whereDbsQuery + whereTblsQuery)
2012-07-20 22:17:35 +04:00
query = agent.limitQuery(index, query)
2013-01-23 17:22:35 +04:00
db = unArrayizeValue(inject.getValue(query, union=False, error=False))
2012-07-20 22:17:35 +04:00
db = safeSQLIdentificatorNaming(db)
if db not in dbs:
dbs[db] = {}
if db not in foundCols[column]:
foundCols[column][db] = []
else:
2017-04-18 16:56:24 +03:00
for db in conf.db.split(',') if conf.db else (self.getCurrentDb(),):
2013-02-18 17:40:39 +04:00
db = safeSQLIdentificatorNaming(db)
2012-07-20 22:17:35 +04:00
if db not in foundCols[column]:
foundCols[column][db] = []
origDb = conf.db
origTbl = conf.tbl
2012-07-20 22:17:35 +04:00
for column, dbData in foundCols.items():
colQuery = "%s%s" % (colCond, colCondParam)
2013-02-15 16:54:42 +04:00
colQuery = colQuery % unsafeSQLIdentificatorNaming(column)
2012-07-20 22:17:35 +04:00
for db in dbData:
conf.db = origDb
conf.tbl = origTbl
2012-07-20 22:17:35 +04:00
infoMsg = "fetching number of tables containing column"
if colConsider == "1":
2015-09-23 09:47:52 +03:00
infoMsg += "s LIKE"
2013-02-15 17:26:50 +04:00
infoMsg += " '%s' in database '%s'" % (unsafeSQLIdentificatorNaming(column), unsafeSQLIdentificatorNaming(db))
2012-07-20 22:17:35 +04:00
logger.info(infoMsg)
query = rootQuery.blind.count2
if not re.search(r"(?i)%s\Z" % METADB_SUFFIX, db or ""):
query = query % unsafeSQLIdentificatorNaming(db)
query += " AND %s" % colQuery
else:
query = query % colQuery
2012-07-20 22:17:35 +04:00
query += whereTblsQuery
2013-01-23 17:22:35 +04:00
count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
2012-07-20 22:17:35 +04:00
if not isNumPosStrValue(count):
warnMsg = "no tables contain column"
if colConsider == "1":
2015-09-23 09:47:52 +03:00
warnMsg += "s LIKE"
2013-02-15 17:26:50 +04:00
warnMsg += " '%s' " % unsafeSQLIdentificatorNaming(column)
warnMsg += "in database '%s'" % unsafeSQLIdentificatorNaming(db)
2012-07-20 22:17:35 +04:00
logger.warn(warnMsg)
continue
indexRange = getLimitRange(count)
for index in indexRange:
query = rootQuery.blind.query2
if re.search(r"(?i)%s\Z" % METADB_SUFFIX, db or ""):
query = query % (colQuery + whereTblsQuery)
elif query.endswith("'%s')"):
2013-02-05 15:24:57 +04:00
query = query[:-1] + " AND %s)" % (colQuery + whereTblsQuery)
2020-01-31 23:24:20 +03:00
elif " ORDER BY " in query:
query = query.replace(" ORDER BY ", " AND %s ORDER BY " % (colQuery + whereTblsQuery))
else:
2013-02-05 15:24:57 +04:00
query += " AND %s" % (colQuery + whereTblsQuery)
2013-02-15 20:08:50 +04:00
query = safeStringFormat(query, unsafeSQLIdentificatorNaming(db))
2012-07-20 22:17:35 +04:00
query = agent.limitQuery(index, query)
2013-01-23 17:22:35 +04:00
tbl = unArrayizeValue(inject.getValue(query, union=False, error=False))
2012-07-20 22:17:35 +04:00
kb.hintValue = tbl
tbl = safeSQLIdentificatorNaming(tbl, True)
conf.db = db
conf.tbl = tbl
conf.col = column
self.getColumns(onlyColNames=True, colTuple=(colConsider, colCondParam), bruteForce=False)
if db in kb.data.cachedColumns and tbl in kb.data.cachedColumns[db]:
if db not in dbs:
dbs[db] = {}
if tbl not in dbs[db]:
dbs[db][tbl] = {}
dbs[db][tbl].update(kb.data.cachedColumns[db][tbl])
kb.data.cachedColumns = {}
if db in foundCols[column]:
foundCols[column][db].append(tbl)
else:
foundCols[column][db] = [tbl]
if dbs:
conf.dumper.dbColumns(foundCols, colConsider, dbs)
self.dumpFoundColumn(dbs, foundCols, colConsider)
else:
warnMsg = "no databases have tables containing any of the "
warnMsg += "provided columns"
logger.warn(warnMsg)
2012-07-20 22:17:35 +04:00
def search(self):
2020-01-27 19:32:31 +03:00
if Backend.getIdentifiedDbms() in UPPER_CASE_DBMSES:
2012-07-20 22:17:35 +04:00
for item in ('db', 'tbl', 'col'):
if getattr(conf, item, None):
setattr(conf, item, getattr(conf, item).upper())
if conf.col:
self.searchColumn()
elif conf.tbl:
self.searchTable()
2012-07-20 22:17:35 +04:00
elif conf.db:
2012-07-21 01:29:30 +04:00
self.searchDb()
2012-07-20 22:17:35 +04:00
else:
errMsg = "missing parameter, provide -D, -T or -C along "
2012-07-20 22:17:35 +04:00
errMsg += "with --search"
raise SqlmapMissingMandatoryOptionException(errMsg)