Aligned Sybase and MaxDB to recent enhancements to --dbs, --tables and --columns

This commit is contained in:
Bernardo Damele 2011-04-30 22:11:36 +00:00
parent b31b861d7b
commit d5eeb91b35
2 changed files with 247 additions and 174 deletions

View File

@ -10,12 +10,15 @@ See the file 'doc/COPYING' for copying permission
from lib.core.common import Backend from lib.core.common import Backend
from lib.core.common import isTechniqueAvailable from lib.core.common import isTechniqueAvailable
from lib.core.common import randomStr from lib.core.common import randomStr
from lib.core.common import safeSQLIdentificatorNaming
from lib.core.common import unsafeSQLIdentificatorNaming
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
from lib.core.data import queries from lib.core.data import queries
from lib.core.enums import PAYLOAD from lib.core.enums import PAYLOAD
from lib.core.exception import sqlmapMissingMandatoryOptionException from lib.core.exception import sqlmapMissingMandatoryOptionException
from lib.core.exception import sqlmapNoneDataException
from plugins.generic.enumeration import Enumeration as GenericEnumeration from plugins.generic.enumeration import Enumeration as GenericEnumeration
class Enumeration(GenericEnumeration): class Enumeration(GenericEnumeration):
@ -30,70 +33,46 @@ class Enumeration(GenericEnumeration):
return {} return {}
def searchDb(self): def getDbs(self):
warnMsg = "on SAP MaxDB it is not possible to search databases" if len(kb.data.cachedDbs) > 0:
logger.warn(warnMsg) return kb.data.cachedDbs
return [] infoMsg = "fetching database names"
def getColumns(self, onlyColNames=False):
if not conf.tbl:
warnMsg = "missing table parameter, sqlmap will enumerate "
warnMsg += "the whole database management system schema"
logger.warn(warnMsg)
return self.getSchema()
if "." in conf.tbl:
conf.db, conf.tbl = conf.tbl.split(".")
self.forceDbmsEnum()
rootQuery = queries[Backend.getIdentifiedDbms()].columns
infoMsg = "fetching columns "
infoMsg += "for table '%s' " % conf.tbl
if conf.db:
infoMsg += "on schema '%s'" % conf.db
logger.info(infoMsg) logger.info(infoMsg)
rootQuery = queries[Backend.getIdentifiedDbms()].dbs
randStr = randomStr() randStr = randomStr()
query = rootQuery.inband.query % (conf.tbl, ("'%s'" % conf.db) if conf.db != "USER" else 'USER') query = rootQuery.inband.query
retVal = self.__pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.columnname' % randStr,'%s.datatype' % randStr,'%s.len' % randStr], blind=True) retVal = self.__pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.schemaname' % randStr], blind=True)
if retVal: if retVal:
table = {} kb.data.cachedDbs = retVal[0].values()[0]
columns = {}
for columnname, datatype, length in zip(retVal[0]["%s.columnname" % randStr], retVal[0]["%s.datatype" % randStr], retVal[0]["%s.len" % randStr]): return kb.data.cachedDbs
columns[columnname] = "%s(%s)" % (datatype, length)
table[conf.tbl] = columns
kb.data.cachedColumns[conf.db] = table
return kb.data.cachedColumns
def getTables(self, bruteForce=None): def getTables(self, bruteForce=None):
if len(kb.data.cachedTables) > 0:
return kb.data.cachedTables
self.forceDbmsEnum() self.forceDbmsEnum()
infoMsg = "fetching tables" if conf.db == "CD":
conf.db = self.getCurrentDb()
if conf.db: if conf.db:
infoMsg += " for schema '%s'" % conf.db dbs = conf.db.split(",")
else:
dbs = self.getDbs()
for db in dbs:
dbs[dbs.index(db)] = safeSQLIdentificatorNaming(db)
infoMsg = "fetching tables for database"
infoMsg += "%s: %s" % ("s" if len(dbs) > 1 else "", ", ".join(db for db in dbs))
logger.info(infoMsg) logger.info(infoMsg)
rootQuery = queries[Backend.getIdentifiedDbms()].tables rootQuery = queries[Backend.getIdentifiedDbms()].tables
if conf.db:
if "," in conf.db:
dbs = conf.db.split(",")
else:
dbs = [conf.db]
else:
if not len(kb.data.cachedDbs):
dbs = self.getDbs()
else:
dbs = kb.data.cachedDbs
for db in dbs: for db in dbs:
randStr = randomStr() randStr = randomStr()
query = rootQuery.inband.query % (("'%s'" % db) if db != "USER" else 'USER') query = rootQuery.inband.query % (("'%s'" % db) if db != "USER" else 'USER')
@ -108,18 +87,79 @@ class Enumeration(GenericEnumeration):
return kb.data.cachedTables return kb.data.cachedTables
def getDbs(self): def getColumns(self, onlyColNames=False):
infoMsg = "fetching database names" self.forceDbmsEnum()
logger.info(infoMsg)
rootQuery = queries[Backend.getIdentifiedDbms()].dbs if conf.db is None or conf.db == "CD":
if conf.db is None:
warnMsg = "missing database parameter, sqlmap is going "
warnMsg += "to use the current database to enumerate "
warnMsg += "table(s) columns"
logger.warn(warnMsg)
randStr = randomStr() conf.db = self.getCurrentDb()
query = rootQuery.inband.query
retVal = self.__pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.schemaname' % randStr], blind=True) elif conf.db is not None:
if ',' in conf.db:
errMsg = "only one database name is allowed when enumerating "
errMsg += "the tables' columns"
raise sqlmapMissingMandatoryOptionException, errMsg
if retVal: conf.db = safeSQLIdentificatorNaming(conf.db)
kb.data.cachedDbs = retVal[0].values()[0]
return kb.data.cachedDbs if conf.tbl:
tblList = conf.tbl.split(",")
else:
self.getTables()
if len(kb.data.cachedTables) > 0:
tblList = kb.data.cachedTables.values()
if isinstance(tblList[0], (set, tuple, list)):
tblList = tblList[0]
else:
errMsg = "unable to retrieve the tables"
errMsg += "on database '%s'" % conf.db
raise sqlmapNoneDataException, errMsg
for tbl in tblList:
tblList[tblList.index(tbl)] = safeSQLIdentificatorNaming(tbl)
rootQuery = queries[Backend.getIdentifiedDbms()].columns
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'" % conf.db
logger.info(infoMsg)
return { conf.db: kb.data.cachedColumns[conf.db]}
infoMsg = "fetching columns "
infoMsg += "for table '%s' " % tbl
infoMsg += "on database '%s'" % conf.db
logger.info(infoMsg)
randStr = randomStr()
query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), ("'%s'" % unsafeSQLIdentificatorNaming(conf.db)) if unsafeSQLIdentificatorNaming(conf.db) != "USER" else 'USER')
retVal = self.__pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.columnname' % randStr,'%s.datatype' % randStr,'%s.len' % randStr], blind=True)
if retVal:
table = {}
columns = {}
for columnname, datatype, length in zip(retVal[0]["%s.columnname" % randStr], retVal[0]["%s.datatype" % randStr], retVal[0]["%s.len" % randStr]):
columns[columnname] = "%s(%s)" % (datatype, length)
table[tbl] = columns
kb.data.cachedColumns[conf.db] = table
return kb.data.cachedColumns
def searchDb(self):
warnMsg = "on SAP MaxDB it is not possible to search databases"
logger.warn(warnMsg)
return []

View File

@ -10,6 +10,8 @@ See the file 'doc/COPYING' for copying permission
from lib.core.common import Backend from lib.core.common import Backend
from lib.core.common import isTechniqueAvailable from lib.core.common import isTechniqueAvailable
from lib.core.common import randomStr from lib.core.common import randomStr
from lib.core.common import safeSQLIdentificatorNaming
from lib.core.common import unsafeSQLIdentificatorNaming
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
@ -17,6 +19,7 @@ from lib.core.data import queries
from lib.core.dicts import sybaseTypes from lib.core.dicts import sybaseTypes
from lib.core.enums import PAYLOAD from lib.core.enums import PAYLOAD
from lib.core.exception import sqlmapMissingMandatoryOptionException from lib.core.exception import sqlmapMissingMandatoryOptionException
from lib.core.exception import sqlmapNoneDataException
from plugins.generic.enumeration import Enumeration as GenericEnumeration from plugins.generic.enumeration import Enumeration as GenericEnumeration
class Enumeration(GenericEnumeration): class Enumeration(GenericEnumeration):
@ -46,122 +49,6 @@ class Enumeration(GenericEnumeration):
return kb.data.cachedUsers return kb.data.cachedUsers
def getColumns(self, onlyColNames=False):
if not conf.tbl:
warnMsg = "missing table parameter, sqlmap will enumerate "
warnMsg += "the whole database management system schema"
logger.warn(warnMsg)
return self.getSchema()
if "." in conf.tbl:
conf.db, conf.tbl = conf.tbl.split(".")
self.forceDbmsEnum()
if not conf.db:
warnMsg = "missing database parameter, sqlmap is going to "
warnMsg += "use the current database to enumerate table "
warnMsg += "'%s' columns" % conf.tbl
logger.warn(warnMsg)
conf.db = self.getCurrentDb()
rootQuery = queries[Backend.getIdentifiedDbms()].columns
infoMsg = "fetching columns "
infoMsg += "for table '%s' " % conf.tbl
infoMsg += "on database '%s'" % conf.db
logger.info(infoMsg)
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) or conf.direct:
blinds = [False, True]
else:
blinds = [True]
for blind in blinds:
randStr = randomStr()
query = rootQuery.inband.query % (conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, conf.tbl)
retVal = self.__pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.name' % randStr,'%s.usertype' % randStr], blind=blind)
if retVal:
table = {}
columns = {}
for name, type_ in zip(retVal[0]["%s.name" % randStr], retVal[0]["%s.usertype" % randStr]):
columns[name] = sybaseTypes[type_] if type_ else None
table[conf.tbl] = columns
kb.data.cachedColumns[conf.db] = table
break
return kb.data.cachedColumns
def getTables(self, bruteForce=None):
self.forceDbmsEnum()
infoMsg = "fetching tables"
if conf.db:
infoMsg += " for database '%s'" % conf.db
logger.info(infoMsg)
rootQuery = queries[Backend.getIdentifiedDbms()].tables
if conf.db:
if "," in conf.db:
dbs = conf.db.split(",")
else:
dbs = [conf.db]
else:
if not len(kb.data.cachedDbs):
dbs = self.getDbs()
else:
dbs = kb.data.cachedDbs
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) or conf.direct:
blinds = [False, True]
else:
blinds = [True]
for db in dbs:
for blind in blinds:
randStr = randomStr()
query = rootQuery.inband.query % db
retVal = self.__pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.name' % randStr], blind=blind)
if retVal:
for table in retVal[0].values()[0]:
if not kb.data.cachedTables.has_key(db):
kb.data.cachedTables[db] = [table]
else:
kb.data.cachedTables[db].append(table)
break
return kb.data.cachedTables
def getDbs(self):
infoMsg = "fetching database names"
logger.info(infoMsg)
rootQuery = queries[Backend.getIdentifiedDbms()].dbs
randStr = randomStr()
query = rootQuery.inband.query
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) or conf.direct:
blinds = [False, True]
else:
blinds = [True]
for blind in blinds:
retVal = self.__pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.name' % randStr], blind=blind)
if retVal:
kb.data.cachedDbs = retVal[0].values()[0]
break
return kb.data.cachedDbs
def getPrivileges(self, *args): def getPrivileges(self, *args):
warnMsg = "on Sybase it is not possible to fetch " warnMsg = "on Sybase it is not possible to fetch "
warnMsg += "database users privileges, sqlmap will check whether " warnMsg += "database users privileges, sqlmap will check whether "
@ -191,6 +78,152 @@ class Enumeration(GenericEnumeration):
return ( kb.data.cachedUsersPrivileges, areAdmins ) return ( kb.data.cachedUsersPrivileges, areAdmins )
def getDbs(self):
if len(kb.data.cachedDbs) > 0:
return kb.data.cachedDbs
infoMsg = "fetching database names"
logger.info(infoMsg)
rootQuery = queries[Backend.getIdentifiedDbms()].dbs
randStr = randomStr()
query = rootQuery.inband.query
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) or conf.direct:
blinds = [False, True]
else:
blinds = [True]
for blind in blinds:
retVal = self.__pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.name' % randStr], blind=blind)
if retVal:
kb.data.cachedDbs = retVal[0].values()[0]
break
return kb.data.cachedDbs
def getTables(self, bruteForce=None):
if len(kb.data.cachedTables) > 0:
return kb.data.cachedTables
self.forceDbmsEnum()
if conf.db == "CD":
conf.db = self.getCurrentDb()
if conf.db:
dbs = conf.db.split(",")
else:
dbs = self.getDbs()
for db in dbs:
dbs[dbs.index(db)] = safeSQLIdentificatorNaming(db)
infoMsg = "fetching tables for database"
infoMsg += "%s: %s" % ("s" if len(dbs) > 1 else "", ", ".join(db for db in dbs))
logger.info(infoMsg)
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) or conf.direct:
blinds = [False, True]
else:
blinds = [True]
for db in dbs:
for blind in blinds:
randStr = randomStr()
query = rootQuery.inband.query % db
retVal = self.__pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.name' % randStr], blind=blind)
if retVal:
for table in retVal[0].values()[0]:
if not kb.data.cachedTables.has_key(db):
kb.data.cachedTables[db] = [table]
else:
kb.data.cachedTables[db].append(table)
break
return kb.data.cachedTables
def getColumns(self, onlyColNames=False):
self.forceDbmsEnum()
if conf.db is None or conf.db == "CD":
if conf.db is None:
warnMsg = "missing database parameter, sqlmap is going "
warnMsg += "to use the current database to enumerate "
warnMsg += "table(s) columns"
logger.warn(warnMsg)
conf.db = self.getCurrentDb()
elif conf.db is not None:
if ',' in conf.db:
errMsg = "only one database name is allowed when enumerating "
errMsg += "the tables' columns"
raise sqlmapMissingMandatoryOptionException, errMsg
conf.db = safeSQLIdentificatorNaming(conf.db)
if conf.tbl:
tblList = conf.tbl.split(",")
else:
self.getTables()
if len(kb.data.cachedTables) > 0:
tblList = kb.data.cachedTables.values()
if isinstance(tblList[0], (set, tuple, list)):
tblList = tblList[0]
else:
errMsg = "unable to retrieve the tables"
errMsg += "on database '%s'" % conf.db
raise sqlmapNoneDataException, errMsg
for tbl in tblList:
tblList[tblList.index(tbl)] = safeSQLIdentificatorNaming(tbl)
rootQuery = queries[Backend.getIdentifiedDbms()].columns
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) or conf.direct:
blinds = [False, True]
else:
blinds = [True]
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'" % conf.db
logger.info(infoMsg)
return { conf.db: kb.data.cachedColumns[conf.db]}
infoMsg = "fetching columns "
infoMsg += "for table '%s' " % tbl
infoMsg += "on database '%s'" % conf.db
logger.info(infoMsg)
for blind in blinds:
randStr = randomStr()
query = rootQuery.inband.query % (conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl))
retVal = self.__pivotDumpTable("(%s) AS %s" % (query, randStr), ['%s.name' % randStr,'%s.usertype' % randStr], blind=blind)
if retVal:
table = {}
columns = {}
for name, type_ in zip(retVal[0]["%s.name" % randStr], retVal[0]["%s.usertype" % randStr]):
columns[name] = sybaseTypes[type_] if type_ else None
table[tbl] = columns
kb.data.cachedColumns[conf.db] = table
break
return kb.data.cachedColumns
def searchDb(self): def searchDb(self):
warnMsg = "on Sybase searching of databases is not implemented" warnMsg = "on Sybase searching of databases is not implemented"
logger.warn(warnMsg) logger.warn(warnMsg)