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
from lib . core . common import arrayizeValue
from lib . core . common import Backend
2016-07-15 01:10:41 +03:00
from lib . core . common import extractRegexResult
2019-03-29 04:28:16 +03:00
from lib . core . common import filterNone
2012-07-20 22:17:35 +04:00
from lib . core . common import filterPairValues
2014-05-17 17:00:09 +04:00
from lib . core . common import flattenValue
2012-07-20 22:17:35 +04:00
from lib . core . common import getLimitRange
from lib . core . common import isInferenceAvailable
from lib . core . common import isListLike
from lib . core . common import isNoneValue
from lib . core . common import isNumPosStrValue
from lib . core . common import isTechniqueAvailable
from lib . core . common import parseSqliteTableSchema
from lib . core . common import popValue
from lib . core . common import pushValue
2016-07-15 01:10:41 +03:00
from lib . core . common import randomStr
2012-07-20 22:17:35 +04:00
from lib . core . common import readInput
from lib . core . common import safeSQLIdentificatorNaming
2020-01-17 19:14:41 +03:00
from lib . core . common import safeStringFormat
2018-02-13 17:53:50 +03:00
from lib . core . common import singleTimeLogMessage
2013-07-19 15:24:35 +04:00
from lib . core . common import singleTimeWarnMessage
2012-07-20 22:17:35 +04:00
from lib . core . common import unArrayizeValue
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
2018-04-01 13:45:47 +03:00
from lib . core . decorators import stackedmethod
2020-02-07 16:02:45 +03:00
from lib . core . dicts import ALTIBASE_TYPES
2012-08-21 13:30:01 +04:00
from lib . core . dicts import FIREBIRD_TYPES
2016-09-23 19:03:31 +03:00
from lib . core . dicts import INFORMIX_TYPES
2012-07-20 22:17:35 +04:00
from lib . core . enums import CHARSET_TYPE
from lib . core . enums import DBMS
from lib . core . enums import EXPECTED
2020-02-10 18:22:58 +03:00
from lib . core . enums import FORK
2012-07-20 22:17:35 +04:00
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 SqlmapNoneDataException
from lib . core . exception import SqlmapUserQuitException
2012-07-20 22:17:35 +04:00
from lib . core . settings import CURRENT_DB
2019-05-29 16:52:33 +03:00
from lib . core . settings import REFLECTED_VALUE_MARKER
2020-01-27 19:32:31 +03:00
from lib . core . settings import UPPER_CASE_DBMSES
2020-01-21 17:40:59 +03:00
from lib . core . settings import VERTICA_DEFAULT_SCHEMA
2012-07-20 22:17:35 +04:00
from lib . request import inject
2016-07-15 01:10:41 +03:00
from lib . techniques . union . use import unionUse
2017-04-18 14:53:41 +03:00
from lib . utils . brute import columnExists
from lib . utils . brute import tableExists
2019-03-28 16:12:11 +03:00
from thirdparty import six
2012-07-20 22:17:35 +04:00
2019-05-29 17:42:04 +03:00
class Databases ( object ) :
2012-07-20 22:17:35 +04:00
"""
This class defines databases ' enumeration functionalities for plugins.
"""
def __init__ ( self ) :
kb . data . currentDb = " "
kb . data . cachedDbs = [ ]
kb . data . cachedTables = { }
kb . data . cachedColumns = { }
kb . data . cachedCounts = { }
kb . data . dumpedTable = { }
2019-05-29 16:52:33 +03:00
kb . data . cachedStatements = [ ]
2012-07-20 22:17:35 +04:00
def getCurrentDb ( self ) :
infoMsg = " fetching current database "
logger . info ( infoMsg )
query = queries [ Backend . getIdentifiedDbms ( ) ] . current_db . query
if not kb . data . currentDb :
kb . data . currentDb = unArrayizeValue ( inject . getValue ( query , safeCharEncode = False ) )
2020-01-21 17:40:59 +03:00
if not kb . data . currentDb and Backend . isDbms ( DBMS . VERTICA ) :
kb . data . currentDb = VERTICA_DEFAULT_SCHEMA
2020-02-02 16:51:24 +03:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . PGSQL , DBMS . MONETDB , DBMS . DERBY , DBMS . VERTICA , DBMS . PRESTO , DBMS . MIMERSQL , DBMS . CRATEDB ) :
2013-07-19 15:24:35 +04:00
warnMsg = " on %s you ' ll need to use " % Backend . getIdentifiedDbms ( )
warnMsg + = " schema names for enumeration as the counterpart to database "
warnMsg + = " names on other DBMSes "
singleTimeWarnMessage ( warnMsg )
2020-02-03 03:58:12 +03:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ALTIBASE , DBMS . CUBRID ) :
2020-01-27 19:32:31 +03:00
warnMsg = " on %s you ' ll need to use " % Backend . getIdentifiedDbms ( )
warnMsg + = " user names for enumeration as the counterpart to database "
warnMsg + = " names on other DBMSes "
singleTimeWarnMessage ( warnMsg )
2013-07-19 15:24:35 +04:00
2012-07-20 22:17:35 +04:00
return kb . data . currentDb
def getDbs ( self ) :
if len ( kb . data . cachedDbs ) > 0 :
return kb . data . cachedDbs
infoMsg = None
if Backend . isDbms ( DBMS . MYSQL ) and not kb . data . has_information_schema :
warnMsg = " information_schema not available, "
warnMsg + = " back-end DBMS is MySQL < 5. database "
warnMsg + = " names will be fetched from ' mysql ' database "
logger . warn ( warnMsg )
2020-02-02 16:51:24 +03:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . PGSQL , DBMS . MONETDB , DBMS . DERBY , DBMS . VERTICA , DBMS . PRESTO , DBMS . MIMERSQL , DBMS . CRATEDB ) :
2013-07-19 15:24:35 +04:00
warnMsg = " schema names are going to be used on %s " % Backend . getIdentifiedDbms ( )
2012-07-20 22:17:35 +04:00
warnMsg + = " for enumeration as the counterpart to database "
warnMsg + = " names on other DBMSes "
logger . warn ( warnMsg )
infoMsg = " fetching database (schema) names "
2020-02-03 03:58:12 +03:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ALTIBASE , DBMS . CUBRID ) :
2020-01-27 19:32:31 +03:00
warnMsg = " user names are going to be used on %s " % Backend . getIdentifiedDbms ( )
warnMsg + = " for enumeration as the counterpart to database "
warnMsg + = " names on other DBMSes "
logger . warn ( warnMsg )
infoMsg = " fetching database (user) names "
2012-07-20 22:17:35 +04:00
else :
infoMsg = " fetching database names "
if infoMsg :
logger . info ( infoMsg )
rootQuery = queries [ Backend . getIdentifiedDbms ( ) ] . dbs
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
2012-12-21 13:15:42 +04:00
values = inject . getValue ( query , blind = False , time = False )
2012-07-20 22:17:35 +04:00
2012-12-21 13:15:42 +04:00
if not isNoneValue ( values ) :
kb . data . cachedDbs = arrayizeValue ( values )
2012-07-20 22:17:35 +04:00
if not kb . data . cachedDbs and isInferenceAvailable ( ) and not conf . direct :
infoMsg = " fetching number of databases "
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-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 ) :
errMsg = " unable to retrieve the number of databases "
logger . error ( errMsg )
else :
2020-01-27 19:32:31 +03:00
plusOne = Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . ALTIBASE )
2012-07-20 22:17:35 +04:00
indexRange = getLimitRange ( count , plusOne = plusOne )
for index in indexRange :
if Backend . isDbms ( DBMS . SYBASE ) :
query = rootQuery . blind . query % ( kb . data . cachedDbs [ - 1 ] if kb . data . cachedDbs else " " )
elif Backend . isDbms ( DBMS . MYSQL ) and not kb . data . has_information_schema :
query = rootQuery . blind . query2 % index
else :
query = rootQuery . blind . query % index
2019-05-29 16:52:33 +03: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
2019-05-29 16:52:33 +03:00
if not isNoneValue ( db ) :
2012-07-20 22:17:35 +04:00
kb . data . cachedDbs . append ( safeSQLIdentificatorNaming ( db ) )
if not kb . data . cachedDbs and Backend . isDbms ( DBMS . MSSQL ) :
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
blinds = ( False , True )
else :
blinds = ( True , )
for blind in blinds :
count = 0
kb . data . cachedDbs = [ ]
while True :
query = rootQuery . inband . query2 % count
2012-12-06 18:55:33 +04:00
value = unArrayizeValue ( inject . getValue ( query , blind = blind ) )
if not ( value or " " ) . strip ( ) :
2012-07-20 22:17:35 +04:00
break
else :
2012-12-06 18:55:33 +04:00
kb . data . cachedDbs . append ( value )
2012-07-20 22:17:35 +04:00
count + = 1
if kb . data . cachedDbs :
break
if not kb . data . cachedDbs :
infoMsg = " falling back to current database "
logger . info ( infoMsg )
self . getCurrentDb ( )
if kb . data . currentDb :
kb . data . cachedDbs = [ kb . data . currentDb ]
else :
errMsg = " unable to retrieve the database names "
2013-01-04 02:20:55 +04:00
raise SqlmapNoneDataException ( errMsg )
2012-07-20 22:17:35 +04:00
else :
kb . data . cachedDbs . sort ( )
2012-12-18 12:55:33 +04:00
if kb . data . cachedDbs :
2019-01-22 05:14:23 +03:00
kb . data . cachedDbs = [ _ for _ in set ( flattenValue ( kb . data . cachedDbs ) ) if _ ]
2012-12-18 12:55:33 +04:00
2012-07-20 22:17:35 +04:00
return kb . data . cachedDbs
def getTables ( self , bruteForce = None ) :
if len ( kb . data . cachedTables ) > 0 :
return kb . data . cachedTables
self . forceDbmsEnum ( )
if bruteForce is None :
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 "
logger . error ( errMsg )
bruteForce = True
2020-01-23 01:41:06 +03:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . MCKOI , ) :
bruteForce = True
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ACCESS , ) :
2012-07-20 22:17:35 +04:00
try :
tables = self . getTables ( False )
2012-12-06 17:14:19 +04:00
except SqlmapNoneDataException :
2012-07-20 22:17:35 +04:00
tables = None
if not tables :
errMsg = " cannot retrieve table names, "
2020-01-23 01:41:06 +03:00
errMsg + = " back-end DBMS is %s " % Backend . getIdentifiedDbms ( )
2012-07-20 22:17:35 +04:00
logger . error ( errMsg )
bruteForce = True
else :
return tables
if conf . db == CURRENT_DB :
conf . db = self . getCurrentDb ( )
2020-01-27 19:32:31 +03:00
if conf . db and Backend . getIdentifiedDbms ( ) in UPPER_CASE_DBMSES :
2012-07-20 22:17:35 +04:00
conf . db = conf . db . upper ( )
if conf . db :
2017-04-18 16:56:24 +03:00
dbs = conf . db . split ( ' , ' )
2012-07-20 22:17:35 +04:00
else :
dbs = self . getDbs ( )
2014-06-22 02:19:10 +04:00
dbs = [ _ for _ in dbs if _ and _ . strip ( ) ]
2012-07-20 22:17:35 +04:00
for db in dbs :
dbs [ dbs . index ( db ) ] = safeSQLIdentificatorNaming ( db )
if bruteForce :
resumeAvailable = False
for db , table in kb . brute . tables :
if db == conf . db :
resumeAvailable = True
break
2014-02-05 18:11:39 +04:00
if resumeAvailable and not conf . freshQueries :
2012-07-20 22:17:35 +04:00
for db , table in kb . brute . tables :
if db == conf . db :
if conf . db not in kb . data . cachedTables :
kb . data . cachedTables [ conf . db ] = [ table ]
else :
kb . data . cachedTables [ conf . db ] . append ( table )
return kb . data . cachedTables
2020-01-23 01:41:06 +03:00
message = " do you want to use common table existence check? %s " % ( " [Y/n/q] " if Backend . getIdentifiedDbms ( ) in ( DBMS . ACCESS , DBMS . MCKOI ) 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 ' :
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 :
return tableExists ( paths . COMMON_TABLES )
infoMsg = " fetching tables for database "
2013-02-15 19:48:58 +04:00
infoMsg + = " %s : ' %s ' " % ( " s " if len ( dbs ) > 1 else " " , " , " . join ( unsafeSQLIdentificatorNaming ( unArrayizeValue ( db ) ) for db in sorted ( dbs ) ) )
2012-07-20 22:17:35 +04:00
logger . info ( infoMsg )
rootQuery = queries [ Backend . getIdentifiedDbms ( ) ] . tables
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 :
2018-09-07 12:53:43 +03:00
values = [ ]
2012-07-20 22:17:35 +04:00
2018-09-07 12:53:43 +03:00
for query , condition in ( ( rootQuery . inband . query , getattr ( rootQuery . inband , " condition " , None ) ) , ( getattr ( rootQuery . inband , " query2 " , None ) , getattr ( rootQuery . inband , " condition2 " , None ) ) ) :
if not isNoneValue ( values ) or not query :
break
2012-12-17 18:07:28 +04:00
2018-09-07 12:53:43 +03:00
if condition :
if not Backend . isDbms ( DBMS . SQLITE ) :
query + = " WHERE %s " % condition
2012-07-20 22:17:35 +04:00
2018-09-07 12:53:43 +03:00
if conf . excludeSysDbs :
infoMsg = " skipping system database %s ' %s ' " % ( " s " if len ( self . excludeDbsList ) > 1 else " " , " , " . join ( unsafeSQLIdentificatorNaming ( db ) for db in self . excludeDbsList ) )
logger . info ( infoMsg )
query + = " IN ( %s ) " % ' , ' . join ( " ' %s ' " % unsafeSQLIdentificatorNaming ( db ) for db in sorted ( dbs ) if db not in self . excludeDbsList )
else :
query + = " IN ( %s ) " % ' , ' . join ( " ' %s ' " % unsafeSQLIdentificatorNaming ( db ) for db in sorted ( dbs ) )
2012-07-20 22:17:35 +04:00
2018-09-07 12:53:43 +03:00
if len ( dbs ) < 2 and ( " %s , " % condition ) in query :
query = query . replace ( " %s , " % condition , " " , 1 )
if query :
values = inject . getValue ( query , blind = False , time = False )
2012-07-20 22:17:35 +04:00
2012-12-21 13:15:42 +04:00
if not isNoneValue ( values ) :
2019-01-22 05:14:23 +03:00
values = [ _ for _ in arrayizeValue ( values ) if _ ]
2012-07-20 22:17:35 +04:00
2012-12-21 13:15:42 +04:00
if len ( values ) > 0 and not isListLike ( values [ 0 ] ) :
2013-01-11 14:17:41 +04:00
values = [ ( dbs [ 0 ] , _ ) for _ in values ]
2012-07-20 22:17:35 +04:00
2012-12-21 13:15:42 +04:00
for db , table in filterPairValues ( values ) :
2019-05-17 01:34:11 +03:00
table = unArrayizeValue ( table )
if not isNoneValue ( table ) :
db = safeSQLIdentificatorNaming ( db )
table = safeSQLIdentificatorNaming ( table , True )
if conf . getComments :
_ = queries [ Backend . getIdentifiedDbms ( ) ] . table_comment
if hasattr ( _ , " query " ) :
2020-01-27 19:32:31 +03:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . DERBY , DBMS . ALTIBASE ) :
2019-05-17 01:34:11 +03:00
query = _ . query % ( unsafeSQLIdentificatorNaming ( db . upper ( ) ) , unsafeSQLIdentificatorNaming ( table . upper ( ) ) )
else :
query = _ . query % ( unsafeSQLIdentificatorNaming ( db ) , unsafeSQLIdentificatorNaming ( table ) )
comment = unArrayizeValue ( inject . getValue ( query , blind = False , time = False ) )
if not isNoneValue ( comment ) :
infoMsg = " retrieved comment ' %s ' for table ' %s ' " % ( comment , unsafeSQLIdentificatorNaming ( table ) )
infoMsg + = " in database ' %s ' " % unsafeSQLIdentificatorNaming ( db )
logger . info ( infoMsg )
2018-05-22 00:44:21 +03:00
else :
2019-05-17 01:34:11 +03:00
warnMsg = " on %s it is not " % Backend . getIdentifiedDbms ( )
2019-06-01 13:38:37 +03:00
warnMsg + = " possible to get table comments "
2019-05-17 01:34:11 +03:00
singleTimeWarnMessage ( warnMsg )
2018-05-22 00:44:21 +03:00
2019-05-17 01:34:11 +03:00
if db not in kb . data . cachedTables :
kb . data . cachedTables [ db ] = [ table ]
2018-05-22 00:44:21 +03:00
else :
2019-05-17 01:34:11 +03:00
kb . data . cachedTables [ db ] . append ( table )
2012-07-20 22:17:35 +04:00
if not kb . data . cachedTables and isInferenceAvailable ( ) and not conf . direct :
for db in dbs :
if conf . excludeSysDbs and db in self . excludeDbsList :
2013-02-15 19:48:58 +04:00
infoMsg = " skipping system database ' %s ' " % unsafeSQLIdentificatorNaming ( db )
2012-07-20 22:17:35 +04:00
logger . info ( infoMsg )
2018-02-13 17:53:50 +03:00
continue
2012-07-20 22:17:35 +04:00
2019-11-04 14:53:29 +03:00
if conf . exclude and re . search ( conf . exclude , db , re . I ) is not None :
2018-02-13 17:53:50 +03:00
infoMsg = " skipping database ' %s ' " % unsafeSQLIdentificatorNaming ( db )
singleTimeLogMessage ( infoMsg )
2012-07-20 22:17:35 +04:00
continue
infoMsg = " fetching number of tables for "
infoMsg + = " database ' %s ' " % unsafeSQLIdentificatorNaming ( db )
logger . info ( infoMsg )
2020-01-23 01:41:06 +03:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . SQLITE , DBMS . FIREBIRD , DBMS . MAXDB , DBMS . ACCESS , DBMS . MCKOI ) :
2012-07-20 22:17:35 +04:00
query = rootQuery . blind . count
else :
query = rootQuery . blind . count % unsafeSQLIdentificatorNaming ( db )
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
2012-10-23 12:33:30 +04:00
if count == 0 :
warnMsg = " database ' %s ' " % unsafeSQLIdentificatorNaming ( db )
warnMsg + = " appears to be empty "
logger . warn ( warnMsg )
continue
elif not isNumPosStrValue ( count ) :
2012-07-20 22:17:35 +04:00
warnMsg = " unable to retrieve the number of "
warnMsg + = " tables for database ' %s ' " % unsafeSQLIdentificatorNaming ( db )
logger . warn ( warnMsg )
continue
tables = [ ]
2020-01-27 19:32:31 +03:00
plusOne = Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . ALTIBASE )
2012-07-20 22:17:35 +04:00
indexRange = getLimitRange ( count , plusOne = plusOne )
for index in indexRange :
if Backend . isDbms ( DBMS . SYBASE ) :
query = rootQuery . blind . query % ( db , ( kb . data . cachedTables [ - 1 ] if kb . data . cachedTables else " " ) )
2020-01-23 01:41:06 +03:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . MAXDB , DBMS . ACCESS , DBMS . MCKOI ) :
2012-07-20 22:17:35 +04:00
query = rootQuery . blind . query % ( kb . data . cachedTables [ - 1 ] if kb . data . cachedTables else " " )
elif Backend . getIdentifiedDbms ( ) in ( DBMS . SQLITE , DBMS . FIREBIRD ) :
query = rootQuery . blind . query % index
2016-09-23 13:33:27 +03:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . HSQLDB , DBMS . INFORMIX ) :
2014-03-07 18:57:41 +04:00
query = rootQuery . blind . query % ( index , unsafeSQLIdentificatorNaming ( db ) )
2012-07-20 22:17:35 +04:00
else :
query = rootQuery . blind . query % ( unsafeSQLIdentificatorNaming ( db ) , index )
2012-12-21 13:15:42 +04:00
table = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
2019-05-29 16:52:33 +03:00
2012-07-20 22:17:35 +04:00
if not isNoneValue ( table ) :
kb . hintValue = table
table = safeSQLIdentificatorNaming ( table , True )
tables . append ( table )
2018-05-22 00:44:21 +03:00
if conf . getComments :
_ = queries [ Backend . getIdentifiedDbms ( ) ] . table_comment
if hasattr ( _ , " query " ) :
2020-01-27 19:32:31 +03:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . DERBY , DBMS . ALTIBASE ) :
2018-05-22 00:44:21 +03:00
query = _ . query % ( unsafeSQLIdentificatorNaming ( db . upper ( ) ) , unsafeSQLIdentificatorNaming ( table . upper ( ) ) )
else :
query = _ . query % ( unsafeSQLIdentificatorNaming ( db ) , unsafeSQLIdentificatorNaming ( table ) )
comment = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
if not isNoneValue ( comment ) :
infoMsg = " retrieved comment ' %s ' for table ' %s ' " % ( comment , unsafeSQLIdentificatorNaming ( table ) )
infoMsg + = " in database ' %s ' " % unsafeSQLIdentificatorNaming ( db )
logger . info ( infoMsg )
else :
warnMsg = " on %s it is not " % Backend . getIdentifiedDbms ( )
2019-06-01 13:38:37 +03:00
warnMsg + = " possible to get table comments "
2018-05-22 00:44:21 +03:00
singleTimeWarnMessage ( warnMsg )
2012-07-20 22:17:35 +04:00
if tables :
kb . data . cachedTables [ db ] = tables
else :
warnMsg = " unable to retrieve the table names "
warnMsg + = " for database ' %s ' " % unsafeSQLIdentificatorNaming ( db )
logger . warn ( warnMsg )
if isNoneValue ( kb . data . cachedTables ) :
kb . data . cachedTables . clear ( )
if not kb . data . cachedTables :
errMsg = " unable to retrieve the table names for any database "
if bruteForce is None :
logger . error ( errMsg )
return self . getTables ( bruteForce = True )
2015-09-24 14:44:51 +03:00
elif not conf . search :
2013-01-04 02:20:55 +04:00
raise SqlmapNoneDataException ( errMsg )
2012-07-20 22:17:35 +04:00
else :
for db , tables in kb . data . cachedTables . items ( ) :
kb . data . cachedTables [ db ] = sorted ( tables ) if tables else tables
2012-12-18 12:55:33 +04:00
if kb . data . cachedTables :
2019-01-22 05:00:44 +03:00
for db in kb . data . cachedTables :
2012-12-18 12:55:33 +04:00
kb . data . cachedTables [ db ] = list ( set ( kb . data . cachedTables [ db ] ) )
2012-07-20 22:17:35 +04:00
return kb . data . cachedTables
2015-09-22 13:33:11 +03:00
def getColumns ( self , onlyColNames = False , colTuple = None , bruteForce = None , dumpMode = False ) :
2012-07-20 22:17:35 +04:00
self . forceDbmsEnum ( )
if conf . db is None or conf . db == CURRENT_DB :
if conf . db is None :
2012-10-04 20:28:36 +04:00
warnMsg = " missing database parameter. sqlmap is going "
2012-07-20 22:17:35 +04:00
warnMsg + = " to use the current database to enumerate "
warnMsg + = " table(s) columns "
logger . warn ( warnMsg )
conf . db = self . getCurrentDb ( )
2013-07-02 17:01:49 +04:00
if not conf . db :
errMsg = " unable to retrieve the current "
errMsg + = " database name "
raise SqlmapNoneDataException ( errMsg )
2012-07-20 22:17:35 +04:00
elif conf . db is not None :
2020-01-27 19:32:31 +03:00
if Backend . getIdentifiedDbms ( ) in UPPER_CASE_DBMSES :
2012-07-20 22:17:35 +04:00
conf . db = conf . db . upper ( )
2018-03-13 15:45:42 +03:00
if ' , ' in conf . db :
2012-07-20 22:17:35 +04:00
errMsg = " only one database name is allowed when enumerating "
errMsg + = " the tables ' columns "
2013-01-04 02:20:55 +04:00
raise SqlmapMissingMandatoryOptionException ( errMsg )
2012-07-20 22:17:35 +04:00
conf . db = safeSQLIdentificatorNaming ( conf . db )
if conf . col :
2020-01-27 19:32:31 +03:00
if Backend . getIdentifiedDbms ( ) in UPPER_CASE_DBMSES :
2012-07-20 22:17:35 +04:00
conf . col = conf . col . upper ( )
2014-01-13 13:05:49 +04:00
colList = conf . col . split ( ' , ' )
2012-07-20 22:17:35 +04:00
else :
colList = [ ]
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-20 22:17:35 +04:00
for col in colList :
colList [ colList . index ( col ) ] = safeSQLIdentificatorNaming ( col )
2019-01-22 05:14:23 +03:00
colList = [ _ for _ in colList if _ ]
2012-07-20 22:17:35 +04:00
if conf . tbl :
2020-01-27 19:32:31 +03:00
if Backend . getIdentifiedDbms ( ) in UPPER_CASE_DBMSES :
2012-07-20 22:17:35 +04:00
conf . tbl = conf . tbl . upper ( )
2017-04-18 16:56:24 +03:00
tblList = conf . tbl . split ( ' , ' )
2012-07-20 22:17:35 +04:00
else :
self . getTables ( )
if len ( kb . data . cachedTables ) > 0 :
if conf . db in kb . data . cachedTables :
tblList = kb . data . cachedTables [ conf . db ]
else :
2019-05-15 11:30:47 +03:00
tblList = list ( six . itervalues ( kb . data . cachedTables ) )
2012-07-20 22:17:35 +04:00
2019-05-15 11:30:47 +03:00
if tblList and isListLike ( tblList [ 0 ] ) :
2012-07-20 22:17:35 +04:00
tblList = tblList [ 0 ]
tblList = list ( tblList )
2015-09-24 14:44:51 +03:00
elif not conf . search :
2012-07-20 22:17:35 +04:00
errMsg = " unable to retrieve the tables "
errMsg + = " in database ' %s ' " % unsafeSQLIdentificatorNaming ( conf . db )
2013-01-04 02:20:55 +04:00
raise SqlmapNoneDataException ( errMsg )
2015-09-24 14:44:51 +03:00
else :
return kb . data . cachedColumns
2012-07-20 22:17:35 +04:00
2019-03-29 04:28:16 +03:00
tblList = filterNone ( safeSQLIdentificatorNaming ( _ , True ) for _ in tblList )
2012-07-20 22:17:35 +04:00
if bruteForce is None :
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 "
logger . error ( errMsg )
bruteForce = True
2020-01-23 01:41:06 +03:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ACCESS , DBMS . MCKOI ) :
2012-07-20 22:17:35 +04:00
errMsg = " cannot retrieve column names, "
2020-01-23 01:41:06 +03:00
errMsg + = " back-end DBMS is %s " % Backend . getIdentifiedDbms ( )
2012-07-20 22:17:35 +04:00
logger . error ( errMsg )
bruteForce = True
2012-12-18 19:31:30 +04:00
if bruteForce :
2012-07-20 22:17:35 +04:00
resumeAvailable = False
for tbl in tblList :
for db , table , colName , colType in kb . brute . columns :
if db == conf . db and table == tbl :
resumeAvailable = True
break
2014-02-05 18:11:39 +04:00
if resumeAvailable and not conf . freshQueries or colList :
2012-07-20 22:17:35 +04:00
columns = { }
for column in colList :
columns [ column ] = None
for tbl in tblList :
for db , table , colName , colType in kb . brute . columns :
if db == conf . db and table == tbl :
columns [ colName ] = colType
if conf . db in kb . data . cachedColumns :
kb . data . cachedColumns [ safeSQLIdentificatorNaming ( conf . db ) ] [ safeSQLIdentificatorNaming ( tbl , True ) ] = columns
else :
kb . data . cachedColumns [ safeSQLIdentificatorNaming ( conf . db ) ] = { safeSQLIdentificatorNaming ( tbl , True ) : columns }
return kb . data . cachedColumns
2020-01-23 01:41:06 +03:00
message = " do you want to use common column existence check? %s " % ( " [Y/n/q] " if Backend . getIdentifiedDbms ( ) in ( DBMS . ACCESS , DBMS . MCKOI ) 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 ' :
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 :
return columnExists ( paths . COMMON_COLUMNS )
rootQuery = queries [ Backend . getIdentifiedDbms ( ) ] . columns
condition = rootQuery . blind . condition if ' condition ' in rootQuery . blind else None
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
for tbl in tblList :
if conf . db is not None and len ( kb . data . cachedColumns ) > 0 \
and conf . db in kb . data . cachedColumns and tbl in \
kb . data . cachedColumns [ conf . db ] :
infoMsg = " fetched tables ' columns on "
infoMsg + = " database ' %s ' " % unsafeSQLIdentificatorNaming ( conf . db )
logger . info ( infoMsg )
return { conf . db : kb . data . cachedColumns [ conf . db ] }
infoMsg = " fetching columns "
2012-12-18 19:31:30 +04:00
condQuery = " "
2012-07-20 22:17:35 +04:00
if len ( colList ) > 0 :
2012-12-18 19:31:30 +04:00
if colTuple :
_ , colCondParam = colTuple
2015-09-22 13:03:47 +03:00
infoMsg + = " LIKE ' %s ' " % " , " . join ( unsafeSQLIdentificatorNaming ( col ) for col in sorted ( colList ) )
2012-07-20 22:17:35 +04:00
else :
2012-12-18 19:31:30 +04:00
colCondParam = " = ' %s ' "
2012-07-20 22:17:35 +04:00
infoMsg + = " ' %s ' " % " , " . join ( unsafeSQLIdentificatorNaming ( col ) for col in sorted ( colList ) )
2012-12-18 19:31:30 +04:00
condQueryStr = " %% s %s " % colCondParam
condQuery = " AND ( %s ) " % " OR " . join ( condQueryStr % ( condition , unsafeSQLIdentificatorNaming ( col ) ) for col in sorted ( colList ) )
2012-07-20 22:17:35 +04:00
2020-02-03 13:33:19 +03:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . MYSQL , DBMS . PGSQL , DBMS . HSQLDB , DBMS . H2 , DBMS . MONETDB , DBMS . VERTICA , DBMS . PRESTO , DBMS . CRATEDB , DBMS . CUBRID ) :
2012-07-20 22:17:35 +04:00
query = rootQuery . inband . query % ( unsafeSQLIdentificatorNaming ( tbl ) , unsafeSQLIdentificatorNaming ( conf . db ) )
query + = condQuery
2019-06-21 11:15:36 +03:00
2020-02-10 18:22:58 +03:00
if Backend . isFork ( FORK . DRIZZLE ) :
query = query . replace ( " column_type " , " data_type " )
2020-01-31 13:33:31 +03:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . DERBY , DBMS . ALTIBASE , DBMS . MIMERSQL ) :
2013-01-19 00:44:56 +04:00
query = rootQuery . inband . query % ( unsafeSQLIdentificatorNaming ( tbl . upper ( ) ) , unsafeSQLIdentificatorNaming ( conf . db . upper ( ) ) )
2012-07-20 22:17:35 +04:00
query + = condQuery
2019-06-21 11:15:36 +03:00
2012-07-20 22:17:35 +04:00
elif Backend . isDbms ( DBMS . MSSQL ) :
query = rootQuery . inband . query % ( conf . db , conf . db , conf . db , conf . db ,
conf . db , conf . db , conf . db , unsafeSQLIdentificatorNaming ( tbl ) . split ( " . " ) [ - 1 ] )
query + = condQuery . replace ( " [DB] " , conf . db )
2019-06-21 11:15:36 +03:00
2013-01-19 02:10:10 +04:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . SQLITE , DBMS . FIREBIRD ) :
2017-09-05 00:00:16 +03:00
query = rootQuery . inband . query % unsafeSQLIdentificatorNaming ( tbl )
2013-06-24 18:03:08 +04:00
2019-06-21 11:15:36 +03:00
elif Backend . isDbms ( DBMS . INFORMIX ) :
query = rootQuery . inband . query % ( conf . db , conf . db , conf . db , conf . db , conf . db , unsafeSQLIdentificatorNaming ( tbl ) )
query + = condQuery
2015-09-22 13:33:11 +03:00
if dumpMode and colList :
values = [ ( _ , ) for _ in colList ]
else :
infoMsg + = " for table ' %s ' " % unsafeSQLIdentificatorNaming ( tbl )
infoMsg + = " in database ' %s ' " % unsafeSQLIdentificatorNaming ( conf . db )
logger . info ( infoMsg )
2016-07-15 01:10:41 +03:00
values = None
if Backend . isDbms ( DBMS . MSSQL ) and isTechniqueAvailable ( PAYLOAD . TECHNIQUE . UNION ) :
expression = query
kb . dumpColumns = [ ]
kb . rowXmlMode = True
2019-04-05 10:38:56 +03:00
for column in ( extractRegexResult ( r " SELECT (?P<result>.+?) FROM " , query ) or " " ) . split ( ' , ' ) :
2016-07-15 01:10:41 +03:00
kb . dumpColumns . append ( randomStr ( ) . lower ( ) )
expression = expression . replace ( column , " %s AS %s " % ( column , kb . dumpColumns [ - 1 ] ) , 1 )
values = unionUse ( expression )
kb . rowXmlMode = False
kb . dumpColumns = None
if values is None :
values = inject . getValue ( query , blind = False , time = False )
2019-03-28 15:53:54 +03:00
if values and isinstance ( values [ 0 ] , six . string_types ) :
2018-08-22 18:58:00 +03:00
values = [ values ]
2012-07-20 22:17:35 +04:00
2013-01-11 14:17:41 +04:00
if Backend . isDbms ( DBMS . MSSQL ) and isNoneValue ( values ) :
index , values = 1 , [ ]
2013-01-19 00:40:38 +04:00
2013-01-11 14:17:41 +04:00
while True :
2017-09-05 00:00:16 +03:00
query = rootQuery . inband . query2 % ( conf . db , unsafeSQLIdentificatorNaming ( tbl ) , index )
2013-01-11 14:17:41 +04:00
value = unArrayizeValue ( inject . getValue ( query , blind = False , time = False ) )
2013-01-19 00:40:38 +04:00
2013-01-11 14:17:41 +04:00
if isNoneValue ( value ) or value == " " :
break
else :
values . append ( ( value , ) )
index + = 1
2012-07-20 22:17:35 +04:00
if Backend . isDbms ( DBMS . SQLITE ) :
2019-02-07 19:33:16 +03:00
if dumpMode and colList :
if conf . db not in kb . data . cachedColumns :
kb . data . cachedColumns [ conf . db ] = { }
2019-02-07 19:34:51 +03:00
kb . data . cachedColumns [ conf . db ] [ safeSQLIdentificatorNaming ( conf . tbl , True ) ] = dict ( ( _ , None ) for _ in colList )
2019-02-07 19:33:16 +03:00
else :
parseSqliteTableSchema ( unArrayizeValue ( values ) )
2012-12-21 13:15:42 +04:00
elif not isNoneValue ( values ) :
2012-07-20 22:17:35 +04:00
table = { }
columns = { }
2012-12-21 13:15:42 +04:00
for columnData in values :
2012-07-20 22:17:35 +04:00
if not isNoneValue ( columnData ) :
2019-05-09 14:14:42 +03:00
columnData = [ unArrayizeValue ( _ ) for _ in columnData ]
2012-07-20 22:17:35 +04:00
name = safeSQLIdentificatorNaming ( columnData [ 0 ] )
if name :
2013-07-29 20:25:27 +04:00
if conf . getComments :
_ = queries [ Backend . getIdentifiedDbms ( ) ] . column_comment
if hasattr ( _ , " query " ) :
2020-01-27 19:32:31 +03:00
if Backend . getIdentifiedDbms ( ) in UPPER_CASE_DBMSES :
2013-07-29 20:25:27 +04:00
query = _ . query % ( unsafeSQLIdentificatorNaming ( conf . db . upper ( ) ) , unsafeSQLIdentificatorNaming ( tbl . upper ( ) ) , unsafeSQLIdentificatorNaming ( name . upper ( ) ) )
else :
query = _ . query % ( unsafeSQLIdentificatorNaming ( conf . db ) , unsafeSQLIdentificatorNaming ( tbl ) , unsafeSQLIdentificatorNaming ( name ) )
2016-04-19 14:13:37 +03:00
2013-07-29 20:25:27 +04:00
comment = unArrayizeValue ( inject . getValue ( query , blind = False , time = False ) )
2016-04-19 14:13:37 +03:00
if not isNoneValue ( comment ) :
infoMsg = " retrieved comment ' %s ' for column ' %s ' " % ( comment , name )
logger . info ( infoMsg )
2013-07-29 20:25:27 +04:00
else :
warnMsg = " on %s it is not " % Backend . getIdentifiedDbms ( )
warnMsg + = " possible to get column comments "
singleTimeWarnMessage ( warnMsg )
2012-07-20 22:17:35 +04:00
if len ( columnData ) == 1 :
2013-01-11 14:17:41 +04:00
columns [ name ] = None
2012-07-20 22:17:35 +04:00
else :
2019-03-28 15:53:54 +03:00
key = int ( columnData [ 1 ] ) if isinstance ( columnData [ 1 ] , six . string_types ) and columnData [ 1 ] . isdigit ( ) else columnData [ 1 ]
2013-01-21 20:20:46 +04:00
if Backend . isDbms ( DBMS . FIREBIRD ) :
2016-09-23 19:03:31 +03:00
columnData [ 1 ] = FIREBIRD_TYPES . get ( key , columnData [ 1 ] )
2020-02-07 16:02:45 +03:00
elif Backend . isDbms ( DBMS . ALTIBASE ) :
columnData [ 1 ] = ALTIBASE_TYPES . get ( key , columnData [ 1 ] )
2016-09-23 19:03:31 +03:00
elif Backend . isDbms ( DBMS . INFORMIX ) :
notNull = False
if isinstance ( key , int ) and key > 255 :
key - = 256
notNull = True
columnData [ 1 ] = INFORMIX_TYPES . get ( key , columnData [ 1 ] )
if notNull :
columnData [ 1 ] = " %s NOT NULL " % columnData [ 1 ]
2013-01-21 20:20:46 +04:00
2012-07-20 22:17:35 +04:00
columns [ name ] = columnData [ 1 ]
if conf . db in kb . data . cachedColumns :
kb . data . cachedColumns [ safeSQLIdentificatorNaming ( conf . db ) ] [ safeSQLIdentificatorNaming ( tbl , True ) ] = columns
else :
table [ safeSQLIdentificatorNaming ( tbl , True ) ] = columns
kb . data . cachedColumns [ safeSQLIdentificatorNaming ( conf . db ) ] = table
elif isInferenceAvailable ( ) and not conf . direct :
for tbl in tblList :
if conf . db is not None and len ( kb . data . cachedColumns ) > 0 \
and conf . db in kb . data . cachedColumns and tbl in \
kb . data . cachedColumns [ conf . db ] :
infoMsg = " fetched tables ' columns on "
2013-02-15 19:48:58 +04:00
infoMsg + = " database ' %s ' " % unsafeSQLIdentificatorNaming ( conf . db )
2012-07-20 22:17:35 +04:00
logger . info ( infoMsg )
return { conf . db : kb . data . cachedColumns [ conf . db ] }
infoMsg = " fetching columns "
2012-12-18 19:31:30 +04:00
condQuery = " "
2012-07-20 22:17:35 +04:00
if len ( colList ) > 0 :
2012-12-18 19:31:30 +04:00
if colTuple :
_ , colCondParam = colTuple
2015-09-22 13:03:47 +03:00
infoMsg + = " LIKE ' %s ' " % " , " . join ( unsafeSQLIdentificatorNaming ( col ) for col in sorted ( colList ) )
2012-07-20 22:17:35 +04:00
else :
2012-12-18 19:31:30 +04:00
colCondParam = " = ' %s ' "
2012-07-20 22:17:35 +04:00
infoMsg + = " ' %s ' " % " , " . join ( unsafeSQLIdentificatorNaming ( col ) for col in sorted ( colList ) )
2012-12-18 19:31:30 +04:00
condQueryStr = " %% s %s " % colCondParam
condQuery = " AND ( %s ) " % " OR " . join ( condQueryStr % ( condition , unsafeSQLIdentificatorNaming ( col ) ) for col in sorted ( colList ) )
2012-07-20 22:17:35 +04:00
2020-02-03 13:33:19 +03:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . MYSQL , DBMS . PGSQL , DBMS . HSQLDB , DBMS . H2 , DBMS . MONETDB , DBMS . VERTICA , DBMS . PRESTO , DBMS . CRATEDB , DBMS . CUBRID ) :
2012-07-20 22:17:35 +04:00
query = rootQuery . blind . count % ( unsafeSQLIdentificatorNaming ( tbl ) , unsafeSQLIdentificatorNaming ( conf . db ) )
query + = condQuery
2020-01-31 13:33:31 +03:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . DERBY , DBMS . ALTIBASE , DBMS . MIMERSQL ) :
2013-01-19 00:44:56 +04:00
query = rootQuery . blind . count % ( unsafeSQLIdentificatorNaming ( tbl . upper ( ) ) , unsafeSQLIdentificatorNaming ( conf . db . upper ( ) ) )
2012-07-20 22:17:35 +04:00
query + = condQuery
elif Backend . isDbms ( DBMS . MSSQL ) :
2018-03-13 15:45:42 +03:00
query = rootQuery . blind . count % ( conf . db , conf . db , unsafeSQLIdentificatorNaming ( tbl ) . split ( " . " ) [ - 1 ] )
2012-07-20 22:17:35 +04:00
query + = condQuery . replace ( " [DB] " , conf . db )
elif Backend . isDbms ( DBMS . FIREBIRD ) :
2017-09-05 00:00:16 +03:00
query = rootQuery . blind . count % unsafeSQLIdentificatorNaming ( tbl )
2012-07-20 22:17:35 +04:00
query + = condQuery
2016-09-23 13:33:27 +03:00
elif Backend . isDbms ( DBMS . INFORMIX ) :
2017-09-05 00:00:16 +03:00
query = rootQuery . blind . count % ( conf . db , conf . db , conf . db , conf . db , conf . db , unsafeSQLIdentificatorNaming ( tbl ) )
2016-09-23 13:33:27 +03:00
query + = condQuery
2012-07-20 22:17:35 +04:00
elif Backend . isDbms ( DBMS . SQLITE ) :
2019-02-07 19:33:16 +03:00
if dumpMode and colList :
if conf . db not in kb . data . cachedColumns :
kb . data . cachedColumns [ conf . db ] = { }
2019-02-07 19:34:51 +03:00
kb . data . cachedColumns [ conf . db ] [ safeSQLIdentificatorNaming ( conf . tbl , True ) ] = dict ( ( _ , None ) for _ in colList )
2019-02-07 19:33:16 +03:00
else :
query = rootQuery . blind . query % unsafeSQLIdentificatorNaming ( tbl )
value = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
parseSqliteTableSchema ( unArrayizeValue ( value ) )
2012-07-20 22:17:35 +04:00
return kb . data . cachedColumns
table = { }
columns = { }
2015-09-22 13:33:11 +03:00
if dumpMode and colList :
count = 0
for value in colList :
columns [ safeSQLIdentificatorNaming ( value ) ] = None
else :
infoMsg + = " for table ' %s ' " % unsafeSQLIdentificatorNaming ( tbl )
infoMsg + = " in database ' %s ' " % unsafeSQLIdentificatorNaming ( conf . db )
logger . info ( infoMsg )
count = inject . getValue ( query , union = False , error = False , expected = EXPECTED . INT , charsetType = CHARSET_TYPE . DIGITS )
if not isNumPosStrValue ( count ) :
if Backend . isDbms ( DBMS . MSSQL ) :
count , index , values = 0 , 1 , [ ]
while True :
2017-09-05 00:00:16 +03:00
query = rootQuery . blind . query3 % ( conf . db , unsafeSQLIdentificatorNaming ( tbl ) , index )
2015-09-22 13:33:11 +03:00
value = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
2019-05-29 16:52:33 +03:00
2015-09-22 13:33:11 +03:00
if isNoneValue ( value ) or value == " " :
break
else :
columns [ safeSQLIdentificatorNaming ( value ) ] = None
index + = 1
2013-01-11 14:17:41 +04:00
2015-09-24 12:49:05 +03:00
if not columns :
errMsg = " unable to retrieve the %s columns " % ( " number of " if not Backend . isDbms ( DBMS . MSSQL ) else " " )
errMsg + = " for table ' %s ' " % unsafeSQLIdentificatorNaming ( tbl )
errMsg + = " in database ' %s ' " % unsafeSQLIdentificatorNaming ( conf . db )
logger . error ( errMsg )
continue
2013-01-11 14:17:41 +04:00
2012-09-07 19:06:38 +04:00
for index in getLimitRange ( count ) :
2020-02-03 13:33:19 +03:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . MYSQL , DBMS . PGSQL , DBMS . HSQLDB , DBMS . VERTICA , DBMS . PRESTO , DBMS . CRATEDB , DBMS . CUBRID ) :
2012-07-20 22:17:35 +04:00
query = rootQuery . blind . query % ( unsafeSQLIdentificatorNaming ( tbl ) , unsafeSQLIdentificatorNaming ( conf . db ) )
query + = condQuery
field = None
2018-10-16 15:47:09 +03:00
elif Backend . isDbms ( DBMS . H2 ) :
query = rootQuery . blind . query % ( unsafeSQLIdentificatorNaming ( tbl ) , unsafeSQLIdentificatorNaming ( conf . db ) )
query = query . replace ( " ORDER BY " , " %s ORDER BY " % condQuery )
field = None
2020-01-31 23:24:20 +03:00
elif Backend . isDbms ( DBMS . MIMERSQL ) :
query = rootQuery . blind . query % ( unsafeSQLIdentificatorNaming ( tbl . upper ( ) ) , unsafeSQLIdentificatorNaming ( conf . db . upper ( ) ) )
query = query . replace ( " ORDER BY " , " %s ORDER BY " % condQuery )
field = None
2020-01-17 19:14:41 +03:00
elif Backend . isDbms ( DBMS . MONETDB ) :
query = safeStringFormat ( rootQuery . blind . query , ( unsafeSQLIdentificatorNaming ( tbl ) , unsafeSQLIdentificatorNaming ( conf . db ) , index ) )
field = None
2020-01-31 23:24:20 +03:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . DERBY , DBMS . ALTIBASE ) :
2013-01-19 00:44:56 +04:00
query = rootQuery . blind . query % ( unsafeSQLIdentificatorNaming ( tbl . upper ( ) ) , unsafeSQLIdentificatorNaming ( conf . db . upper ( ) ) )
2012-07-20 22:17:35 +04:00
query + = condQuery
field = None
elif Backend . isDbms ( DBMS . MSSQL ) :
2012-09-07 19:06:38 +04:00
query = rootQuery . blind . query . replace ( " ' %s ' " , " ' %s ' " % unsafeSQLIdentificatorNaming ( tbl ) . split ( " . " ) [ - 1 ] ) . replace ( " %s " , conf . db ) . replace ( " %d " , str ( index ) )
2012-07-20 22:17:35 +04:00
query + = condQuery . replace ( " [DB] " , conf . db )
field = condition . replace ( " [DB] " , conf . db )
elif Backend . isDbms ( DBMS . FIREBIRD ) :
2017-09-05 00:00:16 +03:00
query = rootQuery . blind . query % unsafeSQLIdentificatorNaming ( tbl )
2012-07-20 22:17:35 +04:00
query + = condQuery
field = None
2016-09-23 13:33:27 +03:00
elif Backend . isDbms ( DBMS . INFORMIX ) :
2017-09-05 00:00:16 +03:00
query = rootQuery . blind . query % ( index , conf . db , conf . db , conf . db , conf . db , conf . db , unsafeSQLIdentificatorNaming ( tbl ) )
2016-09-23 13:33:27 +03:00
query + = condQuery
field = condition
2012-07-20 22:17:35 +04:00
2012-09-07 19:06:38 +04:00
query = agent . limitQuery ( index , query , field , field )
2012-12-21 13:15:42 +04:00
column = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
2012-07-20 22:17:35 +04:00
if not isNoneValue ( column ) :
2013-07-29 20:25:27 +04:00
if conf . getComments :
_ = queries [ Backend . getIdentifiedDbms ( ) ] . column_comment
if hasattr ( _ , " query " ) :
2020-01-27 19:32:31 +03:00
if Backend . getIdentifiedDbms ( ) in UPPER_CASE_DBMSES :
2013-07-29 20:25:27 +04:00
query = _ . query % ( unsafeSQLIdentificatorNaming ( conf . db . upper ( ) ) , unsafeSQLIdentificatorNaming ( tbl . upper ( ) ) , unsafeSQLIdentificatorNaming ( column . upper ( ) ) )
else :
query = _ . query % ( unsafeSQLIdentificatorNaming ( conf . db ) , unsafeSQLIdentificatorNaming ( tbl ) , unsafeSQLIdentificatorNaming ( column ) )
2016-04-19 14:13:37 +03:00
2013-07-29 20:25:27 +04:00
comment = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
2016-04-19 14:13:37 +03:00
if not isNoneValue ( comment ) :
infoMsg = " retrieved comment ' %s ' for column ' %s ' " % ( comment , column )
logger . info ( infoMsg )
2013-07-29 20:25:27 +04:00
else :
warnMsg = " on %s it is not " % Backend . getIdentifiedDbms ( )
warnMsg + = " possible to get column comments "
singleTimeWarnMessage ( warnMsg )
2012-07-20 22:17:35 +04:00
if not onlyColNames :
2020-02-02 16:51:24 +03:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . MYSQL , DBMS . PGSQL , DBMS . HSQLDB , DBMS . H2 , DBMS . VERTICA , DBMS . PRESTO , DBMS . CRATEDB ) :
2012-07-20 22:17:35 +04:00
query = rootQuery . blind . query2 % ( unsafeSQLIdentificatorNaming ( tbl ) , column , unsafeSQLIdentificatorNaming ( conf . db ) )
2020-01-31 13:33:31 +03:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . DERBY , DBMS . ALTIBASE , DBMS . MIMERSQL ) :
2013-01-19 00:44:56 +04:00
query = rootQuery . blind . query2 % ( unsafeSQLIdentificatorNaming ( tbl . upper ( ) ) , column , unsafeSQLIdentificatorNaming ( conf . db . upper ( ) ) )
2012-07-20 22:17:35 +04:00
elif Backend . isDbms ( DBMS . MSSQL ) :
2018-03-13 15:45:42 +03:00
query = rootQuery . blind . query2 % ( conf . db , conf . db , conf . db , conf . db , column , conf . db , conf . db , conf . db , unsafeSQLIdentificatorNaming ( tbl ) . split ( " . " ) [ - 1 ] )
2012-07-20 22:17:35 +04:00
elif Backend . isDbms ( DBMS . FIREBIRD ) :
2017-09-05 00:00:16 +03:00
query = rootQuery . blind . query2 % ( unsafeSQLIdentificatorNaming ( tbl ) , column )
2016-09-23 19:03:31 +03:00
elif Backend . isDbms ( DBMS . INFORMIX ) :
2017-09-05 00:00:16 +03:00
query = rootQuery . blind . query2 % ( conf . db , conf . db , conf . db , conf . db , conf . db , unsafeSQLIdentificatorNaming ( tbl ) , column )
2020-01-17 19:14:41 +03:00
elif Backend . isDbms ( DBMS . MONETDB ) :
query = rootQuery . blind . query2 % ( column , unsafeSQLIdentificatorNaming ( tbl ) , unsafeSQLIdentificatorNaming ( conf . db ) )
2012-07-20 22:17:35 +04:00
2012-12-21 13:15:42 +04:00
colType = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
2019-03-28 15:53:54 +03:00
key = int ( colType ) if hasattr ( colType , " isdigit " ) and colType . isdigit ( ) else colType
2019-05-29 16:52:33 +03:00
2012-07-20 22:17:35 +04:00
if Backend . isDbms ( DBMS . FIREBIRD ) :
2016-09-23 19:03:31 +03:00
colType = FIREBIRD_TYPES . get ( key , colType )
elif Backend . isDbms ( DBMS . INFORMIX ) :
notNull = False
if isinstance ( key , int ) and key > 255 :
key - = 256
notNull = True
colType = INFORMIX_TYPES . get ( key , colType )
if notNull :
colType = " %s NOT NULL " % colType
2012-07-20 22:17:35 +04:00
column = safeSQLIdentificatorNaming ( column )
columns [ column ] = colType
else :
column = safeSQLIdentificatorNaming ( column )
columns [ column ] = None
if columns :
if conf . db in kb . data . cachedColumns :
kb . data . cachedColumns [ safeSQLIdentificatorNaming ( conf . db ) ] [ safeSQLIdentificatorNaming ( tbl , True ) ] = columns
else :
table [ safeSQLIdentificatorNaming ( tbl , True ) ] = columns
kb . data . cachedColumns [ safeSQLIdentificatorNaming ( conf . db ) ] = table
if not kb . data . cachedColumns :
2012-12-18 20:42:03 +04:00
warnMsg = " unable to retrieve column names for "
2013-02-15 19:48:58 +04:00
warnMsg + = ( " table ' %s ' " % unsafeSQLIdentificatorNaming ( unArrayizeValue ( tblList ) ) ) if len ( tblList ) == 1 else " any table "
2012-12-18 20:42:03 +04:00
warnMsg + = " in database ' %s ' " % unsafeSQLIdentificatorNaming ( conf . db )
logger . warn ( warnMsg )
2012-07-20 22:17:35 +04:00
if bruteForce is None :
return self . getColumns ( onlyColNames = onlyColNames , colTuple = colTuple , bruteForce = True )
return kb . data . cachedColumns
2018-04-01 13:45:47 +03:00
@stackedmethod
2012-07-20 22:17:35 +04:00
def getSchema ( self ) :
infoMsg = " enumerating database management system schema "
logger . info ( infoMsg )
2015-07-18 18:01:34 +03:00
try :
pushValue ( conf . db )
pushValue ( conf . tbl )
pushValue ( conf . col )
2012-07-20 22:17:35 +04:00
2015-07-18 18:01:34 +03:00
kb . data . cachedTables = { }
kb . data . cachedColumns = { }
2012-07-20 22:17:35 +04:00
2015-07-18 18:01:34 +03:00
self . getTables ( )
2012-07-20 22:17:35 +04:00
2015-07-18 18:01:34 +03:00
infoMsg = " fetched tables: "
2019-12-12 16:10:02 +03:00
infoMsg + = " , " . join ( [ " %s " % " , " . join ( " ' %s %s %s ' " % ( unsafeSQLIdentificatorNaming ( db ) , " .. " if Backend . isDbms ( DBMS . MSSQL ) or Backend . isDbms ( DBMS . SYBASE ) else ' . ' , unsafeSQLIdentificatorNaming ( _ ) ) for _ in tbl ) for db , tbl in kb . data . cachedTables . items ( ) ] )
2015-07-18 18:01:34 +03:00
logger . info ( infoMsg )
2012-07-20 22:17:35 +04:00
2015-07-18 18:01:34 +03:00
for db , tables in kb . data . cachedTables . items ( ) :
for tbl in tables :
conf . db = db
conf . tbl = tbl
self . getColumns ( )
finally :
conf . col = popValue ( )
conf . tbl = popValue ( )
conf . db = popValue ( )
2012-07-20 22:17:35 +04:00
return kb . data . cachedColumns
2012-12-06 17:14:19 +04:00
def _tableGetCount ( self , db , table ) :
2014-12-30 12:04:41 +03:00
if not db or not table :
return None
2020-01-27 19:32:31 +03:00
if Backend . getIdentifiedDbms ( ) in UPPER_CASE_DBMSES :
2013-01-18 02:13:59 +04:00
db = db . upper ( )
table = table . upper ( )
2012-07-20 22:17:35 +04:00
2020-01-23 01:41:06 +03:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . SQLITE , DBMS . ACCESS , DBMS . FIREBIRD , DBMS . MCKOI ) :
2013-01-19 03:07:16 +04:00
query = " SELECT %s FROM %s " % ( queries [ Backend . getIdentifiedDbms ( ) ] . count . query % ' * ' , safeSQLIdentificatorNaming ( table , True ) )
else :
query = " SELECT %s FROM %s . %s " % ( queries [ Backend . getIdentifiedDbms ( ) ] . count . query % ' * ' , safeSQLIdentificatorNaming ( db ) , safeSQLIdentificatorNaming ( table , True ) )
2019-02-15 18:54:43 +03:00
query = agent . whereQuery ( query )
2012-07-20 22:17:35 +04:00
count = inject . getValue ( query , expected = EXPECTED . INT , charsetType = CHARSET_TYPE . DIGITS )
if isNumPosStrValue ( count ) :
if safeSQLIdentificatorNaming ( db ) not in kb . data . cachedCounts :
kb . data . cachedCounts [ safeSQLIdentificatorNaming ( db ) ] = { }
if int ( count ) in kb . data . cachedCounts [ safeSQLIdentificatorNaming ( db ) ] :
kb . data . cachedCounts [ safeSQLIdentificatorNaming ( db ) ] [ int ( count ) ] . append ( safeSQLIdentificatorNaming ( table , True ) )
else :
kb . data . cachedCounts [ safeSQLIdentificatorNaming ( db ) ] [ int ( count ) ] = [ safeSQLIdentificatorNaming ( table , True ) ]
def getCount ( self ) :
if not conf . tbl :
warnMsg = " missing table parameter, sqlmap will retrieve "
warnMsg + = " the number of entries for all database "
warnMsg + = " management system databases ' tables "
logger . warn ( warnMsg )
elif " . " in conf . tbl :
if not conf . db :
2015-09-09 15:46:06 +03:00
conf . db , conf . tbl = conf . tbl . split ( ' . ' , 1 )
2012-07-20 22:17:35 +04:00
2020-01-23 01:41:06 +03:00
if conf . tbl is not None and conf . db is None and Backend . getIdentifiedDbms ( ) not in ( DBMS . SQLITE , DBMS . ACCESS , DBMS . FIREBIRD , DBMS . MCKOI ) :
2012-10-04 20:28:36 +04:00
warnMsg = " missing database parameter. sqlmap is going to "
2012-07-20 22:17:35 +04:00
warnMsg + = " use the current database to retrieve the "
warnMsg + = " number of entries for table ' %s ' " % unsafeSQLIdentificatorNaming ( conf . tbl )
logger . warn ( warnMsg )
conf . db = self . getCurrentDb ( )
self . forceDbmsEnum ( )
if conf . tbl :
2017-04-18 16:56:24 +03:00
for table in conf . tbl . split ( ' , ' ) :
2012-12-06 17:14:19 +04:00
self . _tableGetCount ( conf . db , table )
2012-07-20 22:17:35 +04:00
else :
self . getTables ( )
for db , tables in kb . data . cachedTables . items ( ) :
for table in tables :
2012-12-06 17:14:19 +04:00
self . _tableGetCount ( db , table )
2012-07-20 22:17:35 +04:00
return kb . data . cachedCounts
2019-05-29 16:52:33 +03:00
def getStatements ( self ) :
infoMsg = " fetching SQL statements "
logger . info ( infoMsg )
rootQuery = queries [ Backend . getIdentifiedDbms ( ) ] . statements
if any ( isTechniqueAvailable ( _ ) for _ in ( PAYLOAD . TECHNIQUE . UNION , PAYLOAD . TECHNIQUE . ERROR , PAYLOAD . TECHNIQUE . QUERY ) ) or conf . direct :
2020-02-10 18:22:58 +03:00
if Backend . isFork ( FORK . DRIZZLE ) :
query = rootQuery . inband . query2
else :
query = rootQuery . inband . query
2019-05-29 16:52:33 +03:00
while True :
values = inject . getValue ( query , blind = False , time = False )
if not isNoneValue ( values ) :
kb . data . cachedStatements = [ ]
for value in arrayizeValue ( values ) :
value = ( unArrayizeValue ( value ) or " " ) . strip ( )
if not isNoneValue ( value ) :
kb . data . cachedStatements . append ( value . strip ( ) )
elif Backend . isDbms ( DBMS . PGSQL ) and " current_query " not in query :
query = query . replace ( " query " , " current_query " )
continue
break
if not kb . data . cachedStatements and isInferenceAvailable ( ) and not conf . direct :
infoMsg = " fetching number of statements "
logger . info ( infoMsg )
query = rootQuery . blind . count
2020-02-10 18:22:58 +03:00
if Backend . isFork ( FORK . DRIZZLE ) :
query = query . replace ( " INFORMATION_SCHEMA " , " DATA_DICTIONARY " )
2019-05-29 16:52:33 +03:00
count = inject . getValue ( query , union = False , error = False , expected = EXPECTED . INT , charsetType = CHARSET_TYPE . DIGITS )
if count == 0 :
return kb . data . cachedStatements
elif not isNumPosStrValue ( count ) :
errMsg = " unable to retrieve the number of statements "
raise SqlmapNoneDataException ( errMsg )
2020-01-27 19:32:31 +03:00
plusOne = Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . ALTIBASE )
2019-05-29 16:52:33 +03:00
indexRange = getLimitRange ( count , plusOne = plusOne )
for index in indexRange :
value = None
if Backend . getIdentifiedDbms ( ) in ( DBMS . MYSQL , ) : # case with multiple processes
query = rootQuery . blind . query3 % index
identifier = unArrayizeValue ( inject . getValue ( query , union = False , error = False , expected = EXPECTED . INT ) )
if not isNoneValue ( identifier ) :
query = rootQuery . blind . query2 % identifier
value = unArrayizeValue ( inject . getValue ( query , union = False , error = False , expected = EXPECTED . INT ) )
if isNoneValue ( value ) :
query = rootQuery . blind . query % index
2020-02-10 18:22:58 +03:00
if Backend . isFork ( FORK . DRIZZLE ) :
query = query . replace ( " INFORMATION_SCHEMA " , " DATA_DICTIONARY " )
2019-05-29 16:52:33 +03:00
value = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
if not isNoneValue ( value ) :
kb . data . cachedStatements . append ( value )
if not kb . data . cachedStatements :
errMsg = " unable to retrieve the statements "
logger . error ( errMsg )
else :
kb . data . cachedStatements = [ _ . replace ( REFLECTED_VALUE_MARKER , " <payload> " ) for _ in kb . data . cachedStatements ]
2019-06-01 13:38:37 +03:00
return kb . data . cachedStatements