Path: blob/master/plugins/dbms/maxdb/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 isListLike10from lib.core.common import isTechniqueAvailable11from lib.core.common import readInput12from lib.core.common import safeSQLIdentificatorNaming13from lib.core.common import unsafeSQLIdentificatorNaming14from lib.core.data import conf15from lib.core.data import kb16from lib.core.data import logger17from lib.core.data import paths18from lib.core.data import queries19from lib.core.enums import DBMS20from lib.core.enums import PAYLOAD21from lib.core.exception import SqlmapMissingMandatoryOptionException22from lib.core.exception import SqlmapNoneDataException23from lib.core.exception import SqlmapUserQuitException24from lib.core.settings import CURRENT_DB25from lib.utils.brute import columnExists26from lib.utils.pivotdumptable import pivotDumpTable27from plugins.generic.enumeration import Enumeration as GenericEnumeration28from thirdparty import six29from thirdparty.six.moves import zip as _zip3031class Enumeration(GenericEnumeration):32def __init__(self):33GenericEnumeration.__init__(self)3435kb.data.processChar = lambda x: x.replace('_', ' ') if x else x3637def getPasswordHashes(self):38warnMsg = "on SAP MaxDB it is not possible to enumerate the user password hashes"39logger.warning(warnMsg)4041return {}4243def getDbs(self):44if len(kb.data.cachedDbs) > 0:45return kb.data.cachedDbs4647infoMsg = "fetching database names"48logger.info(infoMsg)4950rootQuery = queries[DBMS.MAXDB].dbs51query = rootQuery.inband.query52retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.schemaname' % kb.aliasName], blind=True)5354if retVal:55kb.data.cachedDbs = next(six.itervalues(retVal[0]))5657if kb.data.cachedDbs:58kb.data.cachedDbs.sort()5960return kb.data.cachedDbs6162def getTables(self, bruteForce=None):63if len(kb.data.cachedTables) > 0:64return kb.data.cachedTables6566self.forceDbmsEnum()6768if conf.db == CURRENT_DB:69conf.db = self.getCurrentDb()7071if conf.db:72dbs = conf.db.split(',')73else:74dbs = self.getDbs()7576for db in (_ for _ in dbs if _):77dbs[dbs.index(db)] = safeSQLIdentificatorNaming(db)7879infoMsg = "fetching tables for database"80infoMsg += "%s: %s" % ("s" if len(dbs) > 1 else "", ", ".join(db if isinstance(db, six.string_types) else db[0] for db in sorted(dbs)))81logger.info(infoMsg)8283rootQuery = queries[DBMS.MAXDB].tables8485for db in dbs:86query = rootQuery.inband.query % (("'%s'" % db) if db != "USER" else 'USER')87blind = not isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION)88retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.tablename' % kb.aliasName], blind=blind)8990if retVal:91for table in list(retVal[0].values())[0]:92if db not in kb.data.cachedTables:93kb.data.cachedTables[db] = [table]94else:95kb.data.cachedTables[db].append(table)9697for db, tables in kb.data.cachedTables.items():98kb.data.cachedTables[db] = sorted(tables) if tables else tables99100return kb.data.cachedTables101102def getColumns(self, onlyColNames=False, colTuple=None, bruteForce=None, dumpMode=False):103self.forceDbmsEnum()104105if conf.db is None or conf.db == CURRENT_DB:106if conf.db is None:107warnMsg = "missing database parameter. sqlmap is going "108warnMsg += "to use the current database to enumerate "109warnMsg += "table(s) columns"110logger.warning(warnMsg)111112conf.db = self.getCurrentDb()113114elif conf.db is not None:115if ',' in conf.db:116errMsg = "only one database name is allowed when enumerating "117errMsg += "the tables' columns"118raise SqlmapMissingMandatoryOptionException(errMsg)119120conf.db = safeSQLIdentificatorNaming(conf.db)121122if conf.col:123colList = conf.col.split(',')124else:125colList = []126127if conf.exclude:128colList = [_ for _ in colList if re.search(conf.exclude, _, re.I) is None]129130for col in colList:131colList[colList.index(col)] = safeSQLIdentificatorNaming(col)132133if conf.tbl:134tblList = conf.tbl.split(',')135else:136self.getTables()137138if len(kb.data.cachedTables) > 0:139tblList = list(kb.data.cachedTables.values())140141if tblList and isListLike(tblList[0]):142tblList = tblList[0]143else:144errMsg = "unable to retrieve the tables "145errMsg += "on database '%s'" % unsafeSQLIdentificatorNaming(conf.db)146raise SqlmapNoneDataException(errMsg)147148for tbl in tblList:149tblList[tblList.index(tbl)] = safeSQLIdentificatorNaming(tbl, True)150151if bruteForce:152resumeAvailable = False153154for tbl in tblList:155for db, table, colName, colType in kb.brute.columns:156if db == conf.db and table == tbl:157resumeAvailable = True158break159160if resumeAvailable and not conf.freshQueries or colList:161columns = {}162163for column in colList:164columns[column] = None165166for tbl in tblList:167for db, table, colName, colType in kb.brute.columns:168if db == conf.db and table == tbl:169columns[colName] = colType170171if conf.db in kb.data.cachedColumns:172kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)][safeSQLIdentificatorNaming(tbl, True)] = columns173else:174kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = {safeSQLIdentificatorNaming(tbl, True): columns}175176return kb.data.cachedColumns177178message = "do you want to use common column existence check? [y/N/q] "179choice = readInput(message, default='Y' if 'Y' in message else 'N').upper()180181if choice == 'N':182return183elif choice == 'Q':184raise SqlmapUserQuitException185else:186return columnExists(paths.COMMON_COLUMNS)187188rootQuery = queries[DBMS.MAXDB].columns189190for tbl in tblList:191if 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]:192infoMsg = "fetched tables' columns on "193infoMsg += "database '%s'" % unsafeSQLIdentificatorNaming(conf.db)194logger.info(infoMsg)195196return {conf.db: kb.data.cachedColumns[conf.db]}197198if dumpMode and colList:199table = {}200table[safeSQLIdentificatorNaming(tbl, True)] = dict((_, None) for _ in colList)201kb.data.cachedColumns[safeSQLIdentificatorNaming(conf.db)] = table202continue203204infoMsg = "fetching columns "205infoMsg += "for table '%s' " % unsafeSQLIdentificatorNaming(tbl)206infoMsg += "on database '%s'" % unsafeSQLIdentificatorNaming(conf.db)207logger.info(infoMsg)208209blind = not isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION)210211query = rootQuery.inband.query % (unsafeSQLIdentificatorNaming(tbl), ("'%s'" % unsafeSQLIdentificatorNaming(conf.db)) if unsafeSQLIdentificatorNaming(conf.db) != "USER" else 'USER')212retVal = pivotDumpTable("(%s) AS %s" % (query, kb.aliasName), ['%s.columnname' % kb.aliasName, '%s.datatype' % kb.aliasName, '%s.len' % kb.aliasName], blind=blind)213214if retVal:215table = {}216columns = {}217218for columnname, datatype, length in _zip(retVal[0]["%s.columnname" % kb.aliasName], retVal[0]["%s.datatype" % kb.aliasName], retVal[0]["%s.len" % kb.aliasName]):219columns[safeSQLIdentificatorNaming(columnname)] = "%s(%s)" % (datatype, length)220221table[tbl] = columns222kb.data.cachedColumns[conf.db] = table223224return kb.data.cachedColumns225226def getPrivileges(self, *args, **kwargs):227warnMsg = "on SAP MaxDB it is not possible to enumerate the user privileges"228logger.warning(warnMsg)229230return {}231232def search(self):233warnMsg = "on SAP MaxDB search option is not available"234logger.warning(warnMsg)235236def getHostname(self):237warnMsg = "on SAP MaxDB it is not possible to enumerate the hostname"238logger.warning(warnMsg)239240def getStatements(self):241warnMsg = "on SAP MaxDB it is not possible to enumerate the SQL statements"242logger.warning(warnMsg)243244return []245246247