2019-05-08 12:47:52 +02:00
#!/usr/bin/env python
2012-07-20 19:17:35 +01:00
"""
2024-01-03 23:11:52 +01:00
Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
2017-10-11 14:50:46 +02:00
See the file ' LICENSE ' for copying permission
2012-07-20 19:17:35 +01:00
"""
2019-11-04 12:53:29 +01:00
import re
2012-07-20 19:17:35 +01:00
from lib . core . agent import agent
from lib . core . common import arrayizeValue
from lib . core . common import Backend
2019-03-29 02:28:16 +01:00
from lib . core . common import filterNone
2012-07-20 19:17:35 +01:00
from lib . core . common import filterPairValues
2014-05-17 15:00:09 +02:00
from lib . core . common import flattenValue
2012-07-20 19:17:35 +01: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
from lib . core . common import readInput
from lib . core . common import safeSQLIdentificatorNaming
2020-01-17 17:14:41 +01:00
from lib . core . common import safeStringFormat
2018-02-13 15:53:50 +01:00
from lib . core . common import singleTimeLogMessage
2013-07-19 13:24:35 +02:00
from lib . core . common import singleTimeWarnMessage
2012-07-20 19:17:35 +01: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 12:45:47 +02:00
from lib . core . decorators import stackedmethod
2020-02-07 14:02:45 +01:00
from lib . core . dicts import ALTIBASE_TYPES
2012-08-21 11:30:01 +02:00
from lib . core . dicts import FIREBIRD_TYPES
2016-09-23 18:03:31 +02:00
from lib . core . dicts import INFORMIX_TYPES
2012-07-20 19:17:35 +01:00
from lib . core . enums import CHARSET_TYPE
from lib . core . enums import DBMS
from lib . core . enums import EXPECTED
2020-02-10 16:22:58 +01:00
from lib . core . enums import FORK
2012-07-20 19:17:35 +01:00
from lib . core . enums import PAYLOAD
2012-12-06 14:14:19 +01:00
from lib . core . exception import SqlmapMissingMandatoryOptionException
from lib . core . exception import SqlmapNoneDataException
from lib . core . exception import SqlmapUserQuitException
2012-07-20 19:17:35 +01:00
from lib . core . settings import CURRENT_DB
2021-01-11 17:36:23 +01:00
from lib . core . settings import METADB_SUFFIX
2020-02-25 12:36:07 +01:00
from lib . core . settings import PLUS_ONE_DBMSES
2019-05-29 15:52:33 +02:00
from lib . core . settings import REFLECTED_VALUE_MARKER
2020-01-27 17:32:31 +01:00
from lib . core . settings import UPPER_CASE_DBMSES
2020-01-21 15:40:59 +01:00
from lib . core . settings import VERTICA_DEFAULT_SCHEMA
2012-07-20 19:17:35 +01:00
from lib . request import inject
2017-04-18 13:53:41 +02:00
from lib . utils . brute import columnExists
from lib . utils . brute import tableExists
2019-03-28 14:12:11 +01:00
from thirdparty import six
2012-07-20 19:17:35 +01:00
2019-05-29 16:42:04 +02:00
class Databases ( object ) :
2012-07-20 19:17:35 +01: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 15:52:33 +02:00
kb . data . cachedStatements = [ ]
2012-07-20 19:17:35 +01: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 15:40:59 +01:00
if not kb . data . currentDb and Backend . isDbms ( DBMS . VERTICA ) :
kb . data . currentDb = VERTICA_DEFAULT_SCHEMA
2023-02-03 23:10:12 +01:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . PGSQL , DBMS . MONETDB , DBMS . DERBY , DBMS . VERTICA , DBMS . PRESTO , DBMS . MIMERSQL , DBMS . CRATEDB , DBMS . CACHE , DBMS . FRONTBASE , DBMS . CLICKHOUSE ) :
2020-02-26 17:33:47 +01:00
warnMsg = " on %s you ' ll need to use " % Backend . getIdentifiedDbms ( )
2013-07-19 13:24:35 +02:00
warnMsg + = " schema names for enumeration as the counterpart to database "
warnMsg + = " names on other DBMSes "
singleTimeWarnMessage ( warnMsg )
2020-02-03 01:58:12 +01:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ALTIBASE , DBMS . CUBRID ) :
2020-02-26 17:33:47 +01:00
warnMsg = " on %s you ' ll need to use " % Backend . getIdentifiedDbms ( )
2020-01-27 17:32:31 +01:00
warnMsg + = " user names for enumeration as the counterpart to database "
warnMsg + = " names on other DBMSes "
singleTimeWarnMessage ( warnMsg )
2013-07-19 13:24:35 +02:00
2012-07-20 19:17:35 +01: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 "
2022-06-22 12:04:34 +02:00
logger . warning ( warnMsg )
2012-07-20 19:17:35 +01:00
2023-02-03 23:10:12 +01:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . PGSQL , DBMS . MONETDB , DBMS . DERBY , DBMS . VERTICA , DBMS . PRESTO , DBMS . MIMERSQL , DBMS . CRATEDB , DBMS . CACHE , DBMS . FRONTBASE , DBMS . CLICKHOUSE ) :
2020-02-26 17:33:47 +01:00
warnMsg = " schema names are going to be used on %s " % Backend . getIdentifiedDbms ( )
2012-07-20 19:17:35 +01:00
warnMsg + = " for enumeration as the counterpart to database "
warnMsg + = " names on other DBMSes "
2022-06-22 12:04:34 +02:00
logger . warning ( warnMsg )
2012-07-20 19:17:35 +01:00
infoMsg = " fetching database (schema) names "
2020-02-03 01:58:12 +01:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ALTIBASE , DBMS . CUBRID ) :
2020-02-26 17:33:47 +01:00
warnMsg = " user names are going to be used on %s " % Backend . getIdentifiedDbms ( )
2020-01-27 17:32:31 +01:00
warnMsg + = " for enumeration as the counterpart to database "
warnMsg + = " names on other DBMSes "
2022-06-22 12:04:34 +02:00
logger . warning ( warnMsg )
2020-01-27 17:32:31 +01:00
infoMsg = " fetching database (user) names "
2012-07-20 19:17:35 +01:00
else :
infoMsg = " fetching database names "
if infoMsg :
logger . info ( infoMsg )
rootQuery = queries [ Backend . getIdentifiedDbms ( ) ] . dbs
2012-12-05 10:45:17 +01:00
if any ( isTechniqueAvailable ( _ ) for _ in ( PAYLOAD . TECHNIQUE . UNION , PAYLOAD . TECHNIQUE . ERROR , PAYLOAD . TECHNIQUE . QUERY ) ) or conf . direct :
2012-07-20 19:17:35 +01: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 10:15:42 +01:00
values = inject . getValue ( query , blind = False , time = False )
2012-07-20 19:17:35 +01:00
2012-12-21 10:15:42 +01:00
if not isNoneValue ( values ) :
kb . data . cachedDbs = arrayizeValue ( values )
2012-07-20 19:17:35 +01: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 00:36:09 +02:00
count = inject . getValue ( query , union = False , error = False , expected = EXPECTED . INT , charsetType = CHARSET_TYPE . DIGITS )
2012-07-20 19:17:35 +01:00
if not isNumPosStrValue ( count ) :
errMsg = " unable to retrieve the number of databases "
logger . error ( errMsg )
else :
2020-02-25 12:36:07 +01:00
plusOne = Backend . getIdentifiedDbms ( ) in PLUS_ONE_DBMSES
2012-07-20 19:17:35 +01: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 15:52:33 +02:00
2012-12-21 10:15:42 +01:00
db = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
2012-07-20 19:17:35 +01:00
2019-05-29 15:52:33 +02:00
if not isNoneValue ( db ) :
2012-07-20 19:17:35 +01:00
kb . data . cachedDbs . append ( safeSQLIdentificatorNaming ( db ) )
if not kb . data . cachedDbs and Backend . isDbms ( DBMS . MSSQL ) :
2012-12-05 10:45:17 +01:00
if any ( isTechniqueAvailable ( _ ) for _ in ( PAYLOAD . TECHNIQUE . UNION , PAYLOAD . TECHNIQUE . ERROR , PAYLOAD . TECHNIQUE . QUERY ) ) or conf . direct :
2012-07-20 19:17:35 +01: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 15:55:33 +01:00
value = unArrayizeValue ( inject . getValue ( query , blind = blind ) )
if not ( value or " " ) . strip ( ) :
2012-07-20 19:17:35 +01:00
break
else :
2012-12-06 15:55:33 +01:00
kb . data . cachedDbs . append ( value )
2012-07-20 19:17:35 +01: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-03 23:20:55 +01:00
raise SqlmapNoneDataException ( errMsg )
2012-07-20 19:17:35 +01:00
else :
kb . data . cachedDbs . sort ( )
2012-12-18 09:55:33 +01:00
if kb . data . cachedDbs :
2019-01-22 03:14:23 +01:00
kb . data . cachedDbs = [ _ for _ in set ( flattenValue ( kb . data . cachedDbs ) ) if _ ]
2012-12-18 09:55:33 +01:00
2012-07-20 19:17:35 +01: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 :
2020-02-26 21:47:10 +01:00
warnMsg = " information_schema not available, "
warnMsg + = " back-end DBMS is MySQL < 5.0 "
2022-06-22 12:04:34 +02:00
logger . warning ( warnMsg )
2012-07-20 19:17:35 +01:00
bruteForce = True
2021-01-11 17:36:23 +01:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . MCKOI , DBMS . EXTREMEDB , DBMS . RAIMA ) :
2020-01-22 23:41:06 +01:00
bruteForce = True
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ACCESS , ) :
2012-07-20 19:17:35 +01:00
try :
tables = self . getTables ( False )
2012-12-06 14:14:19 +01:00
except SqlmapNoneDataException :
2012-07-20 19:17:35 +01:00
tables = None
if not tables :
2020-02-26 21:47:10 +01:00
warnMsg = " cannot retrieve table names, "
warnMsg + = " back-end DBMS is %s " % Backend . getIdentifiedDbms ( )
2022-06-22 12:04:34 +02:00
logger . warning ( warnMsg )
2012-07-20 19:17:35 +01:00
bruteForce = True
else :
return tables
if conf . db == CURRENT_DB :
conf . db = self . getCurrentDb ( )
2020-01-27 17:32:31 +01:00
if conf . db and Backend . getIdentifiedDbms ( ) in UPPER_CASE_DBMSES :
2012-07-20 19:17:35 +01:00
conf . db = conf . db . upper ( )
if conf . db :
2017-04-18 15:56:24 +02:00
dbs = conf . db . split ( ' , ' )
2012-07-20 19:17:35 +01:00
else :
dbs = self . getDbs ( )
2014-06-22 00:19:10 +02:00
dbs = [ _ for _ in dbs if _ and _ . strip ( ) ]
2012-07-20 19:17:35 +01: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 15:11:39 +01:00
if resumeAvailable and not conf . freshQueries :
2012-07-20 19:17:35 +01: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-02-26 17:33:47 +01: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 14:46:27 +02:00
choice = readInput ( message , default = ' Y ' if ' Y ' in message else ' N ' ) . upper ( )
2012-07-20 19:17:35 +01:00
2017-04-18 15:48:05 +02:00
if choice == ' N ' :
2012-07-20 19:17:35 +01:00
return
2017-04-18 15:48:05 +02:00
elif choice == ' Q ' :
2012-12-06 14:14:19 +01:00
raise SqlmapUserQuitException
2012-07-20 19:17:35 +01:00
else :
return tableExists ( paths . COMMON_TABLES )
infoMsg = " fetching tables for database "
2013-02-15 16:48:58 +01:00
infoMsg + = " %s : ' %s ' " % ( " s " if len ( dbs ) > 1 else " " , " , " . join ( unsafeSQLIdentificatorNaming ( unArrayizeValue ( db ) ) for db in sorted ( dbs ) ) )
2012-07-20 19:17:35 +01:00
logger . info ( infoMsg )
rootQuery = queries [ Backend . getIdentifiedDbms ( ) ] . tables
2012-12-05 10:45:17 +01:00
if any ( isTechniqueAvailable ( _ ) for _ in ( PAYLOAD . TECHNIQUE . UNION , PAYLOAD . TECHNIQUE . ERROR , PAYLOAD . TECHNIQUE . QUERY ) ) or conf . direct :
2018-09-07 11:53:43 +02:00
values = [ ]
2012-07-20 19:17:35 +01:00
2018-09-07 11:53:43 +02: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 14:07:28 +00:00
2018-09-07 11:53:43 +02:00
if condition :
if not Backend . isDbms ( DBMS . SQLITE ) :
query + = " WHERE %s " % condition
2012-07-20 19:17:35 +01:00
2018-09-07 11:53:43 +02: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 19:17:35 +01:00
2018-09-07 11:53:43 +02: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 19:17:35 +01:00
2012-12-21 10:15:42 +01:00
if not isNoneValue ( values ) :
2019-01-22 03:14:23 +01:00
values = [ _ for _ in arrayizeValue ( values ) if _ ]
2012-07-20 19:17:35 +01:00
2012-12-21 10:15:42 +01:00
if len ( values ) > 0 and not isListLike ( values [ 0 ] ) :
2013-01-11 11:17:41 +01:00
values = [ ( dbs [ 0 ] , _ ) for _ in values ]
2012-07-20 19:17:35 +01:00
2012-12-21 10:15:42 +01:00
for db , table in filterPairValues ( values ) :
2024-06-24 18:19:24 +02:00
table = unArrayizeValue ( table )
2019-05-17 00:34:11 +02:00
if not isNoneValue ( table ) :
db = safeSQLIdentificatorNaming ( db )
2024-06-24 18:19:24 +02:00
table = safeSQLIdentificatorNaming ( table , True ) . strip ( )
2019-05-17 00:34:11 +02:00
if conf . getComments :
_ = queries [ Backend . getIdentifiedDbms ( ) ] . table_comment
if hasattr ( _ , " query " ) :
2020-01-27 17:32:31 +01:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . DERBY , DBMS . ALTIBASE ) :
2019-05-17 00:34:11 +02: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 ) :
2021-01-11 17:36:23 +01:00
infoMsg = " retrieved comment ' %s ' for table ' %s ' " % ( comment , unsafeSQLIdentificatorNaming ( table ) )
if METADB_SUFFIX not in db :
infoMsg + = " in database ' %s ' " % unsafeSQLIdentificatorNaming ( db )
2019-05-17 00:34:11 +02:00
logger . info ( infoMsg )
2018-05-21 23:44:21 +02:00
else :
2020-02-26 17:33:47 +01:00
warnMsg = " on %s it is not " % Backend . getIdentifiedDbms ( )
2019-06-01 12:38:37 +02:00
warnMsg + = " possible to get table comments "
2019-05-17 00:34:11 +02:00
singleTimeWarnMessage ( warnMsg )
2018-05-21 23:44:21 +02:00
2019-05-17 00:34:11 +02:00
if db not in kb . data . cachedTables :
kb . data . cachedTables [ db ] = [ table ]
2018-05-21 23:44:21 +02:00
else :
2019-05-17 00:34:11 +02:00
kb . data . cachedTables [ db ] . append ( table )
2012-07-20 19:17:35 +01: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 16:48:58 +01:00
infoMsg = " skipping system database ' %s ' " % unsafeSQLIdentificatorNaming ( db )
2012-07-20 19:17:35 +01:00
logger . info ( infoMsg )
2018-02-13 15:53:50 +01:00
continue
2012-07-20 19:17:35 +01:00
2019-11-04 12:53:29 +01:00
if conf . exclude and re . search ( conf . exclude , db , re . I ) is not None :
2018-02-13 15:53:50 +01:00
infoMsg = " skipping database ' %s ' " % unsafeSQLIdentificatorNaming ( db )
singleTimeLogMessage ( infoMsg )
2012-07-20 19:17:35 +01:00
continue
2021-08-18 23:16:19 +02:00
for _query , _count in ( ( rootQuery . blind . query , rootQuery . blind . count ) , ( getattr ( rootQuery . blind , " query2 " , None ) , getattr ( rootQuery . blind , " count2 " , None ) ) ) :
if _query is None :
2021-08-18 23:08:54 +02:00
break
2012-07-20 19:17:35 +01:00
2021-08-18 23:08:54 +02:00
infoMsg = " fetching number of tables for "
infoMsg + = " database ' %s ' " % unsafeSQLIdentificatorNaming ( db )
logger . info ( infoMsg )
2012-07-20 19:17:35 +01:00
2021-08-18 23:08:54 +02:00
if Backend . getIdentifiedDbms ( ) not in ( DBMS . SQLITE , DBMS . FIREBIRD , DBMS . MAXDB , DBMS . ACCESS , DBMS . MCKOI , DBMS . EXTREMEDB ) :
2021-08-18 23:16:19 +02:00
query = _count % unsafeSQLIdentificatorNaming ( db )
else :
query = _count
2012-10-23 10:33:30 +02:00
2021-08-18 23:16:19 +02:00
count = inject . getValue ( query , union = False , error = False , expected = EXPECTED . INT , charsetType = CHARSET_TYPE . DIGITS )
2012-07-20 19:17:35 +01:00
2021-08-18 23:08:54 +02:00
if count == 0 :
warnMsg = " database ' %s ' " % unsafeSQLIdentificatorNaming ( db )
warnMsg + = " appears to be empty "
2022-06-22 12:04:34 +02:00
logger . warning ( warnMsg )
2021-08-18 23:08:54 +02:00
break
2012-07-20 19:17:35 +01:00
2021-08-18 23:08:54 +02:00
elif not isNumPosStrValue ( count ) :
warnMsg = " unable to retrieve the number of "
warnMsg + = " tables for database ' %s ' " % unsafeSQLIdentificatorNaming ( db )
singleTimeWarnMessage ( warnMsg )
continue
tables = [ ]
plusOne = Backend . getIdentifiedDbms ( ) in PLUS_ONE_DBMSES
indexRange = getLimitRange ( count , plusOne = plusOne )
for index in indexRange :
if Backend . isDbms ( DBMS . SYBASE ) :
2021-08-18 23:16:19 +02:00
query = _query % ( db , ( kb . data . cachedTables [ - 1 ] if kb . data . cachedTables else " " ) )
2021-08-18 23:08:54 +02:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . MAXDB , DBMS . ACCESS , DBMS . MCKOI , DBMS . EXTREMEDB ) :
2021-08-18 23:16:19 +02:00
query = _query % ( kb . data . cachedTables [ - 1 ] if kb . data . cachedTables else " " )
2021-08-18 23:08:54 +02:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . SQLITE , DBMS . FIREBIRD ) :
2021-08-18 23:16:19 +02:00
query = _query % index
2021-08-18 23:08:54 +02:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . HSQLDB , DBMS . INFORMIX , DBMS . FRONTBASE , DBMS . VIRTUOSO ) :
2021-08-18 23:16:19 +02:00
query = _query % ( index , unsafeSQLIdentificatorNaming ( db ) )
2021-08-18 23:08:54 +02:00
else :
2021-08-18 23:16:19 +02:00
query = _query % ( unsafeSQLIdentificatorNaming ( db ) , index )
2012-07-20 19:17:35 +01:00
2021-08-18 23:08:54 +02:00
table = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
2012-07-20 19:17:35 +01:00
2021-08-18 23:08:54 +02:00
if not isNoneValue ( table ) :
kb . hintValue = table
table = safeSQLIdentificatorNaming ( table , True )
tables . append ( table )
2019-05-29 15:52:33 +02:00
2021-08-18 23:08:54 +02:00
if tables :
kb . data . cachedTables [ db ] = tables
2012-07-20 19:17:35 +01:00
2018-05-21 23:44:21 +02:00
if conf . getComments :
2021-08-18 23:08:54 +02:00
for table in tables :
_ = queries [ Backend . getIdentifiedDbms ( ) ] . table_comment
if hasattr ( _ , " query " ) :
if Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . DERBY , DBMS . ALTIBASE ) :
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 ) )
if METADB_SUFFIX not in db :
infoMsg + = " in database ' %s ' " % unsafeSQLIdentificatorNaming ( db )
logger . info ( infoMsg )
2018-05-21 23:44:21 +02:00
else :
2021-08-18 23:08:54 +02:00
warnMsg = " on %s it is not " % Backend . getIdentifiedDbms ( )
warnMsg + = " possible to get table comments "
singleTimeWarnMessage ( warnMsg )
2018-05-21 23:44:21 +02:00
2021-08-18 23:08:54 +02:00
break
else :
warnMsg = " unable to retrieve the table names "
warnMsg + = " for database ' %s ' " % unsafeSQLIdentificatorNaming ( db )
2022-06-22 12:04:34 +02:00
logger . warning ( warnMsg )
2012-07-20 19:17:35 +01:00
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 13:44:51 +02:00
elif not conf . search :
2013-01-03 23:20:55 +01:00
raise SqlmapNoneDataException ( errMsg )
2012-07-20 19:17:35 +01:00
else :
for db , tables in kb . data . cachedTables . items ( ) :
kb . data . cachedTables [ db ] = sorted ( tables ) if tables else tables
2012-12-18 09:55:33 +01:00
if kb . data . cachedTables :
2019-01-22 03:00:44 +01:00
for db in kb . data . cachedTables :
2012-12-18 09:55:33 +01:00
kb . data . cachedTables [ db ] = list ( set ( kb . data . cachedTables [ db ] ) )
2012-07-20 19:17:35 +01:00
return kb . data . cachedTables
2015-09-22 12:33:11 +02:00
def getColumns ( self , onlyColNames = False , colTuple = None , bruteForce = None , dumpMode = False ) :
2012-07-20 19:17:35 +01:00
self . forceDbmsEnum ( )
if conf . db is None or conf . db == CURRENT_DB :
if conf . db is None :
2012-10-04 18:28:36 +02:00
warnMsg = " missing database parameter. sqlmap is going "
2012-07-20 19:17:35 +01:00
warnMsg + = " to use the current database to enumerate "
warnMsg + = " table(s) columns "
2022-06-22 12:04:34 +02:00
logger . warning ( warnMsg )
2012-07-20 19:17:35 +01:00
conf . db = self . getCurrentDb ( )
2013-07-02 15:01:49 +02:00
if not conf . db :
errMsg = " unable to retrieve the current "
errMsg + = " database name "
raise SqlmapNoneDataException ( errMsg )
2012-07-20 19:17:35 +01:00
elif conf . db is not None :
2020-01-27 17:32:31 +01:00
if Backend . getIdentifiedDbms ( ) in UPPER_CASE_DBMSES :
2012-07-20 19:17:35 +01:00
conf . db = conf . db . upper ( )
2018-03-13 13:45:42 +01:00
if ' , ' in conf . db :
2012-07-20 19:17:35 +01:00
errMsg = " only one database name is allowed when enumerating "
errMsg + = " the tables ' columns "
2013-01-03 23:20:55 +01:00
raise SqlmapMissingMandatoryOptionException ( errMsg )
2012-07-20 19:17:35 +01:00
conf . db = safeSQLIdentificatorNaming ( conf . db )
if conf . col :
2020-01-27 17:32:31 +01:00
if Backend . getIdentifiedDbms ( ) in UPPER_CASE_DBMSES :
2012-07-20 19:17:35 +01:00
conf . col = conf . col . upper ( )
2014-01-13 10:05:49 +01:00
colList = conf . col . split ( ' , ' )
2012-07-20 19:17:35 +01:00
else :
colList = [ ]
2018-02-13 15:53:50 +01:00
if conf . exclude :
2019-11-04 12:53:29 +01:00
colList = [ _ for _ in colList if re . search ( conf . exclude , _ , re . I ) is None ]
2014-01-13 10:05:49 +01:00
2012-07-20 19:17:35 +01:00
for col in colList :
colList [ colList . index ( col ) ] = safeSQLIdentificatorNaming ( col )
2019-01-22 03:14:23 +01:00
colList = [ _ for _ in colList if _ ]
2012-07-20 19:17:35 +01:00
if conf . tbl :
2020-01-27 17:32:31 +01:00
if Backend . getIdentifiedDbms ( ) in UPPER_CASE_DBMSES :
2012-07-20 19:17:35 +01:00
conf . tbl = conf . tbl . upper ( )
2017-04-18 15:56:24 +02:00
tblList = conf . tbl . split ( ' , ' )
2012-07-20 19:17:35 +01: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 10:30:47 +02:00
tblList = list ( six . itervalues ( kb . data . cachedTables ) )
2012-07-20 19:17:35 +01:00
2019-05-15 10:30:47 +02:00
if tblList and isListLike ( tblList [ 0 ] ) :
2012-07-20 19:17:35 +01:00
tblList = tblList [ 0 ]
tblList = list ( tblList )
2015-09-24 13:44:51 +02:00
elif not conf . search :
2021-01-11 17:36:23 +01:00
errMsg = " unable to retrieve the tables "
if METADB_SUFFIX not in conf . db :
errMsg + = " in database ' %s ' " % unsafeSQLIdentificatorNaming ( conf . db )
2013-01-03 23:20:55 +01:00
raise SqlmapNoneDataException ( errMsg )
2015-09-24 13:44:51 +02:00
else :
return kb . data . cachedColumns
2012-07-20 19:17:35 +01:00
2020-09-23 15:22:07 +02:00
if conf . exclude :
tblList = [ _ for _ in tblList if re . search ( conf . exclude , _ , re . I ) is None ]
2019-03-29 02:28:16 +01:00
tblList = filterNone ( safeSQLIdentificatorNaming ( _ , True ) for _ in tblList )
2012-07-20 19:17:35 +01:00
if bruteForce is None :
if Backend . isDbms ( DBMS . MYSQL ) and not kb . data . has_information_schema :
2020-02-26 21:47:10 +01:00
warnMsg = " information_schema not available, "
warnMsg + = " back-end DBMS is MySQL < 5.0 "
2022-06-22 12:04:34 +02:00
logger . warning ( warnMsg )
2012-07-20 19:17:35 +01:00
bruteForce = True
2021-01-11 17:36:23 +01:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ACCESS , DBMS . MCKOI , DBMS . EXTREMEDB , DBMS . RAIMA ) :
2020-02-26 21:47:10 +01:00
warnMsg = " cannot retrieve column names, "
2021-01-12 13:23:08 +01:00
warnMsg + = " back-end DBMS is %s " % Backend . getIdentifiedDbms ( )
2021-01-12 13:21:51 +01:00
singleTimeWarnMessage ( warnMsg )
2012-07-20 19:17:35 +01:00
bruteForce = True
2012-12-18 15:31:30 +00:00
if bruteForce :
2012-07-20 19:17:35 +01: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
2021-01-11 17:36:23 +01:00
if resumeAvailable and not ( conf . freshQueries and not colList ) :
2012-07-20 19:17:35 +01: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
2021-01-12 13:21:51 +01:00
if kb . choices . columnExists is None :
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] " )
kb . choices . columnExists = readInput ( message , default = ' Y ' if ' Y ' in message else ' N ' ) . upper ( )
2012-07-20 19:17:35 +01:00
2021-01-12 13:21:51 +01:00
if kb . choices . columnExists == ' N ' :
if dumpMode and colList :
kb . data . cachedColumns [ safeSQLIdentificatorNaming ( conf . db ) ] = { safeSQLIdentificatorNaming ( tbl , True ) : dict ( ( _ , None ) for _ in colList ) }
return kb . data . cachedColumns
else :
return None
elif kb . choices . columnExists == ' Q ' :
2012-12-06 14:14:19 +01:00
raise SqlmapUserQuitException
2012-07-20 19:17:35 +01: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 10:45:17 +01:00
if any ( isTechniqueAvailable ( _ ) for _ in ( PAYLOAD . TECHNIQUE . UNION , PAYLOAD . TECHNIQUE . ERROR , PAYLOAD . TECHNIQUE . QUERY ) ) or conf . direct :
2012-07-20 19:17:35 +01: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 ] :
2021-03-11 11:11:29 +01:00
infoMsg = " fetched table columns from "
2012-07-20 19:17:35 +01:00
infoMsg + = " database ' %s ' " % unsafeSQLIdentificatorNaming ( conf . db )
logger . info ( infoMsg )
return { conf . db : kb . data . cachedColumns [ conf . db ] }
infoMsg = " fetching columns "
2012-12-18 15:31:30 +00:00
condQuery = " "
2012-07-20 19:17:35 +01:00
if len ( colList ) > 0 :
2012-12-18 15:31:30 +00:00
if colTuple :
_ , colCondParam = colTuple
2015-09-22 12:03:47 +02:00
infoMsg + = " LIKE ' %s ' " % " , " . join ( unsafeSQLIdentificatorNaming ( col ) for col in sorted ( colList ) )
2012-07-20 19:17:35 +01:00
else :
2012-12-18 15:31:30 +00:00
colCondParam = " = ' %s ' "
2012-07-20 19:17:35 +01:00
infoMsg + = " ' %s ' " % " , " . join ( unsafeSQLIdentificatorNaming ( col ) for col in sorted ( colList ) )
2012-12-18 15:31:30 +00:00
condQueryStr = " %% s %s " % colCondParam
condQuery = " AND ( %s ) " % " OR " . join ( condQueryStr % ( condition , unsafeSQLIdentificatorNaming ( col ) ) for col in sorted ( colList ) )
2012-07-20 19:17:35 +01:00
2023-02-03 23:10:12 +01:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . MYSQL , DBMS . PGSQL , DBMS . HSQLDB , DBMS . H2 , DBMS . MONETDB , DBMS . VERTICA , DBMS . PRESTO , DBMS . CRATEDB , DBMS . CUBRID , DBMS . CACHE , DBMS . FRONTBASE , DBMS . VIRTUOSO , DBMS . CLICKHOUSE ) :
2012-07-20 19:17:35 +01:00
query = rootQuery . inband . query % ( unsafeSQLIdentificatorNaming ( tbl ) , unsafeSQLIdentificatorNaming ( conf . db ) )
query + = condQuery
2019-06-21 10:15:36 +02:00
2021-07-04 23:07:55 +02:00
if Backend . isDbms ( DBMS . MYSQL ) and Backend . isFork ( FORK . DRIZZLE ) :
2021-03-11 11:11:29 +01:00
query = re . sub ( " column_type " , " data_type " , query , flags = re . I )
2020-02-10 16:22:58 +01:00
2020-01-31 11:33:31 +01:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . DERBY , DBMS . ALTIBASE , DBMS . MIMERSQL ) :
2013-01-18 20:44:56 +00:00
query = rootQuery . inband . query % ( unsafeSQLIdentificatorNaming ( tbl . upper ( ) ) , unsafeSQLIdentificatorNaming ( conf . db . upper ( ) ) )
2012-07-20 19:17:35 +01:00
query + = condQuery
2019-06-21 10:15:36 +02:00
2012-07-20 19:17:35 +01: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 10:15:36 +02:00
2013-01-18 22:10:10 +00:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . SQLITE , DBMS . FIREBIRD ) :
2017-09-04 23:00:16 +02:00
query = rootQuery . inband . query % unsafeSQLIdentificatorNaming ( tbl )
2013-06-24 15:03:08 +01:00
2019-06-21 10:15:36 +02: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 12:33:11 +02:00
if dumpMode and colList :
values = [ ( _ , ) for _ in colList ]
else :
infoMsg + = " for table ' %s ' " % unsafeSQLIdentificatorNaming ( tbl )
2021-01-11 17:36:23 +01:00
if METADB_SUFFIX not in conf . db :
infoMsg + = " in database ' %s ' " % unsafeSQLIdentificatorNaming ( conf . db )
2015-09-22 12:33:11 +02:00
logger . info ( infoMsg )
2016-07-15 00:10:41 +02:00
values = None
if values is None :
values = inject . getValue ( query , blind = False , time = False )
2019-03-28 13:53:54 +01:00
if values and isinstance ( values [ 0 ] , six . string_types ) :
2018-08-22 17:58:00 +02:00
values = [ values ]
2012-07-20 19:17:35 +01:00
2013-01-11 11:17:41 +01:00
if Backend . isDbms ( DBMS . MSSQL ) and isNoneValue ( values ) :
index , values = 1 , [ ]
2013-01-18 20:40:38 +00:00
2013-01-11 11:17:41 +01:00
while True :
2017-09-04 23:00:16 +02:00
query = rootQuery . inband . query2 % ( conf . db , unsafeSQLIdentificatorNaming ( tbl ) , index )
2013-01-11 11:17:41 +01:00
value = unArrayizeValue ( inject . getValue ( query , blind = False , time = False ) )
2013-01-18 20:40:38 +00:00
2013-01-11 11:17:41 +01:00
if isNoneValue ( value ) or value == " " :
break
else :
values . append ( ( value , ) )
index + = 1
2012-07-20 19:17:35 +01:00
if Backend . isDbms ( DBMS . SQLITE ) :
2019-02-07 17:33:16 +01:00
if dumpMode and colList :
if conf . db not in kb . data . cachedColumns :
kb . data . cachedColumns [ conf . db ] = { }
2019-02-07 17:34:51 +01:00
kb . data . cachedColumns [ conf . db ] [ safeSQLIdentificatorNaming ( conf . tbl , True ) ] = dict ( ( _ , None ) for _ in colList )
2019-02-07 17:33:16 +01:00
else :
parseSqliteTableSchema ( unArrayizeValue ( values ) )
2012-12-21 10:15:42 +01:00
elif not isNoneValue ( values ) :
2012-07-20 19:17:35 +01:00
table = { }
columns = { }
2012-12-21 10:15:42 +01:00
for columnData in values :
2012-07-20 19:17:35 +01:00
if not isNoneValue ( columnData ) :
2019-05-09 13:14:42 +02:00
columnData = [ unArrayizeValue ( _ ) for _ in columnData ]
2012-07-20 19:17:35 +01:00
name = safeSQLIdentificatorNaming ( columnData [ 0 ] )
if name :
2013-07-29 18:25:27 +02:00
if conf . getComments :
_ = queries [ Backend . getIdentifiedDbms ( ) ] . column_comment
if hasattr ( _ , " query " ) :
2020-01-27 17:32:31 +01:00
if Backend . getIdentifiedDbms ( ) in UPPER_CASE_DBMSES :
2013-07-29 18:25:27 +02: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 13:13:37 +02:00
2013-07-29 18:25:27 +02:00
comment = unArrayizeValue ( inject . getValue ( query , blind = False , time = False ) )
2016-04-19 13:13:37 +02:00
if not isNoneValue ( comment ) :
infoMsg = " retrieved comment ' %s ' for column ' %s ' " % ( comment , name )
logger . info ( infoMsg )
2013-07-29 18:25:27 +02:00
else :
2020-02-26 17:33:47 +01:00
warnMsg = " on %s it is not " % Backend . getIdentifiedDbms ( )
2013-07-29 18:25:27 +02:00
warnMsg + = " possible to get column comments "
singleTimeWarnMessage ( warnMsg )
2012-07-20 19:17:35 +01:00
if len ( columnData ) == 1 :
2013-01-11 11:17:41 +01:00
columns [ name ] = None
2012-07-20 19:17:35 +01:00
else :
2019-03-28 13:53:54 +01:00
key = int ( columnData [ 1 ] ) if isinstance ( columnData [ 1 ] , six . string_types ) and columnData [ 1 ] . isdigit ( ) else columnData [ 1 ]
2013-01-21 17:20:46 +01:00
if Backend . isDbms ( DBMS . FIREBIRD ) :
2016-09-23 18:03:31 +02:00
columnData [ 1 ] = FIREBIRD_TYPES . get ( key , columnData [ 1 ] )
2020-02-07 14:02:45 +01:00
elif Backend . isDbms ( DBMS . ALTIBASE ) :
columnData [ 1 ] = ALTIBASE_TYPES . get ( key , columnData [ 1 ] )
2016-09-23 18:03:31 +02: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 17:20:46 +01:00
2012-07-20 19:17:35 +01: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 ] :
2021-03-11 11:11:29 +01:00
infoMsg = " fetched table columns from "
2013-02-15 16:48:58 +01:00
infoMsg + = " database ' %s ' " % unsafeSQLIdentificatorNaming ( conf . db )
2012-07-20 19:17:35 +01:00
logger . info ( infoMsg )
return { conf . db : kb . data . cachedColumns [ conf . db ] }
infoMsg = " fetching columns "
2012-12-18 15:31:30 +00:00
condQuery = " "
2012-07-20 19:17:35 +01:00
if len ( colList ) > 0 :
2012-12-18 15:31:30 +00:00
if colTuple :
_ , colCondParam = colTuple
2015-09-22 12:03:47 +02:00
infoMsg + = " LIKE ' %s ' " % " , " . join ( unsafeSQLIdentificatorNaming ( col ) for col in sorted ( colList ) )
2012-07-20 19:17:35 +01:00
else :
2012-12-18 15:31:30 +00:00
colCondParam = " = ' %s ' "
2012-07-20 19:17:35 +01:00
infoMsg + = " ' %s ' " % " , " . join ( unsafeSQLIdentificatorNaming ( col ) for col in sorted ( colList ) )
2012-12-18 15:31:30 +00:00
condQueryStr = " %% s %s " % colCondParam
condQuery = " AND ( %s ) " % " OR " . join ( condQueryStr % ( condition , unsafeSQLIdentificatorNaming ( col ) ) for col in sorted ( colList ) )
2012-07-20 19:17:35 +01:00
2023-02-03 23:10:12 +01:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . MYSQL , DBMS . PGSQL , DBMS . HSQLDB , DBMS . H2 , DBMS . MONETDB , DBMS . VERTICA , DBMS . PRESTO , DBMS . CRATEDB , DBMS . CUBRID , DBMS . CACHE , DBMS . FRONTBASE , DBMS . VIRTUOSO , DBMS . CLICKHOUSE ) :
2012-07-20 19:17:35 +01:00
query = rootQuery . blind . count % ( unsafeSQLIdentificatorNaming ( tbl ) , unsafeSQLIdentificatorNaming ( conf . db ) )
query + = condQuery
2020-01-31 11:33:31 +01:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . DERBY , DBMS . ALTIBASE , DBMS . MIMERSQL ) :
2013-01-18 20:44:56 +00:00
query = rootQuery . blind . count % ( unsafeSQLIdentificatorNaming ( tbl . upper ( ) ) , unsafeSQLIdentificatorNaming ( conf . db . upper ( ) ) )
2012-07-20 19:17:35 +01:00
query + = condQuery
elif Backend . isDbms ( DBMS . MSSQL ) :
2018-03-13 13:45:42 +01:00
query = rootQuery . blind . count % ( conf . db , conf . db , unsafeSQLIdentificatorNaming ( tbl ) . split ( " . " ) [ - 1 ] )
2012-07-20 19:17:35 +01:00
query + = condQuery . replace ( " [DB] " , conf . db )
elif Backend . isDbms ( DBMS . FIREBIRD ) :
2017-09-04 23:00:16 +02:00
query = rootQuery . blind . count % unsafeSQLIdentificatorNaming ( tbl )
2012-07-20 19:17:35 +01:00
query + = condQuery
2016-09-23 12:33:27 +02:00
elif Backend . isDbms ( DBMS . INFORMIX ) :
2017-09-04 23:00:16 +02:00
query = rootQuery . blind . count % ( conf . db , conf . db , conf . db , conf . db , conf . db , unsafeSQLIdentificatorNaming ( tbl ) )
2016-09-23 12:33:27 +02:00
query + = condQuery
2012-07-20 19:17:35 +01:00
elif Backend . isDbms ( DBMS . SQLITE ) :
2019-02-07 17:33:16 +01:00
if dumpMode and colList :
if conf . db not in kb . data . cachedColumns :
kb . data . cachedColumns [ conf . db ] = { }
2019-02-07 17:34:51 +01:00
kb . data . cachedColumns [ conf . db ] [ safeSQLIdentificatorNaming ( conf . tbl , True ) ] = dict ( ( _ , None ) for _ in colList )
2019-02-07 17:33:16 +01:00
else :
query = rootQuery . blind . query % unsafeSQLIdentificatorNaming ( tbl )
value = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
parseSqliteTableSchema ( unArrayizeValue ( value ) )
2012-07-20 19:17:35 +01:00
return kb . data . cachedColumns
table = { }
columns = { }
2015-09-22 12:33:11 +02:00
if dumpMode and colList :
count = 0
for value in colList :
columns [ safeSQLIdentificatorNaming ( value ) ] = None
else :
infoMsg + = " for table ' %s ' " % unsafeSQLIdentificatorNaming ( tbl )
2021-01-11 17:36:23 +01:00
if METADB_SUFFIX not in conf . db :
infoMsg + = " in database ' %s ' " % unsafeSQLIdentificatorNaming ( conf . db )
2015-09-22 12:33:11 +02:00
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-04 23:00:16 +02:00
query = rootQuery . blind . query3 % ( conf . db , unsafeSQLIdentificatorNaming ( tbl ) , index )
2015-09-22 12:33:11 +02:00
value = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
2019-05-29 15:52:33 +02:00
2015-09-22 12:33:11 +02:00
if isNoneValue ( value ) or value == " " :
break
else :
columns [ safeSQLIdentificatorNaming ( value ) ] = None
index + = 1
2013-01-11 11:17:41 +01:00
2015-09-24 11:49:05 +02: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 )
2021-01-11 17:36:23 +01:00
if METADB_SUFFIX not in conf . db :
errMsg + = " in database ' %s ' " % unsafeSQLIdentificatorNaming ( conf . db )
2015-09-24 11:49:05 +02:00
logger . error ( errMsg )
continue
2013-01-11 11:17:41 +01:00
2012-09-07 17:06:38 +02:00
for index in getLimitRange ( count ) :
2021-02-15 14:07:04 +01:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . MYSQL , DBMS . PGSQL , DBMS . HSQLDB , DBMS . VERTICA , DBMS . PRESTO , DBMS . CRATEDB , DBMS . CUBRID , DBMS . CACHE , DBMS . FRONTBASE , DBMS . VIRTUOSO ) :
2012-07-20 19:17:35 +01:00
query = rootQuery . blind . query % ( unsafeSQLIdentificatorNaming ( tbl ) , unsafeSQLIdentificatorNaming ( conf . db ) )
query + = condQuery
field = None
2018-10-16 14:47:09 +02: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 21:24:20 +01: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
2023-02-03 23:10:12 +01:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . MONETDB , DBMS . CLICKHOUSE ) :
2020-01-17 17:14:41 +01:00
query = safeStringFormat ( rootQuery . blind . query , ( unsafeSQLIdentificatorNaming ( tbl ) , unsafeSQLIdentificatorNaming ( conf . db ) , index ) )
field = None
2020-01-31 21:24:20 +01:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . DERBY , DBMS . ALTIBASE ) :
2013-01-18 20:44:56 +00:00
query = rootQuery . blind . query % ( unsafeSQLIdentificatorNaming ( tbl . upper ( ) ) , unsafeSQLIdentificatorNaming ( conf . db . upper ( ) ) )
2012-07-20 19:17:35 +01:00
query + = condQuery
field = None
elif Backend . isDbms ( DBMS . MSSQL ) :
2012-09-07 17:06:38 +02:00
query = rootQuery . blind . query . replace ( " ' %s ' " , " ' %s ' " % unsafeSQLIdentificatorNaming ( tbl ) . split ( " . " ) [ - 1 ] ) . replace ( " %s " , conf . db ) . replace ( " %d " , str ( index ) )
2012-07-20 19:17:35 +01:00
query + = condQuery . replace ( " [DB] " , conf . db )
field = condition . replace ( " [DB] " , conf . db )
elif Backend . isDbms ( DBMS . FIREBIRD ) :
2017-09-04 23:00:16 +02:00
query = rootQuery . blind . query % unsafeSQLIdentificatorNaming ( tbl )
2012-07-20 19:17:35 +01:00
query + = condQuery
field = None
2016-09-23 12:33:27 +02:00
elif Backend . isDbms ( DBMS . INFORMIX ) :
2017-09-04 23:00:16 +02:00
query = rootQuery . blind . query % ( index , conf . db , conf . db , conf . db , conf . db , conf . db , unsafeSQLIdentificatorNaming ( tbl ) )
2016-09-23 12:33:27 +02:00
query + = condQuery
field = condition
2012-07-20 19:17:35 +01:00
2012-09-07 17:06:38 +02:00
query = agent . limitQuery ( index , query , field , field )
2012-12-21 10:15:42 +01:00
column = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
2012-07-20 19:17:35 +01:00
if not isNoneValue ( column ) :
2013-07-29 18:25:27 +02:00
if conf . getComments :
_ = queries [ Backend . getIdentifiedDbms ( ) ] . column_comment
if hasattr ( _ , " query " ) :
2020-01-27 17:32:31 +01:00
if Backend . getIdentifiedDbms ( ) in UPPER_CASE_DBMSES :
2013-07-29 18:25:27 +02: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 13:13:37 +02:00
2013-07-29 18:25:27 +02:00
comment = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
2016-04-19 13:13:37 +02:00
if not isNoneValue ( comment ) :
infoMsg = " retrieved comment ' %s ' for column ' %s ' " % ( comment , column )
logger . info ( infoMsg )
2013-07-29 18:25:27 +02:00
else :
2020-02-26 17:33:47 +01:00
warnMsg = " on %s it is not " % Backend . getIdentifiedDbms ( )
2013-07-29 18:25:27 +02:00
warnMsg + = " possible to get column comments "
singleTimeWarnMessage ( warnMsg )
2012-07-20 19:17:35 +01:00
if not onlyColNames :
2023-02-03 23:10:12 +01:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . MYSQL , DBMS . PGSQL , DBMS . HSQLDB , DBMS . H2 , DBMS . VERTICA , DBMS . PRESTO , DBMS . CRATEDB , DBMS . CACHE , DBMS . FRONTBASE , DBMS . VIRTUOSO , DBMS . CLICKHOUSE ) :
2012-07-20 19:17:35 +01:00
query = rootQuery . blind . query2 % ( unsafeSQLIdentificatorNaming ( tbl ) , column , unsafeSQLIdentificatorNaming ( conf . db ) )
2020-01-31 11:33:31 +01:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . DERBY , DBMS . ALTIBASE , DBMS . MIMERSQL ) :
2013-01-18 20:44:56 +00:00
query = rootQuery . blind . query2 % ( unsafeSQLIdentificatorNaming ( tbl . upper ( ) ) , column , unsafeSQLIdentificatorNaming ( conf . db . upper ( ) ) )
2012-07-20 19:17:35 +01:00
elif Backend . isDbms ( DBMS . MSSQL ) :
2018-03-13 13:45:42 +01: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 19:17:35 +01:00
elif Backend . isDbms ( DBMS . FIREBIRD ) :
2017-09-04 23:00:16 +02:00
query = rootQuery . blind . query2 % ( unsafeSQLIdentificatorNaming ( tbl ) , column )
2016-09-23 18:03:31 +02:00
elif Backend . isDbms ( DBMS . INFORMIX ) :
2017-09-04 23:00:16 +02:00
query = rootQuery . blind . query2 % ( conf . db , conf . db , conf . db , conf . db , conf . db , unsafeSQLIdentificatorNaming ( tbl ) , column )
2020-01-17 17:14:41 +01:00
elif Backend . isDbms ( DBMS . MONETDB ) :
query = rootQuery . blind . query2 % ( column , unsafeSQLIdentificatorNaming ( tbl ) , unsafeSQLIdentificatorNaming ( conf . db ) )
2012-07-20 19:17:35 +01:00
2012-12-21 10:15:42 +01:00
colType = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
2019-03-28 13:53:54 +01:00
key = int ( colType ) if hasattr ( colType , " isdigit " ) and colType . isdigit ( ) else colType
2019-05-29 15:52:33 +02:00
2012-07-20 19:17:35 +01:00
if Backend . isDbms ( DBMS . FIREBIRD ) :
2016-09-23 18:03:31 +02: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 19:17:35 +01: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 16:42:03 +00:00
warnMsg = " unable to retrieve column names for "
2013-02-15 16:48:58 +01:00
warnMsg + = ( " table ' %s ' " % unsafeSQLIdentificatorNaming ( unArrayizeValue ( tblList ) ) ) if len ( tblList ) == 1 else " any table "
2021-01-11 17:36:23 +01:00
if METADB_SUFFIX not in conf . db :
warnMsg + = " in database ' %s ' " % unsafeSQLIdentificatorNaming ( conf . db )
2022-06-22 12:04:34 +02:00
logger . warning ( warnMsg )
2012-07-20 19:17:35 +01:00
if bruteForce is None :
return self . getColumns ( onlyColNames = onlyColNames , colTuple = colTuple , bruteForce = True )
return kb . data . cachedColumns
2018-04-01 12:45:47 +02:00
@stackedmethod
2012-07-20 19:17:35 +01:00
def getSchema ( self ) :
infoMsg = " enumerating database management system schema "
logger . info ( infoMsg )
2015-07-18 17:01:34 +02:00
try :
pushValue ( conf . db )
pushValue ( conf . tbl )
pushValue ( conf . col )
2012-07-20 19:17:35 +01:00
2015-07-18 17:01:34 +02:00
kb . data . cachedTables = { }
kb . data . cachedColumns = { }
2012-07-20 19:17:35 +01:00
2015-07-18 17:01:34 +02:00
self . getTables ( )
2012-07-20 19:17:35 +01:00
2015-07-18 17:01:34 +02:00
infoMsg = " fetched tables: "
2019-12-12 14:10:02 +01: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 17:01:34 +02:00
logger . info ( infoMsg )
2012-07-20 19:17:35 +01:00
2015-07-18 17:01:34 +02: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 19:17:35 +01:00
return kb . data . cachedColumns
2012-12-06 14:14:19 +01:00
def _tableGetCount ( self , db , table ) :
2014-12-30 09:04:41 +00:00
if not db or not table :
return None
2020-01-27 17:32:31 +01:00
if Backend . getIdentifiedDbms ( ) in UPPER_CASE_DBMSES :
2013-01-17 22:13:59 +00:00
db = db . upper ( )
table = table . upper ( )
2012-07-20 19:17:35 +01:00
2020-02-26 17:33:47 +01:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . SQLITE , DBMS . ACCESS , DBMS . FIREBIRD , DBMS . MCKOI , DBMS . EXTREMEDB ) :
2013-01-18 23:07:16 +00: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 16:54:43 +01:00
query = agent . whereQuery ( query )
2012-07-20 19:17:35 +01: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 "
2022-06-22 12:04:34 +02:00
logger . warning ( warnMsg )
2012-07-20 19:17:35 +01:00
elif " . " in conf . tbl :
if not conf . db :
2015-09-09 14:46:06 +02:00
conf . db , conf . tbl = conf . tbl . split ( ' . ' , 1 )
2012-07-20 19:17:35 +01:00
2020-02-26 17:33:47 +01: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 , DBMS . EXTREMEDB ) :
2012-10-04 18:28:36 +02:00
warnMsg = " missing database parameter. sqlmap is going to "
2012-07-20 19:17:35 +01:00
warnMsg + = " use the current database to retrieve the "
warnMsg + = " number of entries for table ' %s ' " % unsafeSQLIdentificatorNaming ( conf . tbl )
2022-06-22 12:04:34 +02:00
logger . warning ( warnMsg )
2012-07-20 19:17:35 +01:00
conf . db = self . getCurrentDb ( )
self . forceDbmsEnum ( )
if conf . tbl :
2017-04-18 15:56:24 +02:00
for table in conf . tbl . split ( ' , ' ) :
2012-12-06 14:14:19 +01:00
self . _tableGetCount ( conf . db , table )
2012-07-20 19:17:35 +01:00
else :
self . getTables ( )
for db , tables in kb . data . cachedTables . items ( ) :
for table in tables :
2012-12-06 14:14:19 +01:00
self . _tableGetCount ( db , table )
2012-07-20 19:17:35 +01:00
return kb . data . cachedCounts
2019-05-29 15:52:33 +02: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 :
2021-07-04 23:07:55 +02:00
if Backend . isDbms ( DBMS . MYSQL ) and Backend . isFork ( FORK . DRIZZLE ) :
2020-02-10 16:22:58 +01:00
query = rootQuery . inband . query2
else :
query = rootQuery . inband . query
2019-05-29 15:52:33 +02: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 16:22:58 +01:00
2021-07-04 23:07:55 +02:00
if Backend . isDbms ( DBMS . MYSQL ) and Backend . isFork ( FORK . DRIZZLE ) :
2021-03-11 11:11:29 +01:00
query = re . sub ( " INFORMATION_SCHEMA " , " DATA_DICTIONARY " , query , flags = re . I )
2020-02-10 16:22:58 +01:00
2019-05-29 15:52:33 +02: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-02-25 12:36:07 +01:00
plusOne = Backend . getIdentifiedDbms ( ) in PLUS_ONE_DBMSES
2019-05-29 15:52:33 +02: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 16:22:58 +01:00
2021-07-04 23:07:55 +02:00
if Backend . isDbms ( DBMS . MYSQL ) and Backend . isFork ( FORK . DRIZZLE ) :
2021-03-11 11:11:29 +01:00
query = re . sub ( " INFORMATION_SCHEMA " , " DATA_DICTIONARY " , query , flags = re . I )
2020-02-10 16:22:58 +01:00
2019-05-29 15:52:33 +02: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 12:38:37 +02:00
return kb . data . cachedStatements