From 06be7bbb18d59678fb49dea0ed5ca7b3727a0df9 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 15 Jun 2012 20:41:53 +0000 Subject: [PATCH] few just in case fixes (unarrayizeValue in dumpTable entries) and and some refactoring (unique is now not done for every union case but only if detected that there are duplicates in union test) --- lib/core/common.py | 4 ++-- lib/core/option.py | 1 + lib/core/settings.py | 2 +- lib/request/inject.py | 10 +++++----- lib/takeover/xp_cmdshell.py | 2 +- lib/techniques/union/test.py | 2 +- lib/techniques/union/use.py | 1 + plugins/dbms/mssqlserver/filesystem.py | 4 ++-- plugins/dbms/mysql/filesystem.py | 6 +++--- plugins/generic/enumeration.py | 7 ++----- 10 files changed, 19 insertions(+), 20 deletions(-) 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: