diff --git a/lib/core/common.py b/lib/core/common.py index 753d19899..0b50d8fd3 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1189,7 +1189,7 @@ def getLimitRange(count, dump=False, plusOne=False): return retVal -def parseUnionPage(page, unique=True): +def parseUnionPage(page): """ Returns resulting items from inband query inside provided page content """ @@ -1211,7 +1211,7 @@ def parseUnionPage(page, unique=True): if kb.chars.start in entry: entry = entry.split(kb.chars.start)[-1] - if unique: + if kb.unionDuplicates: key = entry.lower() if key not in _: _.append(key) diff --git a/lib/core/option.py b/lib/core/option.py index c9a5fd92e..b6863c787 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -1512,6 +1512,7 @@ def __setKnowledgeBaseAttributes(flushAll=True): kb.threadException = False kb.timeValidCharsRun = 0 kb.uChar = NULL + kb.unionDuplicates = False kb.xpCmdshellAvailable = False kb.chars = AttribDict() diff --git a/lib/core/settings.py b/lib/core/settings.py index 862eea66b..dc466d23d 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -456,7 +456,7 @@ DEFAULT_COOKIE_DELIMITER = ';' HASHDB_FLUSH_THRESHOLD = 32 # Unique milestone value used for forced deprecation of old HashDB values (e.g. when changing hash/pickle mechanism) -HASHDB_MILESTONE_VALUE = "EfjamfhMVw" # r4856 +HASHDB_MILESTONE_VALUE = "ZTuyinSUvN" # r5125 "".join(random.sample(string.letters, 10)) # Warn user of possible delay due to large page dump in full UNION query injections LARGE_OUTPUT_THRESHOLD = 1024**2 diff --git a/lib/request/inject.py b/lib/request/inject.py index 057f9e61b..e1842896a 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -356,7 +356,7 @@ def __goError(expression, expected=None, dump=False): return output -def __goInband(expression, expected=None, unique=True, unpack=True, dump=False): +def __goInband(expression, expected=None, unpack=True, dump=False): """ Retrieve the output of a SQL query taking advantage of an inband SQL injection vulnerability on the affected parameter. @@ -364,11 +364,11 @@ def __goInband(expression, expected=None, unique=True, unpack=True, dump=False): output = unionUse(expression, unpack=unpack, dump=dump) if isinstance(output, basestring): - output = parseUnionPage(output, unique) + output = parseUnionPage(output) return output -def getValue(expression, blind=True, inband=True, error=True, time=True, fromUser=False, expected=None, batch=False, unpack=True, unique=True, resumeValue=True, charsetType=None, firstChar=None, lastChar=None, dump=False, suppressOutput=None, expectingNone=False, safeCharEncode=True): +def getValue(expression, blind=True, inband=True, error=True, time=True, fromUser=False, expected=None, batch=False, unpack=True, resumeValue=True, charsetType=None, firstChar=None, lastChar=None, dump=False, suppressOutput=None, expectingNone=False, safeCharEncode=True): """ Called each time sqlmap inject a SQL query on the SQL injection affected parameter. It can call a function to retrieve the output @@ -413,9 +413,9 @@ def getValue(expression, blind=True, inband=True, error=True, time=True, fromUse kb.technique = PAYLOAD.TECHNIQUE.UNION if expected == EXPECTED.BOOL: - value = __goInband(forgeCaseExpression, expected, unique, unpack, dump) + value = __goInband(forgeCaseExpression, expected, unpack, dump) else: - value = __goInband(query, expected, unique, unpack, dump) + value = __goInband(query, expected, unpack, dump) count += 1 found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE diff --git a/lib/takeover/xp_cmdshell.py b/lib/takeover/xp_cmdshell.py index 7a1544137..41dea0ea7 100644 --- a/lib/takeover/xp_cmdshell.py +++ b/lib/takeover/xp_cmdshell.py @@ -188,7 +188,7 @@ class xp_cmdshell: self.delRemoteFile(tmpFile) - output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False, unique=False, firstChar=first, lastChar=last, safeCharEncode=False) + output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False, firstChar=first, lastChar=last, safeCharEncode=False) inject.goStacked("DELETE FROM %s" % self.cmdTblName) if output and isinstance(output, (list, tuple)): diff --git a/lib/techniques/union/test.py b/lib/techniques/union/test.py index 111276db4..4982563de 100644 --- a/lib/techniques/union/test.py +++ b/lib/techniques/union/test.py @@ -186,7 +186,7 @@ def __unionPosition(comment, place, parameter, prefix, suffix, count, where=PAYL if content and phrase in content: validPayload = payload - vector = (position, count, comment, prefix, suffix, kb.uChar, where) + vector = (position, count, comment, prefix, suffix, kb.uChar, where, content.count(phrase) > 1) if where == PAYLOAD.WHERE.ORIGINAL: # Prepare expression with delimiters diff --git a/lib/techniques/union/use.py b/lib/techniques/union/use.py index b376bf547..67350701c 100644 --- a/lib/techniques/union/use.py +++ b/lib/techniques/union/use.py @@ -66,6 +66,7 @@ def __oneShotUnionUse(expression, unpack=True, limited=False): # Forge the inband SQL injection request vector = kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector + kb.unionDuplicates = vector[7] query = agent.forgeInbandQuery(injExpression, vector[0], vector[1], vector[2], vector[3], vector[4], vector[5], vector[6], None, limited) payload = agent.payload(newValue=query, where=where) diff --git a/plugins/dbms/mssqlserver/filesystem.py b/plugins/dbms/mssqlserver/filesystem.py index da2c29f2c..c88a03032 100644 --- a/plugins/dbms/mssqlserver/filesystem.py +++ b/plugins/dbms/mssqlserver/filesystem.py @@ -145,7 +145,7 @@ class Filesystem(GenericFilesystem): inject.goStacked(binToHexQuery) if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION): - result = inject.getValue("SELECT %s FROM %s ORDER BY id ASC" % (self.tblField, hexTbl), unique=False, resumeValue=False, blind=False, error=False) + result = inject.getValue("SELECT %s FROM %s ORDER BY id ASC" % (self.tblField, hexTbl), resumeValue=False, blind=False, error=False) if not result: result = [] @@ -159,7 +159,7 @@ class Filesystem(GenericFilesystem): indexRange = getLimitRange(count) for index in indexRange: - chunk = inject.getValue("SELECT TOP 1 %s FROM %s WHERE %s NOT IN (SELECT TOP %d %s FROM %s ORDER BY id ASC) ORDER BY id ASC" % (self.tblField, hexTbl, self.tblField, index, self.tblField, hexTbl), unpack=False, resumeValue=False, unique=False, charsetType=CHARSET_TYPE.HEXADECIMAL) + chunk = inject.getValue("SELECT TOP 1 %s FROM %s WHERE %s NOT IN (SELECT TOP %d %s FROM %s ORDER BY id ASC) ORDER BY id ASC" % (self.tblField, hexTbl, self.tblField, index, self.tblField, hexTbl), unpack=False, resumeValue=False, charsetType=CHARSET_TYPE.HEXADECIMAL) result.append(chunk) inject.goStacked("DROP TABLE %s" % hexTbl) diff --git a/plugins/dbms/mysql/filesystem.py b/plugins/dbms/mysql/filesystem.py index 2afb428cc..0130e8560 100644 --- a/plugins/dbms/mysql/filesystem.py +++ b/plugins/dbms/mysql/filesystem.py @@ -54,7 +54,7 @@ class Filesystem(GenericFilesystem): logger.debug(debugMsg) inject.goStacked("LOAD DATA INFILE '%s' INTO TABLE %s FIELDS TERMINATED BY '%s' (%s)" % (tmpFile, self.fileTblName, randomStr(10), self.tblField)) - length = inject.getValue("SELECT LENGTH(%s) FROM %s" % (self.tblField, self.fileTblName), unique=False, resumeValue=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) + length = inject.getValue("SELECT LENGTH(%s) FROM %s" % (self.tblField, self.fileTblName), resumeValue=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if not isNumPosStrValue(length): warnMsg = "unable to retrieve the content of the " @@ -74,11 +74,11 @@ class Filesystem(GenericFilesystem): result = [] for i in xrange(1, length, sustrLen): - chunk = inject.getValue("SELECT MID(%s, %d, %d) FROM %s" % (self.tblField, i, sustrLen, self.fileTblName), unpack=False, unique=False, resumeValue=False, charsetType=CHARSET_TYPE.HEXADECIMAL) + chunk = inject.getValue("SELECT MID(%s, %d, %d) FROM %s" % (self.tblField, i, sustrLen, self.fileTblName), unpack=False, resumeValue=False, charsetType=CHARSET_TYPE.HEXADECIMAL) result.append(chunk) else: - result = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.fileTblName), unique=False, resumeValue=False, charsetType=CHARSET_TYPE.HEXADECIMAL) + result = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.fileTblName), resumeValue=False, charsetType=CHARSET_TYPE.HEXADECIMAL) return result diff --git a/plugins/generic/enumeration.py b/plugins/generic/enumeration.py index a6ed5c817..195d8b12f 100644 --- a/plugins/generic/enumeration.py +++ b/plugins/generic/enumeration.py @@ -1611,9 +1611,8 @@ class Enumeration: entries = [] entriesCount = len(entries) - index = 0 - for column in colList: + for index, column in enumerate(colList): colLen = len(column) if column not in kb.data.dumpedTable: @@ -1626,7 +1625,7 @@ class Enumeration: if isinstance(entry, basestring): colEntry = entry else: - colEntry = entry[index] if index < len(entry) else u'' + colEntry = unArrayizeValue(entry[index]) if index < len(entry) else u'' colEntryLen = len({" ": NULL, "": BLANK}.get(getUnicode(colEntry), getUnicode(colEntry))) maxLen = max(colLen, colEntryLen) @@ -1636,8 +1635,6 @@ class Enumeration: kb.data.dumpedTable[column]["values"].append(colEntry) - index += 1 - if not kb.data.dumpedTable and isInferenceAvailable() and not conf.direct: infoMsg = "fetching number of " if conf.col: