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
2013-01-30 21:08:34 +04:00
from lib . core . common import safeStringFormat
2012-12-21 13:15:42 +04:00
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
2012-12-06 17:14:19 +04:00
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
2019-03-28 15:53:54 +03:00
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 :
2013-01-23 17:00:58 +04:00
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 )
2012-10-28 01:16:25 +04:00
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 )
2013-01-22 14:14:35 +04:00
2013-01-23 17:00:58 +04:00
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 )
2012-10-28 02:36:09 +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 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 )
2012-12-21 13:15:42 +04:00
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 ' :
2012-12-06 17:14:19 +04:00
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 :
2013-01-23 17:00:58 +04:00
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 )
2016-10-05 18:43:57 +03:00
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 )
2012-10-28 01:16:25 +04:00
values = inject . getValue ( query , blind = False , time = False )
2012-07-20 22:17:35 +04:00
2013-01-22 14:14:35 +04:00
if values and Backend . getIdentifiedDbms ( ) in ( DBMS . SQLITE , DBMS . FIREBIRD ) :
2013-01-14 20:26:11 +04:00
newValues = [ ]
2019-03-28 15:53:54 +03:00
if isinstance ( values , six . string_types ) :
2013-01-14 20:26:11 +04:00
values = [ values ]
for value in values :
2013-01-22 13:53:05 +04:00
dbName = " SQLite " if Backend . isDbms ( DBMS . SQLITE ) else " Firebird "
newValues . append ( [ " %s %s " % ( dbName , METADB_SUFFIX ) , value ] )
2013-01-14 20:26:11 +04:00
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 ]
2013-01-22 14:14:35 +04:00
2013-01-23 17:00:58 +04:00
if not values and isInferenceAvailable ( ) and not conf . direct :
2013-01-22 13:53:05 +04:00
if Backend . getIdentifiedDbms ( ) not in ( DBMS . SQLITE , DBMS . FIREBIRD ) :
2013-01-23 17:00:58 +04:00
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 "
2013-01-23 17:00:58 +04:00
infoMsg + = " ' %s ' " % unsafeSQLIdentificatorNaming ( tbl )
logger . info ( infoMsg )
2012-07-20 22:17:35 +04:00
2013-01-23 17:00:58 +04:00
query = rootQuery . blind . count
2013-01-23 17:22:35 +04:00
query = query % ( tblQuery + whereDbsQuery )
2013-01-23 17:00:58 +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
2013-01-23 17:00:58 +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 "
2013-01-23 17:00:58 +04:00
warnMsg + = " ' %s ' " % unsafeSQLIdentificatorNaming ( tbl )
logger . warn ( warnMsg )
2012-07-20 22:17:35 +04:00
2013-01-23 17:00:58 +04:00
continue
2012-07-20 22:17:35 +04:00
2013-01-23 17:00:58 +04:00
indexRange = getLimitRange ( count )
2012-07-20 22:17:35 +04:00
2013-01-23 17:00:58 +04:00
for index in indexRange :
query = rootQuery . blind . query
2013-01-23 17:22:35 +04:00
query = query % ( tblQuery + whereDbsQuery )
2013-01-23 17:00:58 +04:00
query = agent . limitQuery ( index , query )
2012-10-25 11:56:36 +04:00
2013-01-23 17:00:58 +04:00
foundDb = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
foundDb = safeSQLIdentificatorNaming ( foundDb )
2012-07-20 22:17:35 +04:00
2013-01-23 17:00:58 +04:00
if foundDb not in foundTbls :
foundTbls [ foundDb ] = [ ]
2012-07-20 22:17:35 +04:00
2013-01-23 17:00:58 +04:00
if tblConsider == " 2 " :
foundTbls [ foundDb ] . append ( tbl )
2012-07-20 22:17:35 +04:00
2013-01-23 17:00:58 +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 ] = [ ]
2013-01-14 20:26:11 +04:00
else :
2013-01-22 13:53:05 +04:00
dbName = " SQLite " if Backend . isDbms ( DBMS . SQLITE ) else " Firebird "
foundTbls [ " %s %s " % ( dbName , METADB_SUFFIX ) ] = [ ]
2012-07-20 22:17:35 +04:00
2019-01-22 05:00:44 +03: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
2013-01-22 13:53:05 +04:00
if Backend . getIdentifiedDbms ( ) not in ( DBMS . SQLITE , DBMS . FIREBIRD ) :
2013-01-14 20:26:11 +04:00
query = query % unsafeSQLIdentificatorNaming ( db )
2012-07-20 22:17:35 +04:00
query + = " AND %s " % tblQuery
2013-01-23 17:22:35 +04:00
2012-10-28 02:36:09 +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
2013-01-22 13:53:05 +04:00
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 ' ) " ) :
2013-01-30 21:08:34 +04:00
query = query [ : - 1 ] + " AND %s ) " % tblQuery
else :
query + = " AND %s " % tblQuery
2013-01-22 13:53:05 +04:00
if Backend . isDbms ( DBMS . FIREBIRD ) :
2013-01-30 21:08:34 +04:00
query = safeStringFormat ( query , index )
2013-01-22 13:53:05 +04:00
if Backend . getIdentifiedDbms ( ) not in ( DBMS . SQLITE , DBMS . FIREBIRD ) :
2013-01-30 21:08:34 +04:00
query = safeStringFormat ( query , unsafeSQLIdentificatorNaming ( db ) )
2013-01-22 13:53:05 +04:00
if not Backend . isDbms ( DBMS . FIREBIRD ) :
query = agent . limitQuery ( index , query )
2012-10-25 11:56:36 +04:00
2012-12-21 13:15:42 +04:00
foundTbl = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
2013-02-05 14:37:49 +04:00
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
2019-01-22 05:00:44 +03: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 ]
2012-07-21 00:46:36 +04:00
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
2020-02-10 18:22:58 +03:00
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 ' :
2012-12-06 17:14:19 +04:00
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
2012-07-21 01:29:48 +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 :
2013-01-23 17:00:58 +04:00
values = [ ]
2012-07-20 22:17:35 +04:00
column = safeSQLIdentificatorNaming ( column )
2012-07-21 01:29:48 +04:00
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 ] = { }
2020-02-10 18:22:58 +03:00
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
2016-10-05 18:43:57 +03:00
if conf . db == CURRENT_DB :
conf . db = self . getCurrentDb ( )
2020-02-10 18:22:58 +03:00
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 )
2012-10-28 01:16:25 +04:00
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
2020-02-10 18:22:58 +03: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 = { }
2013-01-22 14:14:35 +04:00
2013-01-23 17:00:58 +04:00
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 )
2012-10-28 02:36:09 +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 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
2012-12-21 13:15:42 +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 ] = [ ]
2012-07-21 01:35:20 +04:00
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 :
2012-07-21 01:35:20 +04:00
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
2020-02-10 18:22:58 +03:00
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
2012-10-28 02:36:09 +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
2013-01-31 19:41:23 +04:00
2020-02-10 18:22:58 +03:00
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 ) )
2013-01-31 19:41:23 +04:00
else :
2013-02-05 15:24:57 +04:00
query + = " AND %s " % ( colQuery + whereTblsQuery )
2013-01-31 19:41:23 +04:00
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
2012-12-21 13:15:42 +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 ]
2012-12-18 22:07:34 +04:00
if dbs :
conf . dumper . dbColumns ( foundCols , colConsider , dbs )
self . dumpFoundColumn ( dbs , foundCols , colConsider )
else :
2012-07-21 00:46:36 +04:00
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 :
2012-07-21 00:46:36 +04:00
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 :
2012-07-21 00:46:36 +04:00
errMsg = " missing parameter, provide -D, -T or -C along "
2012-07-20 22:17:35 +04:00
errMsg + = " with --search "
2013-01-04 02:20:55 +04:00
raise SqlmapMissingMandatoryOptionException ( errMsg )