2013-02-14 15:32:17 +04:00
#!/usr/bin/env python
2012-07-20 22:17:35 +04:00
"""
2015-01-06 17:02:16 +03:00
Copyright ( c ) 2006 - 2015 sqlmap developers ( http : / / sqlmap . org / )
2012-07-20 22:17:35 +04:00
See the file ' doc/COPYING ' for copying permission
"""
from lib . core . agent import agent
from lib . core . common import arrayizeValue
from lib . core . common import Backend
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
from lib . core . common import readInput
from lib . core . common import safeSQLIdentificatorNaming
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
2012-08-21 13:30:01 +04:00
from lib . core . dicts import FIREBIRD_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
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
from lib . request import inject
from lib . techniques . brute . use import columnExists
from lib . techniques . brute . use import tableExists
class Databases :
"""
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 = { }
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 ) )
2013-07-19 15:24:35 +04:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . PGSQL ) :
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 )
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 )
2013-07-19 15:24:35 +04:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . PGSQL ) :
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 "
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 :
plusOne = Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 )
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
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
if db :
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 :
2014-05-20 15:44:10 +04:00
kb . data . cachedDbs = filter ( None , list ( set ( flattenValue ( kb . data . cachedDbs ) ) ) )
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
elif Backend . isDbms ( DBMS . ACCESS ) :
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, "
errMsg + = " back-end DBMS is Access "
logger . error ( errMsg )
bruteForce = True
else :
return tables
if conf . db == CURRENT_DB :
conf . db = self . getCurrentDb ( )
2013-07-01 14:54:31 +04:00
if conf . db and Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . HSQLDB ) :
2012-07-20 22:17:35 +04:00
conf . db = conf . db . upper ( )
if conf . db :
dbs = conf . db . split ( " , " )
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
message = " do you want to use common table existence check? %s " % ( " [Y/n/q] " if Backend . getIdentifiedDbms ( ) in ( DBMS . ACCESS , ) else " [y/N/q] " )
test = readInput ( message , default = " Y " if " Y " in message else " N " )
if test [ 0 ] in ( " n " , " N " ) :
return
elif test [ 0 ] in ( " q " , " 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 :
2012-07-20 22:17:35 +04:00
query = rootQuery . inband . query
condition = rootQuery . inband . condition if ' condition ' in rootQuery . inband else None
if condition :
2012-12-17 18:06:12 +04:00
if not Backend . isDbms ( DBMS . SQLITE ) :
query + = " WHERE %s " % condition
2012-12-17 18:07:28 +04:00
if conf . excludeSysDbs :
2013-02-15 19:48:58 +04:00
infoMsg = " skipping system database %s ' %s ' " % ( " s " if len ( self . excludeDbsList ) > 1 else " " , " , " . join ( unsafeSQLIdentificatorNaming ( db ) for db in self . excludeDbsList ) )
2012-12-17 18:07:28 +04:00
logger . info ( infoMsg )
2013-01-30 14:36:04 +04:00
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
if len ( dbs ) < 2 and ( " %s , " % condition ) in query :
query = query . replace ( " %s , " % condition , " " , 1 )
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 ) :
values = filter ( None , arrayizeValue ( values ) )
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 ) :
2012-07-20 22:17:35 +04:00
db = safeSQLIdentificatorNaming ( db )
2014-01-15 13:29:53 +04:00
table = safeSQLIdentificatorNaming ( unArrayizeValue ( table ) , True )
2012-07-20 22:17:35 +04:00
if db not in kb . data . cachedTables :
kb . data . cachedTables [ db ] = [ table ]
else :
kb . data . cachedTables [ db ] . append ( table )
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 )
continue
infoMsg = " fetching number of tables for "
infoMsg + = " database ' %s ' " % unsafeSQLIdentificatorNaming ( db )
logger . info ( infoMsg )
if Backend . getIdentifiedDbms ( ) in ( DBMS . SQLITE , DBMS . FIREBIRD , DBMS . MAXDB , DBMS . ACCESS ) :
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 = [ ]
plusOne = Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 )
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 " " ) )
elif Backend . getIdentifiedDbms ( ) in ( DBMS . MAXDB , DBMS . ACCESS ) :
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
2014-03-07 18:57:41 +04:00
elif Backend . isDbms ( DBMS . HSQLDB ) :
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 ) )
2012-07-20 22:17:35 +04:00
if not isNoneValue ( table ) :
kb . hintValue = table
table = safeSQLIdentificatorNaming ( table , True )
tables . append ( table )
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 )
else :
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 :
for db in kb . data . cachedTables . keys ( ) :
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 :
2013-07-01 14:54:31 +04:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 , DBMS . HSQLDB ) :
2012-07-20 22:17:35 +04:00
conf . db = conf . db . upper ( )
if ' , ' in conf . db :
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 :
if Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 ) :
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 = [ ]
2014-01-13 13:05:49 +04:00
if conf . excludeCol :
colList = [ _ for _ in colList if _ not in conf . excludeCol . split ( ' , ' ) ]
2012-07-20 22:17:35 +04:00
for col in colList :
colList [ colList . index ( col ) ] = safeSQLIdentificatorNaming ( col )
colList = filter ( None , colList )
if conf . tbl :
if Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 ) :
conf . tbl = conf . tbl . upper ( )
tblList = conf . tbl . split ( " , " )
else :
self . getTables ( )
if len ( kb . data . cachedTables ) > 0 :
if conf . db in kb . data . cachedTables :
tblList = kb . data . cachedTables [ conf . db ]
else :
tblList = kb . data . cachedTables . values ( )
if isinstance ( tblList [ 0 ] , ( set , tuple , list ) ) :
tblList = tblList [ 0 ]
tblList = list ( tblList )
else :
errMsg = " unable to retrieve the tables "
errMsg + = " in database ' %s ' " % unsafeSQLIdentificatorNaming ( conf . db )
2013-01-04 02:20:55 +04:00
raise SqlmapNoneDataException ( errMsg )
2012-07-20 22:17:35 +04:00
2013-07-02 17:01:49 +04:00
tblList = filter ( None , ( 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
elif Backend . isDbms ( DBMS . ACCESS ) :
errMsg = " cannot retrieve column names, "
errMsg + = " back-end DBMS is Access "
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
message = " do you want to use common column existence check? %s " % ( " [Y/n/q] " if Backend . getIdentifiedDbms ( ) in ( DBMS . ACCESS , ) else " [y/N/q] " )
test = readInput ( message , default = " Y " if " Y " in message else " N " )
if test [ 0 ] in ( " n " , " N " ) :
return
elif test [ 0 ] in ( " q " , " 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
2013-07-01 13:57:47 +04:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . MYSQL , DBMS . PGSQL , DBMS . HSQLDB ) :
2012-07-20 22:17:35 +04:00
query = rootQuery . inband . query % ( unsafeSQLIdentificatorNaming ( tbl ) , unsafeSQLIdentificatorNaming ( conf . db ) )
query + = condQuery
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 ) :
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
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 )
2013-01-19 02:10:10 +04:00
elif Backend . getIdentifiedDbms ( ) in ( DBMS . SQLITE , DBMS . FIREBIRD ) :
2012-07-20 22:17:35 +04:00
query = rootQuery . inband . query % tbl
2013-06-24 18:03:08 +04:00
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 )
values = inject . getValue ( query , blind = False , time = False )
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 :
query = rootQuery . inband . query2 % ( conf . db , tbl , index )
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 ) :
2012-12-21 13:15:42 +04:00
parseSqliteTableSchema ( unArrayizeValue ( values ) )
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 ) :
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 " ) :
if Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 ) :
query = _ . query % ( unsafeSQLIdentificatorNaming ( conf . db . upper ( ) ) , unsafeSQLIdentificatorNaming ( tbl . upper ( ) ) , unsafeSQLIdentificatorNaming ( name . upper ( ) ) )
else :
query = _ . query % ( unsafeSQLIdentificatorNaming ( conf . db ) , unsafeSQLIdentificatorNaming ( tbl ) , unsafeSQLIdentificatorNaming ( name ) )
comment = unArrayizeValue ( inject . getValue ( query , blind = False , time = False ) )
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 :
2013-01-21 20:20:46 +04:00
if Backend . isDbms ( DBMS . FIREBIRD ) :
columnData [ 1 ] = FIREBIRD_TYPES . get ( columnData [ 1 ] , columnData [ 1 ] )
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
2014-05-04 22:44:11 +04:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . MYSQL , DBMS . PGSQL , DBMS . HSQLDB ) :
2012-07-20 22:17:35 +04:00
query = rootQuery . blind . count % ( unsafeSQLIdentificatorNaming ( tbl ) , unsafeSQLIdentificatorNaming ( conf . db ) )
query + = condQuery
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 ) :
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 ) :
query = rootQuery . blind . count % ( conf . db , conf . db , \
unsafeSQLIdentificatorNaming ( tbl ) . split ( " . " ) [ - 1 ] )
query + = condQuery . replace ( " [DB] " , conf . db )
elif Backend . isDbms ( DBMS . FIREBIRD ) :
query = rootQuery . blind . count % ( tbl )
query + = condQuery
elif Backend . isDbms ( DBMS . SQLITE ) :
query = rootQuery . blind . query % tbl
2012-12-21 13:15:42 +04:00
value = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
2012-07-20 22:17:35 +04:00
parseSqliteTableSchema ( value )
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 :
query = rootQuery . blind . query3 % ( conf . db , tbl , index )
value = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
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 ) :
2012-07-20 22:17:35 +04:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . MYSQL , DBMS . PGSQL ) :
query = rootQuery . blind . query % ( unsafeSQLIdentificatorNaming ( tbl ) , unsafeSQLIdentificatorNaming ( conf . db ) )
query + = condQuery
field = None
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 ) :
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 ) :
query = rootQuery . blind . query % ( tbl )
query + = condQuery
field = None
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 " ) :
if Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 ) :
query = _ . query % ( unsafeSQLIdentificatorNaming ( conf . db . upper ( ) ) , unsafeSQLIdentificatorNaming ( tbl . upper ( ) ) , unsafeSQLIdentificatorNaming ( column . upper ( ) ) )
else :
query = _ . query % ( unsafeSQLIdentificatorNaming ( conf . db ) , unsafeSQLIdentificatorNaming ( tbl ) , unsafeSQLIdentificatorNaming ( column ) )
comment = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
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 :
if Backend . getIdentifiedDbms ( ) in ( DBMS . MYSQL , DBMS . PGSQL ) :
query = rootQuery . blind . query2 % ( unsafeSQLIdentificatorNaming ( tbl ) , column , unsafeSQLIdentificatorNaming ( conf . db ) )
elif Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 ) :
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 ) :
query = rootQuery . blind . query2 % ( conf . db , conf . db , conf . db , conf . db , column , conf . db ,
conf . db , conf . db , unsafeSQLIdentificatorNaming ( tbl ) . split ( " . " ) [ - 1 ] )
elif Backend . isDbms ( DBMS . FIREBIRD ) :
query = rootQuery . blind . query2 % ( tbl , column )
2012-12-21 13:15:42 +04:00
colType = unArrayizeValue ( inject . getValue ( query , union = False , error = False ) )
2012-07-20 22:17:35 +04:00
if Backend . isDbms ( DBMS . FIREBIRD ) :
2012-09-10 21:28:15 +04:00
colType = FIREBIRD_TYPES . get ( colType , 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
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: "
infoMsg + = " , " . join ( [ " %s " % " , " . join ( " %s %s %s " % ( unsafeSQLIdentificatorNaming ( db ) , " .. " if \
Backend . isDbms ( DBMS . MSSQL ) or Backend . isDbms ( DBMS . SYBASE ) \
else " . " , unsafeSQLIdentificatorNaming ( t ) ) for t in tbl ) for db , tbl in \
kb . data . cachedTables . items ( ) ] )
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
2013-01-18 02:13:59 +04:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . ORACLE , DBMS . DB2 ) :
db = db . upper ( )
table = table . upper ( )
2012-07-20 22:17:35 +04:00
2013-01-19 03:07:16 +04:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . SQLITE , DBMS . ACCESS , DBMS . FIREBIRD ) :
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 ) )
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
2013-01-19 03:04:28 +04:00
if conf . tbl is not None and conf . db is None and Backend . getIdentifiedDbms ( ) not in ( DBMS . SQLITE , DBMS . ACCESS , DBMS . FIREBIRD ) :
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 :
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