Path: blob/master/plugins/dbms/sybase/enumeration.py
2992 views
#!/usr/bin/env python12"""3Copyright (c) 2006-2025 sqlmap developers (https://sqlmap.org)4See the file 'LICENSE' for copying permission5"""67import re89from lib.core.common import filterPairValues10from lib.core.common import isListLike11from lib.core.common import isTechniqueAvailable12from lib.core.common import readInput13from lib.core.common import safeSQLIdentificatorNaming14from lib.core.common import unArrayizeValue15from lib.core.common import unsafeSQLIdentificatorNaming16from lib.core.data import conf17from lib.core.data import kb18from lib.core.data import logger19from lib.core.data import paths20from lib.core.data import queries21from lib.core.dicts import SYBASE_TYPES22from lib.core.enums import DBMS23from lib.core.enums import PAYLOAD24from lib.core.exception import SqlmapMissingMandatoryOptionException25from lib.core.exception import SqlmapNoneDataException26from lib.core.exception import SqlmapUserQuitException27from lib.core.settings import CURRENT_DB28from lib.utils.brute import columnExists29from lib.utils.pivotdumptable import pivotDumpTable30from plugins.generic.enumeration import Enumeration as GenericEnumeration31from thirdparty import six32from thirdparty.six.moves import zip as _zip3334class Enumeration(GenericEnumeration):35def getUsers(self):36infoMsg = "fetching database users"37logger.info(infoMsg)3839rootQuery = queries[DBMS.SYBASE].users4041query = rootQuery.inband.query4243if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:44blinds = (False, True)45else:46blinds = (True,)4748for blind in blinds:49retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.name' % kb.aliasName], blind=blind, alias=kb.aliasName)5051if retVal:52kb.data.cachedUsers = list(retVal[0].values())[0]53break5455return kb.data.cachedUsers5657def getPrivileges(self, *args, **kwargs):58warnMsg = "on Sybase it is not possible to fetch "59warnMsg += "database users privileges, sqlmap will check whether "60warnMsg += "or not the database users are database administrators"61logger.warning(warnMsg)6263users = []64areAdmins = set()6566if conf.user:67users = [conf.user]68elif not len(kb.data.cachedUsers):69users = self.getUsers()70else:71users = kb.data.cachedUsers7273for user in users:74user = unArrayizeValue(user)7576if user is None:77continue7879isDba = self.isDba(user)8081if isDba is True:82areAdmins.add(user)8384kb.data.cachedUsersPrivileges[user] = None8586return (kb.data.cachedUsersPrivileges, areAdmins)8788def getDbs(self):89if len(kb.data.cachedDbs) > 0:90return kb.data.cachedDbs9192infoMsg = "fetching database names"93logger.info(infoMsg)9495rootQuery = queries[DBMS.SYBASE].dbs96query = rootQuery.inband.query9798if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:99blinds = [False, True]100else:101blinds = [True]102103for blind in blinds:104retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.name' % kb.aliasName], blind=blind, alias=kb.aliasName)105106if retVal:107kb.data.cachedDbs = next(six.itervalues(retVal[0]))108break109110if kb.data.cachedDbs:111kb.data.cachedDbs.sort()112113return kb.data.cachedDbs114115def getTables(self, bruteForce=None):116if len(kb.data.cachedTables) > 0:117return kb.data.cachedTables118119self.forceDbmsEnum()120121if conf.db == CURRENT_DB:122conf.db = self.getCurrentDb()123124if conf.db:125dbs = conf.db.split(',')126else:127dbs = self.getDbs()128129for db in dbs:130dbs[dbs.index(db)] = safeSQLIdentificatorNaming(db)131132dbs = [_ for _ in dbs if _]133134infoMsg = "fetching tables for database"135infoMsg += "%s: %s" % ("s" if len(dbs) > 1 else "", ", ".join(db if isinstance(db, six.string_types) else db[0] for db in sorted(dbs)))136logger.info(infoMsg)137138if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:139blinds = [False, True]140else:141blinds = [True]142143rootQuery = queries[DBMS.SYBASE].tables144145for db in dbs:146for blind in blinds:147query = rootQuery.inband.query % db148retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.name' % kb.aliasName], blind=blind, alias=kb.aliasName)149150if retVal:151for table in next(six.itervalues(retVal[0])):152if db not in kb.data.cachedTables:153kb.data.cachedTables[db] = [table]154else:155kb.data.cachedTables[db].append(table)156break157158for db, tables in kb.data.cachedTables.items():159kb.data.cachedTables[db] = sorted(tables) if tables else tables160161return kb.data.cachedTables162163def getColumns(self, onlyColNames=False, colTuple=None, bruteForce=None, dumpMode=False):164self.forceDbmsEnum()165166if conf.db is None or conf.db == CURRENT_DB:167if conf.db is None:168warnMsg = "missing database parameter. sqlmap is going "169warnMsg += "to use the current database to enumerate "170warnMsg += "table(s) columns"171logger.warning(warnMsg)172173conf.db = self.getCurrentDb()174175elif conf.db is not None:176if ',' in conf.db:177errMsg = "only one database name is allowed when enumerating "178errMsg += "the tables' columns"179raise SqlmapMissingMandatoryOptionException(errMsg)180181conf.db = safeSQLIdentificatorNaming(conf.db)182183if conf.col:184colList = conf.col.split(',')185else:186colList = []187188if conf.exclude:189colList = [_ for _ in colList if re.search(conf.exclude, _, re.I) is None]190191for col in colList:192colList[colList.index(col)] = safeSQLIdentificatorNaming(col)193194if conf.tbl:195tblList = conf.tbl.split(',')196else:197self.getTables()198199if len(kb.data.cachedTables) > 0:200tblList = list(six.itervalues(kb.data.cachedTables))201202if tblList and isListLike(tblList[0]):203tblList = tblList[0]204else:205errMsg = "unable to retrieve the tables "206errMsg += "on database '%s'" % unsafeSQLIdentificatorNaming(conf.db)207raise SqlmapNoneDataException(errMsg)208209for tbl in tblList:210tblList[tblList.index(tbl)] = safeSQLIdentificatorNaming(tbl, True)211212if bruteForce:213resumeAvailable = False214215for tbl in tblList:216for db, table, colName, colType in kb.brute.columns:217if db == conf.db and table == tbl:218resumeAvailable = True219break220221if resumeAvailable and not conf.freshQueries or colList:222columns = {}223224for column in colList:225columns[column] = None226227for tbl in tblList:228for db, table, colName, colType in kb.brute.columns:229if db == conf.db and table == tbl:230columns[colName] = colType231232if conf.db in kb.data.cachedColumns:233kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns234else:235kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = {safeSQLIdentificatorNaming(tbl, True): columns}236237return kb.data.cachedColumns238239message = "do you want to use common column existence check? [y/N/q] "240choice = readInput(message, default='Y' if 'Y' in message else 'N').upper()241242if choice == 'N':243return244elif choice == 'Q':245raise SqlmapUserQuitException246else:247return columnExists(paths.COMMON_COLUMNS)248249rootQuery = queries[DBMS.SYBASE].columns250251if any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.UNION, PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) or conf.direct:252blinds = [False, True]253else:254blinds = [True]255256for tbl in tblList:257if conf.db is not None and len(kb.data.cachedColumns) > 0 \258and conf.db in kb.data.cachedColumns and tbl in \259kb.data.cachedColumns[conf.db]:260infoMsg = "fetched tables' columns on "261infoMsg += "database '%s'" % unsafeSQLIdentificatorNaming(conf.db)262logger.info(infoMsg)263264return {conf.db: kb.data.cachedColumns[conf.db]}265266if dumpMode and colList:267table = {}268table[safeSQLIdentificatorNaming(tbl, True)] = dict((_, None) for _ in colList)269kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table270continue271272infoMsg = "fetching columns "273infoMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl)274infoMsg += "on database '%s'" % unsafeSQLIdentificatorNaming(conf.db)275logger.info(infoMsg)276277for blind in blinds:278query = rootQuery.inband.query % (conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, unsafeSQLIdentificatorNaming(tbl))279retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.name' % kb.aliasName, '%s.usertype' % kb.aliasName], blind=blind, alias=kb.aliasName)280281if retVal:282table = {}283columns = {}284285for name, type_ in filterPairValues(_zip(retVal[0]["%s.name" % kb.aliasName], retVal[0]["%s.usertype" % kb.aliasName])):286columns[name] = SYBASE_TYPES.get(int(type_) if hasattr(type_, "isdigit") and type_.isdigit() else type_, type_)287288table[safeSQLIdentificatorNaming(tbl, True)] = columns289kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table290291break292293return kb.data.cachedColumns294295def searchDb(self):296warnMsg = "on Sybase searching of databases is not implemented"297logger.warning(warnMsg)298299return []300301def searchTable(self):302warnMsg = "on Sybase searching of tables is not implemented"303logger.warning(warnMsg)304305return []306307def searchColumn(self):308warnMsg = "on Sybase searching of columns is not implemented"309logger.warning(warnMsg)310311return []312313def search(self):314warnMsg = "on Sybase search option is not available"315logger.warning(warnMsg)316317def getHostname(self):318warnMsg = "on Sybase it is not possible to enumerate the hostname"319logger.warning(warnMsg)320321def getStatements(self):322warnMsg = "on Sybase it is not possible to enumerate the SQL statements"323logger.warning(warnMsg)324325return []326327328