diff --git a/lib/controller/checks.py b/lib/controller/checks.py index 8bf476295..95c0edfa4 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -12,6 +12,7 @@ import socket import time from lib.core.agent import agent +from lib.core.common import aliasToDbmsEnum from lib.core.common import beep from lib.core.common import extractRegexResult from lib.core.common import findDynamicContent @@ -430,7 +431,7 @@ def checkSqlInjection(place, parameter, value): for detailKey, detailValue in test.details.items(): if detailKey == "dbms" and injection.dbms is None: injection.dbms = detailValue - kb.dbms = detailValue + kb.dbms = aliasToDbmsEnum(detailValue) elif detailKey == "dbms_version" and injection.dbms_version is None: injection.dbms_version = detailValue kb.dbmsVersion = [ detailValue ] diff --git a/lib/controller/handler.py b/lib/controller/handler.py index adc96f779..d218ccf7d 100644 --- a/lib/controller/handler.py +++ b/lib/controller/handler.py @@ -7,7 +7,7 @@ Copyright (c) 2006-2010 sqlmap developers (http://sqlmap.sourceforge.net/) See the file 'doc/COPYING' for copying permission """ -from lib.core.common import getErrorParsedDBMSes +from lib.core.common import getIdentifiedDBMS from lib.core.common import popValue from lib.core.common import pushValue from lib.core.data import conf @@ -63,18 +63,11 @@ def setHandler(): ( SYBASE_ALIASES, SybaseMap, SybaseConn ), ] - inferencedDbms = (getErrorParsedDBMSes()[0] if getErrorParsedDBMSes() else '') or kb.dbms - - for injection in kb.injections: - if hasattr(injection, "dbms") and injection.dbms: - inferencedDbms = injection.dbms - break - - if inferencedDbms is not None: + if getIdentifiedDBMS() is not None: for i in xrange(len(dbmsObj)): dbmsAliases, _, _ = dbmsObj[i] - if inferencedDbms.lower() in dbmsAliases: + if getIdentifiedDBMS().lower() in dbmsAliases: if i > 0: pushValue(dbmsObj[i]) dbmsObj.remove(dbmsObj[i]) diff --git a/lib/core/agent.py b/lib/core/agent.py index 754578b16..a752b8ba1 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -13,6 +13,7 @@ from xml.etree import ElementTree as ET from lib.core.common import getCompiledRegex from lib.core.common import getErrorParsedDBMSes +from lib.core.common import getIdentifiedDBMS from lib.core.common import isDBMSVersionAtLeast from lib.core.common import isTechniqueAvailable from lib.core.common import randomInt @@ -33,13 +34,6 @@ class Agent: This class defines the SQL agent methods. """ - def __init__(self): - kb.misc = advancedDict() - kb.misc.delimiter = randomStr(length=6) - kb.misc.start = ":%s:" % randomStr(length=3, lowercase=True) - kb.misc.stop = ":%s:" % randomStr(length=3, lowercase=True) - kb.misc.space = ":%s:" % randomStr(length=1, lowercase=True) - def payloadDirect(self, query): if query.startswith("AND "): query = query.replace("AND ", "SELECT ", 1) @@ -211,8 +205,8 @@ class Agent: payload = payload.replace("[ORIGVALUE]", origvalue) if "[INFERENCE]" in payload: - if kb.dbms is not None: - inference = queries[kb.dbms].inference + if getIdentifiedDBMS() is not None: + inference = queries[getIdentifiedDBMS()].inference if "dbms_version" in inference: if isDBMSVersionAtLeast(inference.dbms_version): @@ -223,11 +217,6 @@ class Agent: inferenceQuery = inference.query payload = payload.replace("[INFERENCE]", inferenceQuery) - - elif hasattr(kb.misc, "testedDbms") and kb.misc.testedDbms is not None: - inferenceQuery = queries[kb.misc.testedDbms].inference.query - payload = payload.replace("[INFERENCE]", inferenceQuery) - else: errMsg = "invalid usage of inference payload without " errMsg += "knowledge of underlying DBMS" @@ -275,17 +264,17 @@ class Agent: # SQLite version 2 does not support neither CAST() nor IFNULL(), # introduced only in SQLite version 3 - if kb.dbms == DBMS.SQLITE: + if getIdentifiedDBMS() == DBMS.SQLITE: return field if field.startswith("(CASE"): nulledCastedField = field else: - nulledCastedField = queries[kb.dbms].cast.query % field - if kb.dbms == DBMS.ACCESS: - nulledCastedField = queries[kb.dbms].isnull.query % (nulledCastedField, nulledCastedField) + nulledCastedField = queries[getIdentifiedDBMS()].cast.query % field + if getIdentifiedDBMS() == DBMS.ACCESS: + nulledCastedField = queries[getIdentifiedDBMS()].isnull.query % (nulledCastedField, nulledCastedField) else: - nulledCastedField = queries[kb.dbms].isnull.query % nulledCastedField + nulledCastedField = queries[getIdentifiedDBMS()].isnull.query % nulledCastedField return nulledCastedField @@ -324,7 +313,7 @@ class Agent: fields = fields.replace(", ", ",") fieldsSplitted = fields.split(",") - dbmsDelimiter = queries[kb.dbms].delimiter.query + dbmsDelimiter = queries[getIdentifiedDBMS()].delimiter.query nulledCastedFields = [] for field in fieldsSplitted: @@ -383,13 +372,13 @@ class Agent: def simpleConcatQuery(self, query1, query2): concatenatedQuery = "" - if kb.dbms == DBMS.MYSQL: + if getIdentifiedDBMS() == DBMS.MYSQL: concatenatedQuery = "CONCAT(%s,%s)" % (query1, query2) - elif kb.dbms in ( DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE ): + elif getIdentifiedDBMS() in ( DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE ): concatenatedQuery = "%s||%s" % (query1, query2) - elif kb.dbms in (DBMS.MSSQL, DBMS.SYBASE): + elif getIdentifiedDBMS() in (DBMS.MSSQL, DBMS.SYBASE): concatenatedQuery = "%s+%s" % (query1, query2) return concatenatedQuery @@ -431,7 +420,7 @@ class Agent: concatenatedQuery = query fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, fieldsSelectCase, _, fieldsToCastStr = self.getFields(query) - if kb.dbms == DBMS.MYSQL: + if getIdentifiedDBMS() == DBMS.MYSQL: if fieldsSelectCase: concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT('%s'," % kb.misc.start, 1) concatenatedQuery += ",'%s')" % kb.misc.stop @@ -444,7 +433,7 @@ class Agent: elif fieldsNoSelect: concatenatedQuery = "CONCAT('%s',%s,'%s')" % (kb.misc.start, concatenatedQuery, kb.misc.stop) - elif kb.dbms in ( DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE ): + elif getIdentifiedDBMS() in ( DBMS.PGSQL, DBMS.ORACLE, DBMS.SQLITE ): if fieldsSelectCase: concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % kb.misc.start, 1) concatenatedQuery += "||'%s'" % kb.misc.stop @@ -457,10 +446,10 @@ class Agent: elif fieldsNoSelect: concatenatedQuery = "'%s'||%s||'%s'" % (kb.misc.start, concatenatedQuery, kb.misc.stop) - if kb.dbms == DBMS.ORACLE and " FROM " not in concatenatedQuery and ( fieldsSelect or fieldsNoSelect ): + if getIdentifiedDBMS() == DBMS.ORACLE and " FROM " not in concatenatedQuery and ( fieldsSelect or fieldsNoSelect ): concatenatedQuery += " FROM DUAL" - elif kb.dbms in (DBMS.MSSQL, DBMS.SYBASE): + elif getIdentifiedDBMS() in (DBMS.MSSQL, DBMS.SYBASE): if fieldsSelectTop: topNum = re.search("\ASELECT\s+TOP\s+([\d]+)\s+", concatenatedQuery, re.I).group(1) concatenatedQuery = concatenatedQuery.replace("SELECT TOP %s " % topNum, "TOP %s '%s'+" % (topNum, kb.misc.start), 1) @@ -511,13 +500,13 @@ class Agent: """ if query.startswith("SELECT "): - query = query[len("SELECT "):] + query = query[len("SELECT "):] inbandQuery = self.prefixQuery("UNION ALL SELECT ", prefix=prefix) if query.startswith("TOP"): - topNum = re.search("\ATOP\s+([\d]+)\s+", query, re.I).group(1) - query = query[len("TOP %s " % topNum):] + topNum = re.search("\ATOP\s+([\d]+)\s+", query, re.I).group(1) + query = query[len("TOP %s " % topNum):] inbandQuery += "TOP %s " % topNum intoRegExp = re.search("(\s+INTO (DUMP|OUT)FILE\s+\'(.+?)\')", query, re.I) @@ -526,7 +515,7 @@ class Agent: intoRegExp = intoRegExp.group(1) query = query[:query.index(intoRegExp)] - if kb.dbms == DBMS.ORACLE and inbandQuery.endswith(" FROM DUAL"): + if getIdentifiedDBMS() == DBMS.ORACLE and inbandQuery.endswith(" FROM DUAL"): inbandQuery = inbandQuery[:-len(" FROM DUAL")] for element in range(count): @@ -546,7 +535,7 @@ class Agent: conditionIndex = query.index(" FROM ") inbandQuery += query[conditionIndex:] - if kb.dbms == DBMS.ORACLE or DBMS.ORACLE in getErrorParsedDBMSes(): + if getIdentifiedDBMS() == DBMS.ORACLE: if " FROM " not in inbandQuery: inbandQuery += " FROM DUAL" @@ -565,7 +554,7 @@ class Agent: else: inbandQuery += char - if kb.dbms == DBMS.ORACLE: + if getIdentifiedDBMS() == DBMS.ORACLE: inbandQuery += " FROM DUAL" inbandQuery = self.suffixQuery(inbandQuery, comment, suffix) @@ -595,21 +584,21 @@ class Agent: """ limitedQuery = query - limitStr = queries[kb.dbms].limit.query + limitStr = queries[getIdentifiedDBMS()].limit.query fromIndex = limitedQuery.index(" FROM ") untilFrom = limitedQuery[:fromIndex] fromFrom = limitedQuery[fromIndex+1:] orderBy = False - if kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE ): - limitStr = queries[kb.dbms].limit.query % (num, 1) + if getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE ): + limitStr = queries[getIdentifiedDBMS()].limit.query % (num, 1) limitedQuery += " %s" % limitStr - elif kb.dbms == DBMS.FIREBIRD: - limitStr = queries[kb.dbms].limit.query % (num+1, num+1) + elif getIdentifiedDBMS() == DBMS.FIREBIRD: + limitStr = queries[getIdentifiedDBMS()].limit.query % (num+1, num+1) limitedQuery += " %s" % limitStr - elif kb.dbms == DBMS.ORACLE: + elif getIdentifiedDBMS() == DBMS.ORACLE: if " ORDER BY " in limitedQuery and "(SELECT " in limitedQuery: orderBy = limitedQuery[limitedQuery.index(" ORDER BY "):] limitedQuery = limitedQuery[:limitedQuery.index(" ORDER BY ")] @@ -621,7 +610,7 @@ class Agent: limitedQuery = limitedQuery % fromFrom limitedQuery += "=%d" % (num + 1) - elif kb.dbms in (DBMS.MSSQL, DBMS.SYBASE): + elif getIdentifiedDBMS() in (DBMS.MSSQL, DBMS.SYBASE): forgeNotIn = True if " ORDER BY " in limitedQuery: @@ -635,7 +624,7 @@ class Agent: limitedQuery = limitedQuery.replace("DISTINCT %s" % notDistinct, notDistinct) if limitedQuery.startswith("SELECT TOP ") or limitedQuery.startswith("TOP "): - topNums = re.search(queries[kb.dbms].limitregexp.query, limitedQuery, re.I) + topNums = re.search(queries[getIdentifiedDBMS()].limitregexp.query, limitedQuery, re.I) if topNums: topNums = topNums.groups() @@ -681,7 +670,7 @@ class Agent: @rtype: C{str} """ - return queries[kb.dbms if kb.dbms else kb.misc.testedDbms].case.query % expression + return queries[getIdentifiedDBMS()].case.query % expression def addPayloadDelimiters(self, inpStr): """ diff --git a/lib/core/common.py b/lib/core/common.py index c470c4de1..d2ac6354a 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -218,15 +218,15 @@ def formatDBMSfp(versions=None): versions = kb.dbmsVersion if isinstance(versions, basestring): - return "%s %s" % (kb.dbms, versions) + return "%s %s" % (getIdentifiedDBMS(), versions) elif isinstance(versions, (list, set, tuple)): - return "%s %s" % (kb.dbms, " and ".join([version for version in versions])) + return "%s %s" % (getIdentifiedDBMS(), " and ".join([version for version in versions])) elif not versions: warnMsg = "unable to extensively fingerprint the back-end " warnMsg += "DBMS version" logger.warn(warnMsg) - return kb.dbms + return getIdentifiedDBMS() def formatFingerprintString(values, chain=" or "): strJoin = "|".join([v for v in values]) @@ -627,7 +627,7 @@ def parsePasswordHash(password): if not password or password == " ": password = "NULL" - if kb.dbms == DBMS.MSSQL and password != "NULL" and isHexEncodedString(password): + if getIdentifiedDBMS() == DBMS.MSSQL and password != "NULL" and isHexEncodedString(password): hexPassword = password password = "%s\n" % hexPassword password += "%sheader: %s\n" % (blank, hexPassword[:6]) @@ -928,25 +928,25 @@ def parseUnionPage(output, expression, partial=False, condition=None, sort=True) def getDelayQuery(andCond=False): query = None - if kb.dbms in (DBMS.MYSQL, DBMS.PGSQL): + if getIdentifiedDBMS() in (DBMS.MYSQL, DBMS.PGSQL): if not kb.data.banner: conf.dbmsHandler.getVersionFromBanner() banVer = kb.bannerFp["dbmsVersion"] if 'dbmsVersion' in kb.bannerFp else None - if banVer is None or (kb.dbms == DBMS.MYSQL and banVer >= "5.0.12") or (kb.dbms == DBMS.PGSQL and banVer >= "8.2"): - query = queries[kb.dbms].timedelay.query % conf.timeSec + if banVer is None or (getIdentifiedDBMS() == DBMS.MYSQL and banVer >= "5.0.12") or (getIdentifiedDBMS() == DBMS.PGSQL and banVer >= "8.2"): + query = queries[getIdentifiedDBMS()].timedelay.query % conf.timeSec else: - query = queries[kb.dbms].timedelay.query2 % conf.timeSec - elif kb.dbms == DBMS.FIREBIRD: - query = queries[kb.dbms].timedelay.query + query = queries[getIdentifiedDBMS()].timedelay.query2 % conf.timeSec + elif getIdentifiedDBMS() == DBMS.FIREBIRD: + query = queries[getIdentifiedDBMS()].timedelay.query else: - query = queries[kb.dbms].timedelay.query % conf.timeSec + query = queries[getIdentifiedDBMS()].timedelay.query % conf.timeSec if andCond: - if kb.dbms in ( DBMS.MYSQL, DBMS.SQLITE ): + if getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.SQLITE ): query = query.replace("SELECT ", "") - elif kb.dbms == DBMS.FIREBIRD: + elif getIdentifiedDBMS() == DBMS.FIREBIRD: query = "(%s)>0" % query return query @@ -1763,7 +1763,7 @@ def aliasToDbmsEnum(value): retVal = None for key, item in dbmsDict.items(): - if value in item[0]: + if value.lower() in item[0]: retVal = key break @@ -2040,6 +2040,18 @@ def getErrorParsedDBMSes(): return kb.htmlFp +def getIdentifiedDBMS(): + dbms = None + + if kb.dbms is not None: + dbms = kb.dbms + elif conf.dbms is not None: + dbms = conf.dbms + elif getErrorParsedDBMSes() is not None: + dbms = getErrorParsedDBMSes()[0] + + return aliasToDbmsEnum(dbms) + def showHttpErrorCodes(): """ Shows all HTTP error codes raised till now diff --git a/lib/core/enums.py b/lib/core/enums.py index 6e9845aa5..02103dbbc 100644 --- a/lib/core/enums.py +++ b/lib/core/enums.py @@ -31,7 +31,7 @@ class DBMS: MSSQL = "Microsoft SQL Server" MYSQL = "MySQL" ORACLE = "Oracle" - PGSQL = "PostgreSQL" + PGSQL = "PostgreSQL" SQLITE = "SQLite" SYBASE = "Sybase" diff --git a/lib/core/option.py b/lib/core/option.py index bbc52cbad..58165b6e8 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -34,6 +34,7 @@ from lib.core.common import parseTargetDirect from lib.core.common import parseTargetUrl from lib.core.common import paths from lib.core.common import randomRange +from lib.core.common import randomStr from lib.core.common import readCachedFileContent from lib.core.common import readInput from lib.core.common import runningAsAdmin @@ -46,6 +47,7 @@ from lib.core.data import paths from lib.core.data import queries from lib.core.datatype import advancedDict from lib.core.datatype import injectionDict +from lib.core.enums import DBMS from lib.core.enums import HTTPMETHOD from lib.core.enums import PAYLOAD from lib.core.enums import PRIORITY @@ -1165,6 +1167,12 @@ def __setKnowledgeBaseAttributes(flushAll=True): kb.threadException = False kb.threadData = {} + kb.misc = advancedDict() + kb.misc.delimiter = randomStr(length=6) + kb.misc.start = ":%s:" % randomStr(length=3, lowercase=True) + kb.misc.stop = ":%s:" % randomStr(length=3, lowercase=True) + kb.misc.space = ":%s:" % randomStr(length=1, lowercase=True) + if flushAll: kb.keywords = set(getFileItems(paths.SQL_KEYWORDS)) kb.tamperFunctions = [] diff --git a/lib/core/session.py b/lib/core/session.py index 0a9258c66..e08547a11 100644 --- a/lib/core/session.py +++ b/lib/core/session.py @@ -13,6 +13,7 @@ from lib.core.common import aliasToDbmsEnum from lib.core.common import dataToSessionFile from lib.core.common import formatFingerprintString from lib.core.common import getFilteredPageContent +from lib.core.common import getIdentifiedDBMS from lib.core.common import readInput from lib.core.convert import base64pickle from lib.core.convert import base64unpickle @@ -140,7 +141,7 @@ def setDbms(dbms): if dbmsRegExp: dbms = dbmsRegExp.group(1) - kb.dbms = dbms + kb.dbms = aliasToDbmsEnum(dbms) logger.info("the back-end DBMS is %s" % kb.dbms) @@ -340,7 +341,7 @@ def resumeConfKb(expression, url, value): if '.' in table: db, table = table.split('.') else: - db = "%s%s" % (kb.dbms, METADB_SUFFIX) + db = "%s%s" % (getIdentifiedDBMS(), METADB_SUFFIX) logMsg = "resuming brute forced table name " logMsg += "'%s' from session file" % table @@ -355,7 +356,7 @@ def resumeConfKb(expression, url, value): if '.' in table: db, table = table.split('.') else: - db = "%s%s" % (kb.dbms, METADB_SUFFIX) + db = "%s%s" % (getIdentifiedDBMS(), METADB_SUFFIX) logMsg = "resuming brute forced column name " logMsg += "'%s' for table '%s' from session file" % (colName, table) diff --git a/lib/core/shell.py b/lib/core/shell.py index f99fe52f7..36d2a4e10 100644 --- a/lib/core/shell.py +++ b/lib/core/shell.py @@ -12,6 +12,7 @@ import os import rlcompleter from lib.core import readlineng as readline +from lib.core.common import getIdentifiedDBMS from lib.core.data import kb from lib.core.data import paths from lib.core.data import queries @@ -29,7 +30,7 @@ def loadHistory(): def queriesForAutoCompletion(): autoComplQueries = {} - for item in queries[kb.dbms]._toflat(): + for item in queries[getIdentifiedDBMS()]._toflat(): if item._has_key('query') and len(item.query) > 1 and item._name != 'blind': autoComplQueries[item.query] = None diff --git a/lib/core/unescaper.py b/lib/core/unescaper.py index 0cad913c6..e603fd6df 100644 --- a/lib/core/unescaper.py +++ b/lib/core/unescaper.py @@ -7,18 +7,15 @@ Copyright (c) 2006-2010 sqlmap developers (http://sqlmap.sourceforge.net/) See the file 'doc/COPYING' for copying permission """ -from lib.core.common import getErrorParsedDBMSes -from lib.core.data import kb +from lib.core.common import getIdentifiedDBMS from lib.core.datatype import advancedDict class Unescaper(advancedDict): def unescape(self, expression, quote=True, dbms=None): - if hasattr(kb, "dbms") and kb.dbms is not None: - return self[kb.dbms](expression, quote=quote) - elif hasattr(kb.misc, "testedDbms") and kb.misc.testedDbms is not None: - return self[kb.misc.testedDbms](expression, quote=quote) - elif getErrorParsedDBMSes(): - return self[getErrorParsedDBMSes()[0]](expression, quote=quote) + identifiedDbms = getIdentifiedDBMS() + + if identifiedDbms is not None: + return self[identifiedDbms](expression, quote=quote) elif dbms is not None: return self[dbms](expression, quote=quote) else: diff --git a/lib/parse/banner.py b/lib/parse/banner.py index 524882f46..da3ae5a5b 100644 --- a/lib/parse/banner.py +++ b/lib/parse/banner.py @@ -13,6 +13,7 @@ from xml.sax.handler import ContentHandler from lib.core.common import checkFile from lib.core.common import getCompiledRegex +from lib.core.common import getIdentifiedDBMS from lib.core.common import parseXmlFile from lib.core.common import sanitizeStr from lib.core.data import kb @@ -94,13 +95,13 @@ def bannerParser(banner): xmlfile = None - if kb.dbms == DBMS.MSSQL: + if getIdentifiedDBMS() == DBMS.MSSQL: xmlfile = paths.MSSQL_XML - elif kb.dbms == DBMS.MYSQL: + elif getIdentifiedDBMS() == DBMS.MYSQL: xmlfile = paths.MYSQL_XML - elif kb.dbms == DBMS.ORACLE: + elif getIdentifiedDBMS() == DBMS.ORACLE: xmlfile = paths.ORACLE_XML - elif kb.dbms == DBMS.PGSQL: + elif getIdentifiedDBMS() == DBMS.PGSQL: xmlfile = paths.PGSQL_XML if not xmlfile: @@ -108,7 +109,7 @@ def bannerParser(banner): checkFile(xmlfile) - if kb.dbms == DBMS.MSSQL: + if getIdentifiedDBMS() == DBMS.MSSQL: handler = MSSQLBannerHandler(banner, kb.bannerFp) parseXmlFile(xmlfile, handler) diff --git a/lib/request/direct.py b/lib/request/direct.py index 486f6ac2d..366eadb57 100644 --- a/lib/request/direct.py +++ b/lib/request/direct.py @@ -9,6 +9,7 @@ See the file 'doc/COPYING' for copying permission from lib.core.agent import agent from lib.core.common import dataToSessionFile +from lib.core.common import getIdentifiedDBMS from lib.core.common import getUnicode from lib.core.convert import base64pickle from lib.core.convert import base64unpickle @@ -25,7 +26,7 @@ def direct(query, content=True): select = False query = agent.payloadDirect(query) - if kb.dbms == DBMS.ORACLE and query.startswith("SELECT ") and " FROM " not in query: + if getIdentifiedDBMS() == DBMS.ORACLE and query.startswith("SELECT ") and " FROM " not in query: query = "%s FROM DUAL" % query for sqlTitle, sqlStatements in SQL_STATEMENTS.items(): diff --git a/lib/request/inject.py b/lib/request/inject.py index 646920fbc..1247bcf08 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -15,6 +15,7 @@ from lib.core.common import calculateDeltaSeconds from lib.core.common import cleanQuery from lib.core.common import dataToSessionFile from lib.core.common import expandAsteriskForColumns +from lib.core.common import getIdentifiedDBMS from lib.core.common import getPublicTypeMembers from lib.core.common import initTechnique from lib.core.common import isTechniqueAvailable @@ -48,7 +49,7 @@ from lib.utils.resume import resume def __goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None): start = time.time() - if ( conf.eta or conf.threads > 1 ) and kb.dbms: + if ( conf.eta or conf.threads > 1 ) and getIdentifiedDBMS(): _, length, _ = queryOutputLength(expression, payload) else: length = None @@ -160,7 +161,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r _, _, _, _, _, expressionFieldsList, expressionFields = agent.getFields(expression) rdbRegExp = re.search("RDB\$GET_CONTEXT\([^)]+\)", expression, re.I) - if rdbRegExp and kb.dbms == DBMS.FIREBIRD: + if rdbRegExp and getIdentifiedDBMS() == DBMS.FIREBIRD: expressionFieldsList = [expressionFields] if len(expressionFieldsList) > 1: @@ -176,13 +177,13 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r # NOTE: I assume that only queries that get data from a table # can return multiple entries if fromUser and " FROM " in expression: - limitRegExp = re.search(queries[kb.dbms].limitregexp.query, expression, re.I) + limitRegExp = re.search(queries[getIdentifiedDBMS()].limitregexp.query, expression, re.I) topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I) - if limitRegExp or ( kb.dbms in (DBMS.MSSQL, DBMS.SYBASE) and topLimit ): - if kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL ): - limitGroupStart = queries[kb.dbms].limitgroupstart.query - limitGroupStop = queries[kb.dbms].limitgroupstop.query + if limitRegExp or ( getIdentifiedDBMS() in (DBMS.MSSQL, DBMS.SYBASE) and topLimit ): + if getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.PGSQL ): + limitGroupStart = queries[getIdentifiedDBMS()].limitgroupstart.query + limitGroupStop = queries[getIdentifiedDBMS()].limitgroupstop.query if limitGroupStart.isdigit(): startLimit = int(limitRegExp.group(int(limitGroupStart))) @@ -190,10 +191,10 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r stopLimit = limitRegExp.group(int(limitGroupStop)) limitCond = int(stopLimit) > 1 - elif kb.dbms in (DBMS.MSSQL, DBMS.SYBASE): + elif getIdentifiedDBMS() in (DBMS.MSSQL, DBMS.SYBASE): if limitRegExp: - limitGroupStart = queries[kb.dbms].limitgroupstart.query - limitGroupStop = queries[kb.dbms].limitgroupstop.query + limitGroupStart = queries[getIdentifiedDBMS()].limitgroupstart.query + limitGroupStop = queries[getIdentifiedDBMS()].limitgroupstop.query if limitGroupStart.isdigit(): startLimit = int(limitRegExp.group(int(limitGroupStart))) @@ -205,7 +206,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r stopLimit = int(topLimit.group(1)) limitCond = int(stopLimit) > 1 - elif kb.dbms == DBMS.ORACLE: + elif getIdentifiedDBMS() == DBMS.ORACLE: limitCond = False else: limitCond = True @@ -219,16 +220,16 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r # From now on we need only the expression until the " LIMIT " # (or similar, depending on the back-end DBMS) word - if kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL ): + if getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.PGSQL ): stopLimit += startLimit - untilLimitChar = expression.index(queries[kb.dbms].limitstring.query) + untilLimitChar = expression.index(queries[getIdentifiedDBMS()].limitstring.query) expression = expression[:untilLimitChar] - elif kb.dbms in (DBMS.MSSQL, DBMS.SYBASE): + elif getIdentifiedDBMS() in (DBMS.MSSQL, DBMS.SYBASE): stopLimit += startLimit if not stopLimit or stopLimit <= 1: - if kb.dbms == DBMS.ORACLE and expression.endswith("FROM DUAL"): + if getIdentifiedDBMS() == DBMS.ORACLE and expression.endswith("FROM DUAL"): test = "n" elif batch: test = "y" @@ -239,7 +240,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r if not test or test[0] in ("y", "Y"): # Count the number of SQL query entries output - countFirstField = queries[kb.dbms].count.query % expressionFieldsList[0] + countFirstField = queries[getIdentifiedDBMS()].count.query % expressionFieldsList[0] countedExpression = expression.replace(expressionFields, countFirstField, 1) if re.search(" ORDER BY ", expression, re.I): @@ -327,7 +328,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r return outputs - elif kb.dbms == DBMS.ORACLE and expression.startswith("SELECT ") and " FROM " not in expression: + elif getIdentifiedDBMS() == DBMS.ORACLE and expression.startswith("SELECT ") and " FROM " not in expression: expression = "%s FROM DUAL" % expression outputs = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, resumeValue=resumeValue, charsetType=charsetType, firstChar=firstChar, lastChar=lastChar) @@ -488,7 +489,7 @@ def goStacked(expression, silent=False): if conf.direct: return direct(expression), None - comment = queries[kb.dbms].comment.query + comment = queries[getIdentifiedDBMS()].comment.query query = agent.prefixQuery("; %s" % expression) query = agent.suffixQuery("%s;%s" % (query, comment)) diff --git a/lib/takeover/abstraction.py b/lib/takeover/abstraction.py index b82c8fc86..2163cf578 100644 --- a/lib/takeover/abstraction.py +++ b/lib/takeover/abstraction.py @@ -8,6 +8,7 @@ See the file 'doc/COPYING' for copying permission """ from lib.core.common import dataToStdout +from lib.core.common import getIdentifiedDBMS from lib.core.common import isTechniqueAvailable from lib.core.common import readInput from lib.core.data import conf @@ -40,10 +41,10 @@ class Abstraction(Web, UDF, xp_cmdshell): if self.webBackdoorUrl and not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED): self.webBackdoorRunCmd(cmd) - elif kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL ): + elif getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.PGSQL ): self.udfExecCmd(cmd, silent=silent) - elif kb.dbms == DBMS.MSSQL: + elif getIdentifiedDBMS() == DBMS.MSSQL: self.xpCmdshellExecCmd(cmd, silent=silent) else: @@ -54,10 +55,10 @@ class Abstraction(Web, UDF, xp_cmdshell): if self.webBackdoorUrl and not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED): return self.webBackdoorRunCmd(cmd) - elif kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL ): + elif getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.PGSQL ): return self.udfEvalCmd(cmd, first, last) - elif kb.dbms == DBMS.MSSQL: + elif getIdentifiedDBMS() == DBMS.MSSQL: return self.xpCmdshellEvalCmd(cmd, first, last) else: @@ -92,13 +93,13 @@ class Abstraction(Web, UDF, xp_cmdshell): logger.info(infoMsg) else: - if kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL ): + if getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.PGSQL ): infoMsg = "going to use injected sys_eval and sys_exec " infoMsg += "user-defined functions for operating system " infoMsg += "command execution" logger.info(infoMsg) - elif kb.dbms == DBMS.MSSQL: + elif getIdentifiedDBMS() == DBMS.MSSQL: infoMsg = "going to use xp_cmdshell extended procedure for " infoMsg += "operating system command execution" logger.info(infoMsg) @@ -150,9 +151,9 @@ class Abstraction(Web, UDF, xp_cmdshell): warnMsg += "the session user is not a database administrator" logger.warn(warnMsg) - if kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL ): + if getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.PGSQL ): self.udfInjectSys() - elif kb.dbms == DBMS.MSSQL: + elif getIdentifiedDBMS() == DBMS.MSSQL: if mandatory: self.xpCmdshellInit() else: diff --git a/lib/takeover/metasploit.py b/lib/takeover/metasploit.py index bb19953ef..36481e42f 100644 --- a/lib/takeover/metasploit.py +++ b/lib/takeover/metasploit.py @@ -19,6 +19,7 @@ from subprocess import PIPE from subprocess import Popen as execute from lib.core.common import dataToStdout +from lib.core.common import getIdentifiedDBMS from lib.core.common import getLocalIP from lib.core.common import getRemoteIP from lib.core.common import getUnicode @@ -186,13 +187,13 @@ class Metasploit: if __payloadStr == "windows/vncinject": choose = False - if kb.dbms == DBMS.MYSQL: + if getIdentifiedDBMS() == DBMS.MYSQL: debugMsg = "by default MySQL on Windows runs as SYSTEM " debugMsg += "user, it is likely that the the VNC " debugMsg += "injection will be successful" logger.debug(debugMsg) - elif kb.dbms == DBMS.PGSQL: + elif getIdentifiedDBMS() == DBMS.PGSQL: choose = True warnMsg = "by default PostgreSQL on Windows runs as " @@ -200,7 +201,7 @@ class Metasploit: warnMsg += "injection will be successful" logger.warn(warnMsg) - elif kb.dbms == DBMS.MSSQL and kb.dbmsVersion[0] in ( "2005", "2008" ): + elif getIdentifiedDBMS() == DBMS.MSSQL and kb.dbmsVersion[0] in ( "2005", "2008" ): choose = True warnMsg = "it is unlikely that the VNC injection will be " @@ -229,12 +230,12 @@ class Metasploit: break elif choice == "1": - if kb.dbms == DBMS.PGSQL: + if getIdentifiedDBMS() == DBMS.PGSQL: logger.warn("beware that the VNC injection might not work") break - elif kb.dbms == DBMS.MSSQL and kb.dbmsVersion[0] in ( "2005", "2008" ): + elif getIdentifiedDBMS() == DBMS.MSSQL and kb.dbmsVersion[0] in ( "2005", "2008" ): break elif not choice.isdigit(): @@ -554,7 +555,7 @@ class Metasploit: # This is useful for sqlmap because on PostgreSQL it is not # possible to write files bigger than 8192 bytes abusing the # lo_export() feature implemented in sqlmap. - if kb.dbms == DBMS.PGSQL: + if getIdentifiedDBMS() == DBMS.PGSQL: self.__fileFormat = "exe-small" else: self.__fileFormat = "exe" @@ -656,7 +657,7 @@ class Metasploit: self.__forgeMsfConsoleResource() self.__forgeMsfConsoleCmd() - if kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL ): + if getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.PGSQL ): self.uncPath = "\\\\\\\\%s\\\\%s" % (self.lhostStr, self.__randFile) else: self.uncPath = "\\\\%s\\%s" % (self.lhostStr, self.__randFile) diff --git a/lib/takeover/udf.py b/lib/takeover/udf.py index e1b4e0a10..dd6b838c8 100644 --- a/lib/takeover/udf.py +++ b/lib/takeover/udf.py @@ -11,6 +11,7 @@ import os from lib.core.agent import agent from lib.core.common import dataToStdout +from lib.core.common import getIdentifiedDBMS from lib.core.common import isTechniqueAvailable from lib.core.common import readInput from lib.core.data import conf @@ -50,7 +51,7 @@ class UDF: def __checkExistUdf(self, udf): logger.info("checking if UDF '%s' already exist" % udf) - query = agent.forgeCaseStatement(queries[kb.dbms].check_udf.query % (udf, udf)) + query = agent.forgeCaseStatement(queries[getIdentifiedDBMS()].check_udf.query % (udf, udf)) exists = inject.getValue(query, resumeValue=False, unpack=False, charsetType=2) if exists == "1": @@ -103,7 +104,7 @@ class UDF: return output def udfCheckNeeded(self): - if ( not conf.rFile or ( conf.rFile and kb.dbms != DBMS.PGSQL ) ) and "sys_fileread" in self.sysUdfs: + if ( not conf.rFile or ( conf.rFile and getIdentifiedDBMS() != DBMS.PGSQL ) ) and "sys_fileread" in self.sysUdfs: self.sysUdfs.pop("sys_fileread") if not conf.osPwn: @@ -142,9 +143,9 @@ class UDF: if udf in self.udfToCreate and udf not in self.createdUdf: self.udfCreateFromSharedLib(udf, inpRet) - if kb.dbms == DBMS.MYSQL: + if getIdentifiedDBMS() == DBMS.MYSQL: supportTblType = "longtext" - elif kb.dbms == DBMS.PGSQL: + elif getIdentifiedDBMS() == DBMS.PGSQL: supportTblType = "text" self.udfCreateSupportTbl(supportTblType) @@ -155,8 +156,8 @@ class UDF: self.udfInjectCore(self.sysUdfs) def udfInjectCustom(self): - if kb.dbms not in ( DBMS.MYSQL, DBMS.PGSQL ): - errMsg = "UDF injection feature is not yet implemented on %s" % kb.dbms + if getIdentifiedDBMS() not in ( DBMS.MYSQL, DBMS.PGSQL ): + errMsg = "UDF injection feature is not yet implemented on %s" % getIdentifiedDBMS() raise sqlmapUnsupportedFeatureException(errMsg) if not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) and not conf.direct: @@ -235,9 +236,9 @@ class UDF: else: logger.warn("you need to specify the name of the UDF") - if kb.dbms == DBMS.MYSQL: + if getIdentifiedDBMS() == DBMS.MYSQL: defaultType = "string" - elif kb.dbms == DBMS.PGSQL: + elif getIdentifiedDBMS() == DBMS.PGSQL: defaultType = "text" self.udfs[udfName]["input"] = [] diff --git a/lib/techniques/blind/inference.py b/lib/techniques/blind/inference.py index 486a37b8d..327ae9a13 100644 --- a/lib/techniques/blind/inference.py +++ b/lib/techniques/blind/inference.py @@ -16,6 +16,7 @@ from lib.core.common import dataToSessionFile from lib.core.common import dataToStdout from lib.core.common import filterControlChars from lib.core.common import getCharset +from lib.core.common import getIdentifiedDBMS from lib.core.common import goGoodSamaritan from lib.core.common import getPartRun from lib.core.common import popValue @@ -49,7 +50,6 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None finalValue = "" asciiTbl = getCharset(charsetType) timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) - dbms = kb.dbms if kb.dbms else kb.misc.testedDbms # Set kb.partRun in case "common prediction" feature (a.k.a. "good # samaritan") is used @@ -121,7 +121,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None hintlock.release() if hintValue is not None and len(hintValue) >= idx: - if dbms in (DBMS.SQLITE, DBMS.ACCESS, DBMS.MAXDB): + if getIdentifiedDBMS() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.MAXDB): posValue = hintValue[idx-1] else: posValue = ord(hintValue[idx-1]) @@ -454,7 +454,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None # check it via equal against the substring-query output if commonPattern is not None: # Substring-query containing equals commonPattern - subquery = queries[dbms].substring.query % (expressionUnescaped, 1, len(commonPattern)) + subquery = queries[getIdentifiedDBMS()].substring.query % (expressionUnescaped, 1, len(commonPattern)) testValue = unescaper.unescape("'%s'" % commonPattern) if "'" not in commonPattern else unescaper.unescape("%s" % commonPattern, quote=False) query = agent.prefixQuery(safeStringFormat("AND (%s) = %s", (subquery, testValue))) query = agent.suffixQuery(query) diff --git a/lib/techniques/brute/use.py b/lib/techniques/brute/use.py index 76049fedb..e034d38d3 100644 --- a/lib/techniques/brute/use.py +++ b/lib/techniques/brute/use.py @@ -15,6 +15,7 @@ from lib.core.common import dataToSessionFile from lib.core.common import dataToStdout from lib.core.common import filterListValue from lib.core.common import getFileItems +from lib.core.common import getIdentifiedDBMS from lib.core.common import getPageTextWordsSet from lib.core.common import popValue from lib.core.common import pushValue @@ -31,7 +32,7 @@ from lib.core.session import safeFormatString from lib.request import inject def tableExists(tableFile, regex=None): - tables = getFileItems(tableFile, lowercase=kb.dbms in (DBMS.ACCESS), unique=True) + tables = getFileItems(tableFile, lowercase=getIdentifiedDBMS() in (DBMS.ACCESS), unique=True) retVal = [] infoMsg = "checking table existence using items from '%s'" % tableFile diff --git a/lib/techniques/error/use.py b/lib/techniques/error/use.py index f68c1e720..4d823ced3 100644 --- a/lib/techniques/error/use.py +++ b/lib/techniques/error/use.py @@ -13,6 +13,7 @@ import time from lib.core.agent import agent from lib.core.common import dataToStdout from lib.core.common import extractRegexResult +from lib.core.common import getIdentifiedDBMS from lib.core.common import initTechnique from lib.core.common import randomInt from lib.core.common import replaceNewlineTabs @@ -44,7 +45,7 @@ def errorUse(expression): _, _, _, _, _, _, fieldToCastStr = agent.getFields(expression) nulledCastedField = agent.nullAndCastField(fieldToCastStr) - if kb.dbms == DBMS.MYSQL: + if getIdentifiedDBMS() == DBMS.MYSQL: nulledCastedField = nulledCastedField.replace("AS CHAR)", "AS CHAR(100))") # fix for that 'Subquery returns more than 1 row' expression = expression.replace(fieldToCastStr, nulledCastedField, 1) diff --git a/lib/techniques/inband/union/test.py b/lib/techniques/inband/union/test.py index 55e945a9f..181b9ac0a 100644 --- a/lib/techniques/inband/union/test.py +++ b/lib/techniques/inband/union/test.py @@ -12,6 +12,7 @@ import time from lib.core.agent import agent from lib.core.common import clearConsoleLine from lib.core.common import dataToStdout +from lib.core.common import getIdentifiedDBMS from lib.core.common import getUnicode from lib.core.common import parseUnionPage from lib.core.common import randomStr @@ -62,7 +63,7 @@ def __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, coun # Perform the request resultPage, _ = Request.queryPage(payload, place=place, content=True) - if resultPage and " UNION ALL SELECT " not in resultPage and (randQuery not in resultPage or randQuery2 not in resultPage): + if resultPage and " UNION ALL SELECT " not in resultPage and ((randQuery in resultPage and randQuery2 not in resultPage) or (randQuery not in resultPage and randQuery2 in resultPage)): vector = (position, count, comment, prefix, suffix, conf.uChar, 2) break @@ -96,13 +97,13 @@ def __unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix query = agent.prefixQuery("UNION ALL SELECT %s" % conf.uChar) for count in range(conf.uColsStart, conf.uColsStop+1): - if kb.dbms == DBMS.ORACLE and query.endswith(" FROM DUAL"): + if getIdentifiedDBMS() == DBMS.ORACLE and query.endswith(" FROM DUAL"): query = query[:-len(" FROM DUAL")] if count: query += ", %s" % conf.uChar - if kb.dbms == DBMS.ORACLE: + if getIdentifiedDBMS() == DBMS.ORACLE: query += " FROM DUAL" status = '%d/%d (%d%s)' % (count, conf.uColsStop, round(100.0*count/conf.uColsStop), '%') diff --git a/lib/techniques/inband/union/use.py b/lib/techniques/inband/union/use.py index 8c5b368d4..b8f0162e2 100644 --- a/lib/techniques/inband/union/use.py +++ b/lib/techniques/inband/union/use.py @@ -14,6 +14,7 @@ from lib.core.agent import agent from lib.core.common import calculateDeltaSeconds from lib.core.common import clearConsoleLine from lib.core.common import dataToStdout +from lib.core.common import getIdentifiedDBMS from lib.core.common import getUnicode from lib.core.common import initTechnique from lib.core.common import parseUnionPage @@ -65,12 +66,12 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh # NOTE: I assume that only queries that get data from a table can # return multiple entries if " FROM " in expression and "EXISTS(" not in expression: - limitRegExp = re.search(queries[kb.dbms].limitregexp.query, expression, re.I) + limitRegExp = re.search(queries[getIdentifiedDBMS()].limitregexp.query, expression, re.I) if limitRegExp: - if kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL ): - limitGroupStart = queries[kb.dbms].limitgroupstart.query - limitGroupStop = queries[kb.dbms].limitgroupstop.query + if getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.PGSQL ): + limitGroupStart = queries[getIdentifiedDBMS()].limitgroupstart.query + limitGroupStop = queries[getIdentifiedDBMS()].limitgroupstop.query if limitGroupStart.isdigit(): startLimit = int(limitRegExp.group(int(limitGroupStart))) @@ -78,9 +79,9 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh stopLimit = limitRegExp.group(int(limitGroupStop)) limitCond = int(stopLimit) > 1 - elif kb.dbms in (DBMS.MSSQL, DBMS.SYBASE): - limitGroupStart = queries[kb.dbms].limitgroupstart.query - limitGroupStop = queries[kb.dbms].limitgroupstop.query + elif getIdentifiedDBMS() in (DBMS.MSSQL, DBMS.SYBASE): + limitGroupStart = queries[getIdentifiedDBMS()].limitgroupstart.query + limitGroupStop = queries[getIdentifiedDBMS()].limitgroupstop.query if limitGroupStart.isdigit(): startLimit = int(limitRegExp.group(int(limitGroupStart))) @@ -88,7 +89,7 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh stopLimit = limitRegExp.group(int(limitGroupStop)) limitCond = int(stopLimit) > 1 - elif kb.dbms == DBMS.ORACLE: + elif getIdentifiedDBMS() == DBMS.ORACLE: limitCond = False else: limitCond = True @@ -102,12 +103,12 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh # From now on we need only the expression until the " LIMIT " # (or similar, depending on the back-end DBMS) word - if kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL ): + if getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.PGSQL ): stopLimit += startLimit - untilLimitChar = expression.index(queries[kb.dbms].limitstring.query) + untilLimitChar = expression.index(queries[getIdentifiedDBMS()].limitstring.query) expression = expression[:untilLimitChar] - elif kb.dbms in (DBMS.MSSQL, DBMS.SYBASE): + elif getIdentifiedDBMS() in (DBMS.MSSQL, DBMS.SYBASE): stopLimit += startLimit elif dump: if conf.limitStart: @@ -116,14 +117,14 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh stopLimit = conf.limitStop if not stopLimit or stopLimit <= 1: - if kb.dbms == DBMS.ORACLE and expression.endswith("FROM DUAL"): + if getIdentifiedDBMS() == DBMS.ORACLE and expression.endswith("FROM DUAL"): test = False else: test = True if test: # Count the number of SQL query entries output - countFirstField = queries[kb.dbms].count.query % expressionFieldsList[0] + countFirstField = queries[getIdentifiedDBMS()].count.query % expressionFieldsList[0] countedExpression = origExpr.replace(expressionFields, countFirstField, 1) if re.search(" ORDER BY ", expression, re.I): @@ -171,9 +172,9 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh try: for num in xrange(startLimit, stopLimit): - if kb.dbms in (DBMS.MSSQL, DBMS.SYBASE): + if getIdentifiedDBMS() in (DBMS.MSSQL, DBMS.SYBASE): field = expressionFieldsList[0] - elif kb.dbms == DBMS.ORACLE: + elif getIdentifiedDBMS() == DBMS.ORACLE: field = expressionFieldsList else: field = None diff --git a/lib/utils/hash.py b/lib/utils/hash.py index 578e8d516..9b13c59db 100644 --- a/lib/utils/hash.py +++ b/lib/utils/hash.py @@ -22,6 +22,7 @@ from lib.core.common import clearConsoleLine from lib.core.common import dataToStdout from lib.core.common import getCompiledRegex from lib.core.common import getFileItems +from lib.core.common import getIdentifiedDBMS from lib.core.common import getPublicTypeMembers from lib.core.common import getUnicode from lib.core.common import paths @@ -267,10 +268,10 @@ def hashRecognition(value): if value: for name, regex in getPublicTypeMembers(HASH): - #hashes for Oracle and old MySQL look the same hence these checks - if kb.dbms == DBMS.ORACLE and regex == HASH.MYSQL_OLD: + # Hashes for Oracle and old MySQL look the same hence these checks + if getIdentifiedDBMS() == DBMS.ORACLE and regex == HASH.MYSQL_OLD: continue - elif kb.dbms == DBMS.MYSQL and regex == HASH.ORACLE_OLD: + elif getIdentifiedDBMS() == DBMS.MYSQL and regex == HASH.ORACLE_OLD: continue elif getCompiledRegex(regex).match(value): retVal = regex diff --git a/lib/utils/resume.py b/lib/utils/resume.py index a85adb771..3b434e7ac 100644 --- a/lib/utils/resume.py +++ b/lib/utils/resume.py @@ -13,6 +13,7 @@ import time from lib.core.common import calculateDeltaSeconds from lib.core.common import dataToSessionFile from lib.core.common import dataToStdout +from lib.core.common import getIdentifiedDBMS from lib.core.common import safeStringFormat from lib.core.common import randomStr from lib.core.common import replaceNewlineTabs @@ -33,8 +34,7 @@ def queryOutputLength(expression, payload): Returns the query output length. """ - lengthQuery = queries[kb.dbms].length.query - + lengthQuery = queries[getIdentifiedDBMS()].length.query select = re.search("\ASELECT\s+", expression, re.I) selectTopExpr = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I) selectDistinctExpr = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I) @@ -60,7 +60,7 @@ def queryOutputLength(expression, payload): if selectDistinctExpr: lengthExpr = "SELECT %s FROM (%s)" % (lengthQuery % regExpr, expression) - if kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL ): + if getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.PGSQL ): lengthExpr += " AS %s" % randomStr(lowercase=True) elif select: lengthExpr = expression.replace(regExpr, lengthQuery % regExpr, 1) @@ -142,10 +142,10 @@ def resume(expression, payload): if not payload: return None - if not kb.dbms: + if not getIdentifiedDBMS(): return None - substringQuery = queries[kb.dbms].substring.query + substringQuery = queries[getIdentifiedDBMS()].substring.query select = re.search("\ASELECT ", expression, re.I) _, length, regExpr = queryOutputLength(expression, payload) diff --git a/plugins/dbms/access/fingerprint.py b/plugins/dbms/access/fingerprint.py index 52d432f0b..9a2f19294 100644 --- a/plugins/dbms/access/fingerprint.py +++ b/plugins/dbms/access/fingerprint.py @@ -14,6 +14,7 @@ from lib.core.common import formatDBMSfp from lib.core.common import formatFingerprint from lib.core.common import getCurrentThreadData from lib.core.common import getErrorParsedDBMSesFormatted +from lib.core.common import getIdentifiedDBMS from lib.core.common import randomInt from lib.core.common import randomStr from lib.core.common import wasLastRequestDBMSError @@ -148,7 +149,7 @@ class Fingerprint(GenericFingerprint): return value def checkDbms(self): - if (kb.dbms is not None and kb.dbms.lower() in ACCESS_ALIASES) or conf.dbms in ACCESS_ALIASES: + if (getIdentifiedDBMS() is not None and getIdentifiedDBMS().lower() in ACCESS_ALIASES) or conf.dbms in ACCESS_ALIASES: setDbms(DBMS.ACCESS) if not conf.extensiveFp: diff --git a/plugins/dbms/firebird/fingerprint.py b/plugins/dbms/firebird/fingerprint.py index 337d5f675..dbac48896 100644 --- a/plugins/dbms/firebird/fingerprint.py +++ b/plugins/dbms/firebird/fingerprint.py @@ -13,6 +13,7 @@ from lib.core.agent import agent from lib.core.common import formatDBMSfp from lib.core.common import formatFingerprint from lib.core.common import getErrorParsedDBMSesFormatted +from lib.core.common import getIdentifiedDBMS from lib.core.common import getUnicode from lib.core.common import randomInt from lib.core.common import randomRange @@ -97,13 +98,13 @@ class Fingerprint(GenericFingerprint): def __dialectCheck(self): retVal = None - if kb.dbms: + if getIdentifiedDBMS(): result = inject.checkBooleanExpression("EXISTS(SELECT CURRENT_DATE FROM RDB$DATABASE)") retVal = "dialect 3" if result else "dialect 1" return retVal def checkDbms(self): - if (kb.dbms is not None and kb.dbms.lower() in FIREBIRD_ALIASES) or conf.dbms in FIREBIRD_ALIASES: + if (getIdentifiedDBMS() is not None and getIdentifiedDBMS().lower() in FIREBIRD_ALIASES) or conf.dbms in FIREBIRD_ALIASES: setDbms(DBMS.FIREBIRD) self.getBanner() diff --git a/plugins/dbms/maxdb/fingerprint.py b/plugins/dbms/maxdb/fingerprint.py index bd67587f4..1228bd11e 100644 --- a/plugins/dbms/maxdb/fingerprint.py +++ b/plugins/dbms/maxdb/fingerprint.py @@ -13,6 +13,7 @@ from lib.core.agent import agent from lib.core.common import formatDBMSfp from lib.core.common import formatFingerprint from lib.core.common import getErrorParsedDBMSesFormatted +from lib.core.common import getIdentifiedDBMS from lib.core.common import randomInt from lib.core.common import randomRange from lib.core.data import conf @@ -100,7 +101,7 @@ class Fingerprint(GenericFingerprint): return value def checkDbms(self): - if (kb.dbms is not None and kb.dbms.lower() in MAXDB_ALIASES) or conf.dbms in MAXDB_ALIASES: + if (getIdentifiedDBMS() is not None and getIdentifiedDBMS().lower() in MAXDB_ALIASES) or conf.dbms in MAXDB_ALIASES: setDbms(DBMS.MAXDB) self.getBanner() diff --git a/plugins/dbms/mssqlserver/enumeration.py b/plugins/dbms/mssqlserver/enumeration.py index 2b2cf0430..34c2a091c 100644 --- a/plugins/dbms/mssqlserver/enumeration.py +++ b/plugins/dbms/mssqlserver/enumeration.py @@ -9,6 +9,7 @@ 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 getIdentifiedDBMS from lib.core.common import getRange from lib.core.common import isNumPosStrValue from lib.core.common import isTechniqueAvailable @@ -40,7 +41,7 @@ class Enumeration(GenericEnumeration): infoMsg += " for database '%s'" % conf.db logger.info(infoMsg) - rootQuery = queries[kb.dbms].tables + rootQuery = queries[getIdentifiedDBMS()].tables if not conf.db: if not len(kb.data.cachedDbs): @@ -110,7 +111,7 @@ class Enumeration(GenericEnumeration): return kb.data.cachedTables def searchTable(self): - rootQuery = queries[kb.dbms].search_table + rootQuery = queries[getIdentifiedDBMS()].search_table foundTbls = {} tblList = conf.tbl.split(",") tblCond = rootQuery.inband.condition @@ -194,7 +195,7 @@ class Enumeration(GenericEnumeration): return foundTbls def searchColumn(self): - rootQuery = queries[kb.dbms].search_column + rootQuery = queries[getIdentifiedDBMS()].search_column foundCols = {} dbs = {} colList = conf.col.split(",") diff --git a/plugins/dbms/mssqlserver/fingerprint.py b/plugins/dbms/mssqlserver/fingerprint.py index 6753227cf..ba4d7d6c4 100644 --- a/plugins/dbms/mssqlserver/fingerprint.py +++ b/plugins/dbms/mssqlserver/fingerprint.py @@ -11,6 +11,7 @@ from lib.core.agent import agent from lib.core.common import formatDBMSfp from lib.core.common import formatFingerprint from lib.core.common import getErrorParsedDBMSesFormatted +from lib.core.common import getIdentifiedDBMS from lib.core.common import getUnicode from lib.core.common import randomInt from lib.core.data import conf @@ -72,7 +73,7 @@ class Fingerprint(GenericFingerprint): return value def checkDbms(self): - if ((kb.dbms is not None and kb.dbms.lower() in MSSQL_ALIASES) \ + if ((getIdentifiedDBMS() is not None and getIdentifiedDBMS().lower() in MSSQL_ALIASES) \ or conf.dbms in MSSQL_ALIASES) and kb.dbmsVersion and \ kb.dbmsVersion[0].isdigit(): setDbms("%s %s" % (DBMS.MSSQL, kb.dbmsVersion[0])) diff --git a/plugins/dbms/mysql/fingerprint.py b/plugins/dbms/mysql/fingerprint.py index 180312f29..7fe8bb229 100644 --- a/plugins/dbms/mysql/fingerprint.py +++ b/plugins/dbms/mysql/fingerprint.py @@ -13,6 +13,7 @@ from lib.core.agent import agent from lib.core.common import formatDBMSfp from lib.core.common import formatFingerprint from lib.core.common import getErrorParsedDBMSesFormatted +from lib.core.common import getIdentifiedDBMS from lib.core.common import getUnicode from lib.core.common import randomInt from lib.core.data import conf @@ -151,7 +152,7 @@ class Fingerprint(GenericFingerprint): * http://dev.mysql.com/doc/refman/6.0/en/news-6-0-x.html (manual has been withdrawn) """ - if ((kb.dbms is not None and kb.dbms.lower() in MYSQL_ALIASES) \ + if ((getIdentifiedDBMS() is not None and getIdentifiedDBMS().lower() in MYSQL_ALIASES) \ or conf.dbms in MYSQL_ALIASES) and kb.dbmsVersion and \ kb.dbmsVersion[0] != UNKNOWN_DBMS_VERSION: kb.dbmsVersion[0] = kb.dbmsVersion[0].replace(">", "") diff --git a/plugins/dbms/oracle/enumeration.py b/plugins/dbms/oracle/enumeration.py index 6611b86f7..892780cec 100644 --- a/plugins/dbms/oracle/enumeration.py +++ b/plugins/dbms/oracle/enumeration.py @@ -8,6 +8,7 @@ See the file 'doc/COPYING' for copying permission """ from lib.core.agent import agent +from lib.core.common import getIdentifiedDBMS from lib.core.common import getRange from lib.core.common import isNumPosStrValue from lib.core.common import isTechniqueAvailable @@ -29,7 +30,7 @@ class Enumeration(GenericEnumeration): def getRoles(self, query2=False): infoMsg = "fetching database users roles" - rootQuery = queries[kb.dbms].roles + rootQuery = queries[getIdentifiedDBMS()].roles if conf.user == "CU": infoMsg += " for current user" @@ -178,7 +179,7 @@ class Enumeration(GenericEnumeration): return [] def searchColumn(self): - rootQuery = queries[kb.dbms].search_column + rootQuery = queries[getIdentifiedDBMS()].search_column foundCols = {} dbs = { "USERS": {} } colList = conf.col.split(",") diff --git a/plugins/dbms/oracle/fingerprint.py b/plugins/dbms/oracle/fingerprint.py index 4845d7cbc..a920af28b 100644 --- a/plugins/dbms/oracle/fingerprint.py +++ b/plugins/dbms/oracle/fingerprint.py @@ -13,6 +13,7 @@ from lib.core.agent import agent from lib.core.common import formatDBMSfp from lib.core.common import formatFingerprint from lib.core.common import getErrorParsedDBMSesFormatted +from lib.core.common import getIdentifiedDBMS from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger @@ -64,7 +65,7 @@ class Fingerprint(GenericFingerprint): return value def checkDbms(self): - if (kb.dbms is not None and kb.dbms.lower() in ORACLE_ALIASES) or conf.dbms in ORACLE_ALIASES: + if (getIdentifiedDBMS() is not None and getIdentifiedDBMS().lower() in ORACLE_ALIASES) or conf.dbms in ORACLE_ALIASES: setDbms(DBMS.ORACLE) self.getBanner() diff --git a/plugins/dbms/postgresql/fingerprint.py b/plugins/dbms/postgresql/fingerprint.py index 076117c6b..bfaccd407 100644 --- a/plugins/dbms/postgresql/fingerprint.py +++ b/plugins/dbms/postgresql/fingerprint.py @@ -13,6 +13,7 @@ from lib.core.agent import agent from lib.core.common import formatDBMSfp from lib.core.common import formatFingerprint from lib.core.common import getErrorParsedDBMSesFormatted +from lib.core.common import getIdentifiedDBMS from lib.core.common import getUnicode from lib.core.common import randomInt from lib.core.data import conf @@ -73,7 +74,7 @@ class Fingerprint(GenericFingerprint): * http://www.postgresql.org/docs/8.4/interactive/release.html (up to 8.4.2) """ - if (kb.dbms is not None and kb.dbms.lower() in PGSQL_ALIASES) or conf.dbms in PGSQL_ALIASES: + if (getIdentifiedDBMS() is not None and getIdentifiedDBMS().lower() in PGSQL_ALIASES) or conf.dbms in PGSQL_ALIASES: setDbms(DBMS.PGSQL) self.getBanner() diff --git a/plugins/dbms/sqlite/fingerprint.py b/plugins/dbms/sqlite/fingerprint.py index 205c8a1e2..ff4ebcd60 100644 --- a/plugins/dbms/sqlite/fingerprint.py +++ b/plugins/dbms/sqlite/fingerprint.py @@ -11,6 +11,7 @@ from lib.core.agent import agent from lib.core.common import formatDBMSfp from lib.core.common import formatFingerprint from lib.core.common import getErrorParsedDBMSesFormatted +from lib.core.common import getIdentifiedDBMS from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger @@ -70,7 +71,7 @@ class Fingerprint(GenericFingerprint): * http://www.sqlite.org/cvstrac/wiki?p=LoadableExtensions """ - if (kb.dbms is not None and kb.dbms.lower() in SQLITE_ALIASES) or conf.dbms in SQLITE_ALIASES: + if (getIdentifiedDBMS() is not None and getIdentifiedDBMS().lower() in SQLITE_ALIASES) or conf.dbms in SQLITE_ALIASES: setDbms(DBMS.SQLITE) self.getBanner() diff --git a/plugins/dbms/sybase/fingerprint.py b/plugins/dbms/sybase/fingerprint.py index 05be959af..03524fc27 100644 --- a/plugins/dbms/sybase/fingerprint.py +++ b/plugins/dbms/sybase/fingerprint.py @@ -11,6 +11,7 @@ from lib.core.agent import agent from lib.core.common import formatDBMSfp from lib.core.common import formatFingerprint from lib.core.common import getErrorParsedDBMSesFormatted +from lib.core.common import getIdentifiedDBMS from lib.core.common import randomInt from lib.core.data import conf from lib.core.data import kb @@ -63,7 +64,7 @@ class Fingerprint(GenericFingerprint): return value def checkDbms(self): - if ((kb.dbms is not None and kb.dbms.lower() in SYBASE_ALIASES) \ + if ((getIdentifiedDBMS() is not None and getIdentifiedDBMS().lower() in SYBASE_ALIASES) \ or conf.dbms in SYBASE_ALIASES) and kb.dbmsVersion and \ kb.dbmsVersion[0].isdigit(): setDbms("%s %s" % (DBMS.SYBASE, kb.dbmsVersion[0])) diff --git a/plugins/generic/enumeration.py b/plugins/generic/enumeration.py index 51b438cce..e289790b3 100644 --- a/plugins/generic/enumeration.py +++ b/plugins/generic/enumeration.py @@ -17,6 +17,7 @@ from lib.core.common import getRange from lib.core.common import getCompiledRegex from lib.core.common import getConsoleWidth from lib.core.common import getFileItems +from lib.core.common import getIdentifiedDBMS from lib.core.common import getUnicode from lib.core.common import isNumPosStrValue from lib.core.common import isTechniqueAvailable @@ -74,19 +75,19 @@ class Enumeration: kb.data.cachedColumns = {} kb.data.dumpedTable = {} kb.data.processChar = None - kb.misc.testedDbms = dbms def getBanner(self): if not conf.getBanner: return if kb.data.banner is None: + # TODO: is this assignement an ugly hack? kb.dbmsDetected = True infoMsg = "fetching banner" logger.info(infoMsg) - query = queries[kb.dbms].banner.query + query = queries[getIdentifiedDBMS()].banner.query kb.data.banner = inject.getValue(query) bannerParser(kb.data.banner) @@ -108,7 +109,7 @@ class Enumeration: infoMsg = "fetching current user" logger.info(infoMsg) - query = queries[kb.dbms].current_user.query + query = queries[getIdentifiedDBMS()].current_user.query if not kb.data.currentUser: kb.data.currentUser = inject.getValue(query) @@ -119,7 +120,7 @@ class Enumeration: infoMsg = "fetching current database" logger.info(infoMsg) - query = queries[kb.dbms].current_db.query + query = queries[getIdentifiedDBMS()].current_db.query if not kb.data.currentDb: kb.data.currentDb = inject.getValue(query) @@ -130,11 +131,11 @@ class Enumeration: infoMsg = "testing if current user is DBA" logger.info(infoMsg) - if kb.dbms == DBMS.MYSQL: + if getIdentifiedDBMS() == DBMS.MYSQL: self.getCurrentUser() - query = queries[kb.dbms].is_dba.query % kb.data.currentUser.split("@")[0] + query = queries[getIdentifiedDBMS()].is_dba.query % kb.data.currentUser.split("@")[0] else: - query = queries[kb.dbms].is_dba.query + query = queries[getIdentifiedDBMS()].is_dba.query query = agent.forgeCaseStatement(query) @@ -146,10 +147,10 @@ class Enumeration: infoMsg = "fetching database users" logger.info(infoMsg) - rootQuery = queries[kb.dbms].users + rootQuery = queries[getIdentifiedDBMS()].users - condition = ( kb.dbms == DBMS.MSSQL and kb.dbmsVersion[0] in ( "2005", "2008" ) ) - condition |= ( kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema ) + condition = ( getIdentifiedDBMS() == DBMS.MSSQL and kb.dbmsVersion[0] in ( "2005", "2008" ) ) + condition |= ( getIdentifiedDBMS() == DBMS.MYSQL and not kb.data.has_information_schema ) if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: if condition: @@ -175,14 +176,14 @@ class Enumeration: errMsg = "unable to retrieve the number of database users" raise sqlmapNoneDataException, errMsg - if kb.dbms == DBMS.ORACLE: + if getIdentifiedDBMS() == DBMS.ORACLE: plusOne = True else: plusOne = False indexRange = getRange(count, plusOne=plusOne) for index in indexRange: - if kb.dbms in (DBMS.SYBASE, DBMS.MAXDB): + if getIdentifiedDBMS() in (DBMS.SYBASE, DBMS.MAXDB): query = rootQuery.blind.query % (kb.data.cachedUsers[-1] if kb.data.cachedUsers else " ") elif condition: query = rootQuery.blind.query2 % index @@ -202,7 +203,7 @@ class Enumeration: def getPasswordHashes(self): infoMsg = "fetching database users password hashes" - rootQuery = queries[kb.dbms].passwords + rootQuery = queries[getIdentifiedDBMS()].passwords if conf.user == "CU": infoMsg += " for current user" @@ -211,7 +212,7 @@ class Enumeration: logger.info(infoMsg) if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: - if kb.dbms == DBMS.MSSQL and kb.dbmsVersion[0] in ( "2005", "2008" ): + if getIdentifiedDBMS() == DBMS.MSSQL and kb.dbmsVersion[0] in ( "2005", "2008" ): query = rootQuery.inband.query2 else: query = rootQuery.inband.query @@ -224,7 +225,7 @@ class Enumeration: query += " WHERE " query += " OR ".join("%s = '%s'" % (condition, user) for user in users) else: - if kb.dbms == DBMS.MYSQL: + if getIdentifiedDBMS() == DBMS.MYSQL: parsedUser = re.search("[\047]*(.*?)[\047]*\@", conf.user) if parsedUser: @@ -261,7 +262,7 @@ class Enumeration: retrievedUsers = set() for user in users: - if kb.dbms == DBMS.MYSQL: + if getIdentifiedDBMS() == DBMS.MYSQL: parsedUser = re.search("[\047]*(.*?)[\047]*\@", user) if parsedUser: @@ -274,7 +275,7 @@ class Enumeration: infoMsg += "for user '%s'" % user logger.info(infoMsg) - if kb.dbms == DBMS.MSSQL and kb.dbmsVersion[0] in ( "2005", "2008" ): + if getIdentifiedDBMS() == DBMS.MSSQL and kb.dbmsVersion[0] in ( "2005", "2008" ): query = rootQuery.blind.count2 % user else: query = rootQuery.blind.count % user @@ -291,14 +292,14 @@ class Enumeration: passwords = [] - if kb.dbms == DBMS.ORACLE: + if getIdentifiedDBMS() == DBMS.ORACLE: plusOne = True else: plusOne = False indexRange = getRange(count, plusOne=plusOne) for index in indexRange: - if kb.dbms == DBMS.SYBASE: + if getIdentifiedDBMS() == DBMS.SYBASE: if index > 0: warnMsg = "unable to retrieve other password " warnMsg += "hashes for user '%s'" % user @@ -307,7 +308,7 @@ class Enumeration: else: query = rootQuery.blind.query % user getCurrentThreadData().disableStdOut = True - elif kb.dbms == DBMS.MSSQL: + elif getIdentifiedDBMS() == DBMS.MSSQL: if kb.dbmsVersion[0] in ( "2005", "2008" ): query = rootQuery.blind.query2 % (user, index, user) else: @@ -315,7 +316,7 @@ class Enumeration: else: query = rootQuery.blind.query % (user, index) password = inject.getValue(query, inband=False) - if kb.dbms == DBMS.SYBASE: + if getIdentifiedDBMS() == DBMS.SYBASE: getCurrentThreadData().disableStdOut = False password = "0x%s" % strToHex(password) infoMsg = "retrieved: %s" % password @@ -352,31 +353,31 @@ class Enumeration: def __isAdminFromPrivileges(self, privileges): # In PostgreSQL the usesuper privilege means that the # user is DBA - dbaCondition = ( kb.dbms == DBMS.PGSQL and "super" in privileges ) + dbaCondition = ( getIdentifiedDBMS() == DBMS.PGSQL and "super" in privileges ) # In Oracle the DBA privilege means that the # user is DBA - dbaCondition |= ( kb.dbms == DBMS.ORACLE and "DBA" in privileges ) + dbaCondition |= ( getIdentifiedDBMS() == DBMS.ORACLE and "DBA" in privileges ) # In MySQL >= 5.0 the SUPER privilege means # that the user is DBA - dbaCondition |= ( kb.dbms == DBMS.MYSQL and kb.data.has_information_schema and "SUPER" in privileges ) + dbaCondition |= ( getIdentifiedDBMS() == DBMS.MYSQL and kb.data.has_information_schema and "SUPER" in privileges ) # In MySQL < 5.0 the super_priv privilege means # that the user is DBA - dbaCondition |= ( kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema and "super_priv" in privileges ) + dbaCondition |= ( getIdentifiedDBMS() == DBMS.MYSQL and not kb.data.has_information_schema and "super_priv" in privileges ) # In Firebird there is no specific privilege that means # that the user is DBA # TODO: confirm - dbaCondition |= ( kb.dbms == DBMS.FIREBIRD and "SELECT" in privileges and "INSERT" in privileges and "UPDATE" in privileges and "DELETE" in privileges and "REFERENCES" in privileges and "EXECUTE" in privileges ) + dbaCondition |= ( getIdentifiedDBMS() == DBMS.FIREBIRD and "SELECT" in privileges and "INSERT" in privileges and "UPDATE" in privileges and "DELETE" in privileges and "REFERENCES" in privileges and "EXECUTE" in privileges ) return dbaCondition def getPrivileges(self, query2=False): infoMsg = "fetching database users privileges" - rootQuery = queries[kb.dbms].privileges + rootQuery = queries[getIdentifiedDBMS()].privileges if conf.user == "CU": infoMsg += " for current user" @@ -432,10 +433,10 @@ class Enumeration: } if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: - if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: + if getIdentifiedDBMS() == DBMS.MYSQL and not kb.data.has_information_schema: query = rootQuery.inband.query2 condition = rootQuery.inband.condition2 - elif kb.dbms == DBMS.ORACLE and query2: + elif getIdentifiedDBMS() == DBMS.ORACLE and query2: query = rootQuery.inband.query2 condition = rootQuery.inband.condition2 else: @@ -447,7 +448,7 @@ class Enumeration: query += " WHERE " # NOTE: I assume that the user provided is not in # MySQL >= 5.0 syntax 'user'@'host' - if kb.dbms == DBMS.MYSQL and kb.data.has_information_schema: + if getIdentifiedDBMS() == DBMS.MYSQL and kb.data.has_information_schema: queryUser = "%" + conf.user + "%" query += " OR ".join("%s LIKE '%s'" % (condition, "%" + user + "%") for user in users) else: @@ -455,7 +456,7 @@ class Enumeration: values = inject.getValue(query, blind=False, error=False) - if not values and kb.dbms == DBMS.ORACLE and not query2: + if not values and getIdentifiedDBMS() == DBMS.ORACLE and not query2: infoMsg = "trying with table USER_SYS_PRIVS" logger.info(infoMsg) @@ -477,19 +478,19 @@ class Enumeration: # In PostgreSQL we get 1 if the privilege is # True, 0 otherwise - if kb.dbms == DBMS.PGSQL and getUnicode(privilege).isdigit(): + if getIdentifiedDBMS() == DBMS.PGSQL and getUnicode(privilege).isdigit(): for position, pgsqlPriv in pgsqlPrivs: if count == position and int(privilege) == 1: privileges.add(pgsqlPriv) # In MySQL >= 5.0 and Oracle we get the list # of privileges as string - elif kb.dbms == DBMS.ORACLE or ( kb.dbms == DBMS.MYSQL and kb.data.has_information_schema ): + elif getIdentifiedDBMS() == DBMS.ORACLE or ( getIdentifiedDBMS() == DBMS.MYSQL and kb.data.has_information_schema ): privileges.add(privilege) # In MySQL < 5.0 we get Y if the privilege is # True, N otherwise - elif kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: + elif getIdentifiedDBMS() == DBMS.MYSQL and not kb.data.has_information_schema: for position, mysqlPriv in mysqlPrivs: if count == position and privilege.upper() == "Y": privileges.add(mysqlPriv) @@ -506,7 +507,7 @@ class Enumeration: conditionChar = "=" if conf.user: - if kb.dbms == DBMS.MYSQL and kb.data.has_information_schema: + if getIdentifiedDBMS() == DBMS.MYSQL and kb.data.has_information_schema: conditionChar = " LIKE " if "," in conf.user: @@ -533,7 +534,7 @@ class Enumeration: for user in users: unescapedUser = None - if kb.dbms == DBMS.MYSQL and kb.data.has_information_schema: + if getIdentifiedDBMS() == DBMS.MYSQL and kb.data.has_information_schema: unescapedUser = unescaper.unescape(user, quote=False) if user in retrievedUsers: @@ -548,18 +549,18 @@ class Enumeration: else: queryUser = user - if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: + if getIdentifiedDBMS() == DBMS.MYSQL and not kb.data.has_information_schema: query = rootQuery.blind.count2 % queryUser - elif kb.dbms == DBMS.MYSQL and kb.data.has_information_schema: + elif getIdentifiedDBMS() == DBMS.MYSQL and kb.data.has_information_schema: query = rootQuery.blind.count % (conditionChar, queryUser) - elif kb.dbms == DBMS.ORACLE and query2: + elif getIdentifiedDBMS() == DBMS.ORACLE and query2: query = rootQuery.blind.count2 % queryUser else: query = rootQuery.blind.count % queryUser count = inject.getValue(query, inband=False, expected=EXPECTED.INT, charsetType=2) if not isNumPosStrValue(count): - if not (isinstance(count, basestring) and count.isdigit()) and kb.dbms == DBMS.ORACLE and not query2: + if not (isinstance(count, basestring) and count.isdigit()) and getIdentifiedDBMS() == DBMS.ORACLE and not query2: infoMsg = "trying with table USER_SYS_PRIVS" logger.info(infoMsg) @@ -575,20 +576,20 @@ class Enumeration: privileges = set() - if kb.dbms == DBMS.ORACLE: + if getIdentifiedDBMS() == DBMS.ORACLE: plusOne = True else: plusOne = False indexRange = getRange(count, plusOne=plusOne) for index in indexRange: - if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: + if getIdentifiedDBMS() == DBMS.MYSQL and not kb.data.has_information_schema: query = rootQuery.blind.query2 % (queryUser, index) - elif kb.dbms == DBMS.MYSQL and kb.data.has_information_schema: + elif getIdentifiedDBMS() == DBMS.MYSQL and kb.data.has_information_schema: query = rootQuery.blind.query % (conditionChar, queryUser, index) - elif kb.dbms == DBMS.ORACLE and query2: + elif getIdentifiedDBMS() == DBMS.ORACLE and query2: query = rootQuery.blind.query2 % (queryUser, index) - elif kb.dbms == DBMS.FIREBIRD: + elif getIdentifiedDBMS() == DBMS.FIREBIRD: query = rootQuery.blind.query % (index, queryUser) else: query = rootQuery.blind.query % (queryUser, index) @@ -596,7 +597,7 @@ class Enumeration: # In PostgreSQL we get 1 if the privilege is True, # 0 otherwise - if kb.dbms == DBMS.PGSQL and ", " in privilege: + if getIdentifiedDBMS() == DBMS.PGSQL and ", " in privilege: privilege = privilege.replace(", ", ",") privs = privilege.split(",") i = 1 @@ -611,12 +612,12 @@ class Enumeration: # In MySQL >= 5.0 and Oracle we get the list # of privileges as string - elif kb.dbms == DBMS.ORACLE or ( kb.dbms == DBMS.MYSQL and kb.data.has_information_schema ): + elif getIdentifiedDBMS() == DBMS.ORACLE or ( getIdentifiedDBMS() == DBMS.MYSQL and kb.data.has_information_schema ): privileges.add(privilege) # In MySQL < 5.0 we get Y if the privilege is # True, N otherwise - elif kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: + elif getIdentifiedDBMS() == DBMS.MYSQL and not kb.data.has_information_schema: privilege = privilege.replace(", ", ",") privs = privilege.split(",") i = 1 @@ -630,7 +631,7 @@ class Enumeration: i += 1 # In Firebird we get one letter for each privilege - elif kb.dbms == DBMS.FIREBIRD: + elif getIdentifiedDBMS() == DBMS.FIREBIRD: privileges.add(firebirdPrivs[privilege.strip()]) if self.__isAdminFromPrivileges(privileges): @@ -639,7 +640,7 @@ class Enumeration: # In MySQL < 5.0 we break the cycle after the first # time we get the user's privileges otherwise we # duplicate the same query - if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: + if getIdentifiedDBMS() == DBMS.MYSQL and not kb.data.has_information_schema: break if privileges: @@ -659,14 +660,14 @@ class Enumeration: return ( kb.data.cachedUsersPrivileges, areAdmins ) def getRoles(self, query2=False): - warnMsg = "on %s the concept of roles does not " % kb.dbms + warnMsg = "on %s the concept of roles does not " % getIdentifiedDBMS() warnMsg += "exist. sqlmap will enumerate privileges instead" logger.warn(warnMsg) return self.getPrivileges(query2) def getDbs(self): - if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: + if getIdentifiedDBMS() == 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" @@ -675,10 +676,10 @@ class Enumeration: infoMsg = "fetching database names" logger.info(infoMsg) - rootQuery = queries[kb.dbms].dbs + rootQuery = queries[getIdentifiedDBMS()].dbs if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: - if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: + if getIdentifiedDBMS() == DBMS.MYSQL and not kb.data.has_information_schema: query = rootQuery.inband.query2 else: query = rootQuery.inband.query @@ -691,7 +692,7 @@ class Enumeration: infoMsg = "fetching number of databases" logger.info(infoMsg) - if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: + if getIdentifiedDBMS() == DBMS.MYSQL and not kb.data.has_information_schema: query = rootQuery.blind.count2 else: query = rootQuery.blind.count @@ -704,9 +705,9 @@ class Enumeration: indexRange = getRange(count) for index in indexRange: - if kb.dbms == DBMS.SYBASE: + if getIdentifiedDBMS() == DBMS.SYBASE: query = rootQuery.blind.query % (kb.data.cachedDbs[-1] if kb.data.cachedDbs else " ") - elif kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: + elif getIdentifiedDBMS() == DBMS.MYSQL and not kb.data.has_information_schema: query = rootQuery.blind.query2 % index else: query = rootQuery.blind.query % index @@ -726,13 +727,13 @@ class Enumeration: self.forceDbmsEnum() - if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: + if getIdentifiedDBMS() == 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 kb.dbms == DBMS.ACCESS: + elif getIdentifiedDBMS() == DBMS.ACCESS: errMsg = "cannot retrieve table names, " errMsg += "back-end DBMS is Access" logger.error(errMsg) @@ -771,7 +772,7 @@ class Enumeration: infoMsg += " for database '%s'" % conf.db logger.info(infoMsg) - rootQuery = queries[kb.dbms].tables + rootQuery = queries[getIdentifiedDBMS()].tables if conf.db: if "," in conf.db: @@ -789,7 +790,7 @@ class Enumeration: condition = rootQuery.inband.condition if 'condition' in rootQuery.inband else None if condition: - if conf.db and kb.dbms != DBMS.SQLITE: + if conf.db and getIdentifiedDBMS() != DBMS.SQLITE: if "," in conf.db: dbs = conf.db.split(",") query += " WHERE " @@ -802,12 +803,12 @@ class Enumeration: infoMsg = "skipping system databases '%s'" % ", ".join(db for db in self.excludeDbsList) logger.info(infoMsg) - if kb.dbms in (DBMS.MSSQL, DBMS.SYBASE): + if getIdentifiedDBMS() in (DBMS.MSSQL, DBMS.SYBASE): query = safeStringFormat(query, conf.db) value = inject.getValue(query, blind=False, error=False) if value: - if kb.dbms == DBMS.SQLITE: + if getIdentifiedDBMS() == DBMS.SQLITE: if isinstance(value, basestring): value = [[ DBMS.SQLITE, value ]] elif isinstance(value, (list, tuple, set)): @@ -836,7 +837,7 @@ class Enumeration: infoMsg += "database '%s'" % db logger.info(infoMsg) - if kb.dbms in (DBMS.SQLITE, DBMS.FIREBIRD, DBMS.MAXDB): + if getIdentifiedDBMS() in (DBMS.SQLITE, DBMS.FIREBIRD, DBMS.MAXDB): query = rootQuery.blind.count else: query = rootQuery.blind.count % db @@ -850,18 +851,18 @@ class Enumeration: tables = [] - if kb.dbms in ( DBMS.MSSQL, DBMS.ORACLE ): + if getIdentifiedDBMS() in ( DBMS.MSSQL, DBMS.ORACLE ): plusOne = True else: plusOne = False indexRange = getRange(count, plusOne=plusOne) for index in indexRange: - if kb.dbms == DBMS.SYBASE: + if getIdentifiedDBMS() == DBMS.SYBASE: query = rootQuery.blind.query % (db, (kb.data.cachedTables[-1] if kb.data.cachedTables else " ")) - elif kb.dbms == DBMS.MAXDB: + elif getIdentifiedDBMS() == DBMS.MAXDB: query = rootQuery.blind.query % (kb.data.cachedTables[-1] if kb.data.cachedTables else " ") - elif kb.dbms in (DBMS.SQLITE, DBMS.FIREBIRD): + elif getIdentifiedDBMS() in (DBMS.SQLITE, DBMS.FIREBIRD): query = rootQuery.blind.query % index else: query = rootQuery.blind.query % (db, index) @@ -902,13 +903,13 @@ class Enumeration: conf.db = self.getCurrentDb() - if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: + if getIdentifiedDBMS() == 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 kb.dbms == DBMS.ACCESS: + elif getIdentifiedDBMS() == DBMS.ACCESS: errMsg = "cannot retrieve column names, " errMsg += "back-end DBMS is Access" logger.error(errMsg) @@ -959,13 +960,13 @@ class Enumeration: "37":"VARCHAR" } - rootQuery = queries[kb.dbms].columns + rootQuery = queries[getIdentifiedDBMS()].columns condition = rootQuery.blind.condition if 'condition' in rootQuery.blind else None infoMsg = "fetching columns " if conf.col: - if kb.dbms == DBMS.ORACLE: + if getIdentifiedDBMS() == DBMS.ORACLE: conf.col = conf.col.upper() colList = conf.col.split(",") condQuery = " AND (" + " OR ".join("%s LIKE '%s'" % (condition, "%" + col + "%") for col in colList) + ")" @@ -978,24 +979,24 @@ class Enumeration: logger.info(infoMsg) if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: - if kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL ): + if getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.PGSQL ): query = rootQuery.inband.query % (conf.tbl, conf.db) query += condQuery - elif kb.dbms == DBMS.ORACLE: + elif getIdentifiedDBMS() == DBMS.ORACLE: query = rootQuery.inband.query % conf.tbl.upper() query += condQuery - elif kb.dbms == DBMS.MSSQL: + elif getIdentifiedDBMS() == DBMS.MSSQL: query = rootQuery.inband.query % (conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, conf.tbl) query += condQuery.replace("[DB]", conf.db) - elif kb.dbms == DBMS.SQLITE: + elif getIdentifiedDBMS() == DBMS.SQLITE: query = rootQuery.inband.query % conf.tbl value = inject.getValue(query, blind=False, error=False) - if kb.dbms == DBMS.SQLITE: + if getIdentifiedDBMS() == DBMS.SQLITE: parseSqliteTableSchema(value) elif value: table = {} @@ -1013,19 +1014,19 @@ class Enumeration: infoMsg += " on database '%s'" % conf.db logger.info(infoMsg) - if kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL ): + if getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.PGSQL ): query = rootQuery.blind.count % (conf.tbl, conf.db) query += condQuery - elif kb.dbms == DBMS.ORACLE: + elif getIdentifiedDBMS() == DBMS.ORACLE: query = rootQuery.blind.count % conf.tbl.upper() query += condQuery - elif kb.dbms == DBMS.MSSQL: + elif getIdentifiedDBMS() == DBMS.MSSQL: query = rootQuery.blind.count % (conf.db, conf.db, conf.tbl) query += condQuery.replace("[DB]", conf.db) - elif kb.dbms == DBMS.FIREBIRD: + elif getIdentifiedDBMS() == DBMS.FIREBIRD: query = rootQuery.blind.count % (conf.tbl) query += condQuery - elif kb.dbms == DBMS.SQLITE: + elif getIdentifiedDBMS() == DBMS.SQLITE: query = rootQuery.blind.query % conf.tbl value = inject.getValue(query, inband=False) @@ -1047,22 +1048,22 @@ class Enumeration: indexRange = getRange(count) for index in indexRange: - if kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL ): + if getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.PGSQL ): query = rootQuery.blind.query % (conf.tbl, conf.db) query += condQuery field = None - elif kb.dbms == DBMS.ORACLE: + elif getIdentifiedDBMS() == DBMS.ORACLE: query = rootQuery.blind.query % (conf.tbl.upper()) query += condQuery field = None - elif kb.dbms == DBMS.MSSQL: + elif getIdentifiedDBMS() == DBMS.MSSQL: query = rootQuery.blind.query % (conf.db, conf.db, conf.db, conf.db, conf.db, conf.db, conf.tbl) query += condQuery.replace("[DB]", conf.db) field = condition.replace("[DB]", conf.db) - elif kb.dbms == DBMS.FIREBIRD: + elif getIdentifiedDBMS() == DBMS.FIREBIRD: query = rootQuery.blind.query % (conf.tbl) query += condQuery field = None @@ -1071,20 +1072,20 @@ class Enumeration: column = inject.getValue(query, inband=False) if not onlyColNames: - if kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL ): + if getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.PGSQL ): query = rootQuery.blind.query2 % (conf.tbl, column, conf.db) - elif kb.dbms == DBMS.ORACLE: + elif getIdentifiedDBMS() == DBMS.ORACLE: query = rootQuery.blind.query2 % (conf.tbl.upper(), column) - elif kb.dbms == DBMS.MSSQL: + elif getIdentifiedDBMS() == DBMS.MSSQL: query = rootQuery.blind.query2 % (conf.db, conf.db, conf.db, conf.db, column, conf.db, conf.db, conf.db, conf.tbl) - elif kb.dbms == DBMS.FIREBIRD: + elif getIdentifiedDBMS() == DBMS.FIREBIRD: query = rootQuery.blind.query2 % (conf.tbl, column) colType = inject.getValue(query, inband=False) - if kb.dbms == DBMS.FIREBIRD: + if getIdentifiedDBMS() == DBMS.FIREBIRD: colType = firebirdTypes[colType] if colType in firebirdTypes else colType columns[column] = colType @@ -1130,9 +1131,9 @@ class Enumeration: conf.db = self.getCurrentDb() - rootQuery = queries[kb.dbms].dump_table + rootQuery = queries[getIdentifiedDBMS()].dump_table - if kb.dbms == DBMS.MYSQL: + if getIdentifiedDBMS() == DBMS.MYSQL: if '-' in conf.tbl: conf.tbl = "`%s`" % conf.tbl if '-' in conf.db: @@ -1175,9 +1176,9 @@ class Enumeration: entriesCount = 0 if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: - if kb.dbms == DBMS.ORACLE: + if getIdentifiedDBMS() == DBMS.ORACLE: query = rootQuery.inband.query % (colString, conf.tbl.upper()) - elif kb.dbms == DBMS.SQLITE: + elif getIdentifiedDBMS() == DBMS.SQLITE: query = rootQuery.inband.query % (colString, conf.tbl) else: query = rootQuery.inband.query % (colString, conf.db, conf.tbl) @@ -1223,9 +1224,9 @@ class Enumeration: infoMsg += "on database '%s'" % conf.db logger.info(infoMsg) - if kb.dbms == DBMS.ORACLE: + if getIdentifiedDBMS() == DBMS.ORACLE: query = rootQuery.blind.count % conf.tbl.upper() - elif kb.dbms in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD): + elif getIdentifiedDBMS() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.FIREBIRD): query = rootQuery.blind.count % conf.tbl else: query = rootQuery.blind.count % (conf.db, conf.tbl) @@ -1245,14 +1246,14 @@ class Enumeration: lengths = {} entries = {} - if kb.dbms in (DBMS.ORACLE, DBMS.MSSQL, DBMS.SYBASE): + if getIdentifiedDBMS() in (DBMS.ORACLE, DBMS.MSSQL, DBMS.SYBASE): plusOne = True else: plusOne = False indexRange = getRange(count, dump=True, plusOne=plusOne) try: - if kb.dbms == DBMS.ACCESS: + if getIdentifiedDBMS() == DBMS.ACCESS: validColumnList = False validPivotValue = False @@ -1329,22 +1330,22 @@ class Enumeration: if column not in entries: entries[column] = [] - if kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL ): + if getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.PGSQL ): query = rootQuery.blind.query % (column, conf.db, conf.tbl, index) - elif kb.dbms == DBMS.ORACLE: + elif getIdentifiedDBMS() == DBMS.ORACLE: query = rootQuery.blind.query % (column, column, conf.tbl.upper(), index) - elif kb.dbms in (DBMS.MSSQL, DBMS.SYBASE): + elif getIdentifiedDBMS() in (DBMS.MSSQL, DBMS.SYBASE): query = rootQuery.blind.query % (column, index, conf.db, conf.tbl, colList[0], colList[0], colList[0]) - elif kb.dbms == DBMS.SQLITE: + elif getIdentifiedDBMS() == DBMS.SQLITE: query = rootQuery.blind.query % (column, conf.tbl, index) - elif kb.dbms == DBMS.FIREBIRD: + elif getIdentifiedDBMS() == DBMS.FIREBIRD: query = rootQuery.blind.query % (index, column, conf.tbl) value = inject.getValue(query, inband=False) @@ -1388,7 +1389,7 @@ class Enumeration: return kb.data.dumpedTable def dumpAll(self): - if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: + if getIdentifiedDBMS() == DBMS.MYSQL and not kb.data.has_information_schema: errMsg = "information_schema not available, " errMsg += "back-end DBMS is MySQL < 5.0" raise sqlmapUnsupportedFeatureException, errMsg @@ -1489,10 +1490,10 @@ class Enumeration: def searchDb(self): foundDbs = [] - rootQuery = queries[kb.dbms].search_db + rootQuery = queries[getIdentifiedDBMS()].search_db dbList = conf.db.split(",") - if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: + if getIdentifiedDBMS() == DBMS.MYSQL and not kb.data.has_information_schema: dbCond = rootQuery.inband.condition2 else: dbCond = rootQuery.inband.condition @@ -1517,7 +1518,7 @@ class Enumeration: dbQuery = dbQuery % db if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: - if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: + if getIdentifiedDBMS() == DBMS.MYSQL and not kb.data.has_information_schema: query = rootQuery.inband.query2 else: query = rootQuery.inband.query @@ -1538,7 +1539,7 @@ class Enumeration: infoMsg += " '%s'" % db logger.info(infoMsg) - if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: + if getIdentifiedDBMS() == DBMS.MYSQL and not kb.data.has_information_schema: query = rootQuery.blind.count2 else: query = rootQuery.blind.count @@ -1558,7 +1559,7 @@ class Enumeration: indexRange = getRange(count) for index in indexRange: - if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: + if getIdentifiedDBMS() == DBMS.MYSQL and not kb.data.has_information_schema: query = rootQuery.blind.query2 else: query = rootQuery.blind.query @@ -1573,12 +1574,12 @@ class Enumeration: def searchTable(self): bruteForce = False - if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: + if getIdentifiedDBMS() == DBMS.MYSQL and not kb.data.has_information_schema: errMsg = "information_schema not available, " errMsg += "back-end DBMS is MySQL < 5.0" bruteForce = True - elif kb.dbms == DBMS.ACCESS: + elif getIdentifiedDBMS() == DBMS.ACCESS: errMsg = "cannot retrieve table names, " errMsg += "back-end DBMS is Access" logger.error(errMsg) @@ -1596,7 +1597,7 @@ class Enumeration: regex = "|".join(conf.tbl.split(",")) return tableExists(paths.COMMON_TABLES, regex) - rootQuery = queries[kb.dbms].search_table + rootQuery = queries[getIdentifiedDBMS()].search_table foundTbls = {} tblList = conf.tbl.split(",") tblCond = rootQuery.inband.condition @@ -1605,7 +1606,7 @@ class Enumeration: tblConsider, tblCondParam = self.likeOrExact("table") for tbl in tblList: - if kb.dbms == DBMS.ORACLE: + if getIdentifiedDBMS() == DBMS.ORACLE: tbl = tbl.upper() infoMsg = "searching table" @@ -1715,12 +1716,12 @@ class Enumeration: def searchColumn(self): bruteForce = False - if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: + if getIdentifiedDBMS() == DBMS.MYSQL and not kb.data.has_information_schema: errMsg = "information_schema not available, " errMsg += "back-end DBMS is MySQL < 5.0" bruteForce = True - elif kb.dbms == DBMS.ACCESS: + elif getIdentifiedDBMS() == DBMS.ACCESS: errMsg = "cannot retrieve column names, " errMsg += "back-end DBMS is Access" logger.error(errMsg) @@ -1746,7 +1747,7 @@ class Enumeration: return - rootQuery = queries[kb.dbms].search_column + rootQuery = queries[getIdentifiedDBMS()].search_column foundCols = {} dbs = {} colList = conf.col.split(",") @@ -1958,7 +1959,7 @@ class Enumeration: return output def sqlShell(self): - infoMsg = "calling %s shell. To quit type " % kb.dbms + infoMsg = "calling %s shell. To quit type " % getIdentifiedDBMS() infoMsg += "'x' or 'q' and press ENTER" logger.info(infoMsg) diff --git a/plugins/generic/filesystem.py b/plugins/generic/filesystem.py index 3ca7deb8c..5e5433554 100644 --- a/plugins/generic/filesystem.py +++ b/plugins/generic/filesystem.py @@ -13,6 +13,7 @@ import os from lib.core.agent import agent from lib.core.common import dataToOutFile +from lib.core.common import getIdentifiedDBMS from lib.core.common import isTechniqueAvailable from lib.core.common import randomStr from lib.core.common import readInput @@ -86,13 +87,13 @@ class Filesystem: return fileLines def __checkWrittenFile(self, wFile, dFile, fileType): - if kb.dbms == DBMS.MYSQL: + if getIdentifiedDBMS() == DBMS.MYSQL: lengthQuery = "SELECT LENGTH(LOAD_FILE('%s'))" % dFile - elif kb.dbms == DBMS.PGSQL: + elif getIdentifiedDBMS() == DBMS.PGSQL: lengthQuery = "SELECT LENGTH(data) FROM pg_largeobject WHERE loid=%d" % self.oid - elif kb.dbms == DBMS.MSSQL: + elif getIdentifiedDBMS() == DBMS.MSSQL: self.createSupportTbl(self.fileTblName, self.tblField, "text") # Reference: http://msdn.microsoft.com/en-us/library/ms188365.aspx @@ -270,7 +271,7 @@ class Filesystem: fileContent = self.unionReadFile(rFile) - if fileContent in ( None, "" ) and kb.dbms != "PostgreSQL": + if fileContent in ( None, "" ) and getIdentifiedDBMS() != DBMS.PGSQL: self.cleanup(onlyFileTbl=True) return @@ -288,7 +289,7 @@ class Filesystem: fileContent = self.__unhexString(fileContent) rFilePath = dataToOutFile(fileContent) - if kb.dbms != "PostgreSQL": + if getIdentifiedDBMS() != DBMS.PGSQL: self.cleanup(onlyFileTbl=True) return rFilePath diff --git a/plugins/generic/misc.py b/plugins/generic/misc.py index c1223ab80..3f3cad92c 100644 --- a/plugins/generic/misc.py +++ b/plugins/generic/misc.py @@ -10,6 +10,7 @@ See the file 'doc/COPYING' for copying permission import re from lib.core.common import getCompiledRegex +from lib.core.common import getIdentifiedDBMS from lib.core.common import isTechniqueAvailable from lib.core.common import normalizePath from lib.core.common import ntToPosixSlashes @@ -56,19 +57,19 @@ class Miscellaneous: infoMsg = "detecting back-end DBMS version from its banner" logger.info(infoMsg) - if kb.dbms == DBMS.MYSQL: + if getIdentifiedDBMS() == DBMS.MYSQL: first, last = 1, 6 - elif kb.dbms == DBMS.PGSQL: + elif getIdentifiedDBMS() == DBMS.PGSQL: first, last = 12, 6 - elif kb.dbms == DBMS.MSSQL: + elif getIdentifiedDBMS() == DBMS.MSSQL: first, last = 29, 9 else: raise sqlmapUnsupportedFeatureException, "unsupported DBMS" - query = queries[kb.dbms].substring.query % (queries[kb.dbms].banner.query, first, last) + query = queries[getIdentifiedDBMS()].substring.query % (queries[getIdentifiedDBMS()].banner.query, first, last) if conf.direct: query = "SELECT %s" % query @@ -119,7 +120,7 @@ class Miscellaneous: if not onlyFileTbl: inject.goStacked("DROP TABLE %s" % self.cmdTblName, silent=True) - if kb.dbms == DBMS.MSSQL: + if getIdentifiedDBMS() == DBMS.MSSQL: return if udfDict is None: @@ -132,7 +133,7 @@ class Miscellaneous: if not output or output in ("y", "Y"): dropStr = "DROP FUNCTION %s" % udf - if kb.dbms == DBMS.PGSQL: + if getIdentifiedDBMS() == DBMS.PGSQL: inp = ", ".join(i for i in inpRet["input"]) dropStr += "(%s)" % inp diff --git a/plugins/generic/takeover.py b/plugins/generic/takeover.py index b9ed105d6..0986bd08a 100644 --- a/plugins/generic/takeover.py +++ b/plugins/generic/takeover.py @@ -9,6 +9,7 @@ See the file 'doc/COPYING' for copying permission import os +from lib.core.common import getIdentifiedDBMS from lib.core.common import isTechniqueAvailable from lib.core.common import readInput from lib.core.common import runningAsAdmin @@ -44,7 +45,7 @@ class Takeover(Abstraction, Metasploit, ICMPsh, Registry, Miscellaneous): def osCmd(self): if isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) or conf.direct: web = False - elif not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) and kb.dbms == DBMS.MYSQL: + elif not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) and getIdentifiedDBMS() == DBMS.MYSQL: infoMsg = "going to use a web backdoor for command execution" logger.info(infoMsg) @@ -65,7 +66,7 @@ class Takeover(Abstraction, Metasploit, ICMPsh, Registry, Miscellaneous): def osShell(self): if isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) or conf.direct: web = False - elif not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) and kb.dbms == DBMS.MYSQL: + elif not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) and getIdentifiedDBMS() == DBMS.MYSQL: infoMsg = "going to use a web backdoor for command prompt" logger.info(infoMsg) @@ -148,7 +149,7 @@ class Takeover(Abstraction, Metasploit, ICMPsh, Registry, Miscellaneous): errMsg += "is unlikely to receive commands send from you" logger.error(errMsg) - if kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL ): + if getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.PGSQL ): self.sysUdfs.pop("sys_bineval") if isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) or conf.direct: @@ -158,7 +159,7 @@ class Takeover(Abstraction, Metasploit, ICMPsh, Registry, Miscellaneous): self.initEnv(web=web) if tunnel == 1: - if kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL ): + if getIdentifiedDBMS() in ( DBMS.MYSQL, DBMS.PGSQL ): msg = "how do you want to execute the Metasploit shellcode " msg += "on the back-end database underlying operating system?" msg += "\n[1] Via UDF 'sys_bineval' (in-memory way, anti-forensics, default)" @@ -188,7 +189,7 @@ class Takeover(Abstraction, Metasploit, ICMPsh, Registry, Miscellaneous): self.uploadMsfPayloadStager() if kb.os == "Windows" and conf.privEsc: - if kb.dbms == DBMS.MYSQL: + if getIdentifiedDBMS() == DBMS.MYSQL: debugMsg = "by default MySQL on Windows runs as SYSTEM " debugMsg += "user, no need to privilege escalate" logger.debug(debugMsg) @@ -206,7 +207,7 @@ class Takeover(Abstraction, Metasploit, ICMPsh, Registry, Miscellaneous): self.uploadIcmpshSlave(web=web) self.icmpPwn() - elif not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) and kb.dbms == DBMS.MYSQL: + elif not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) and getIdentifiedDBMS() == DBMS.MYSQL: web = True infoMsg = "going to use a web backdoor to establish the tunnel" @@ -255,13 +256,13 @@ class Takeover(Abstraction, Metasploit, ICMPsh, Registry, Miscellaneous): raise sqlmapUnsupportedDBMSException(errMsg) if not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) and not conf.direct: - if kb.dbms in ( DBMS.PGSQL, DBMS.MSSQL ): + if getIdentifiedDBMS() in ( DBMS.PGSQL, DBMS.MSSQL ): errMsg = "on this back-end DBMS it is only possible to " errMsg += "perform the SMB relay attack if stacked " errMsg += "queries are supported" raise sqlmapUnsupportedDBMSException(errMsg) - elif kb.dbms == DBMS.MYSQL: + elif getIdentifiedDBMS() == DBMS.MYSQL: debugMsg = "since stacked queries are not supported, " debugMsg += "sqlmap is going to perform the SMB relay " debugMsg += "attack via inference blind SQL injection" @@ -270,18 +271,18 @@ class Takeover(Abstraction, Metasploit, ICMPsh, Registry, Miscellaneous): printWarn = True warnMsg = "it is unlikely that this attack will be successful " - if kb.dbms == DBMS.MYSQL: + if getIdentifiedDBMS() == DBMS.MYSQL: warnMsg += "because by default MySQL on Windows runs as " warnMsg += "Local System which is not a real user, it does " warnMsg += "not send the NTLM session hash when connecting to " warnMsg += "a SMB service" - elif kb.dbms == DBMS.PGSQL: + elif getIdentifiedDBMS() == DBMS.PGSQL: warnMsg += "because by default PostgreSQL on Windows runs " warnMsg += "as postgres user which is a real user of the " warnMsg += "system, but not within the Administrators group" - elif kb.dbms == DBMS.MSSQL and kb.dbmsVersion[0] in ( "2005", "2008" ): + elif getIdentifiedDBMS() == DBMS.MSSQL and kb.dbmsVersion[0] in ( "2005", "2008" ): warnMsg += "because often Microsoft SQL Server %s " % kb.dbmsVersion[0] warnMsg += "runs as Network Service which is not a real user, " warnMsg += "it does not send the NTLM session hash when " @@ -299,7 +300,7 @@ class Takeover(Abstraction, Metasploit, ICMPsh, Registry, Miscellaneous): if not isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED) and not conf.direct: return - if not kb.dbms == DBMS.MSSQL or kb.dbmsVersion[0] not in ( "2000", "2005" ): + if not getIdentifiedDBMS() == DBMS.MSSQL or kb.dbmsVersion[0] not in ( "2000", "2005" ): errMsg = "the back-end DBMS must be Microsoft SQL Server " errMsg += "2000 or 2005 to be able to exploit the heap-based " errMsg += "buffer overflow in the 'sp_replwritetovarbin' "