From 206191d16489db04cfadfe02e8cd02918545be41 Mon Sep 17 00:00:00 2001 From: Bernardo Damele Date: Sun, 2 Nov 2008 19:21:19 +0000 Subject: [PATCH] Major bug fix so that when the expected value of a query (count variable) is an integer and for some reason the resumed value from session file is a string or a binary file, the query is executed again and and its new output saved to the session file --- lib/request/inject.py | 29 +++++++++++++++++------------ plugins/generic/enumeration.py | 28 ++++++++++++++-------------- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/lib/request/inject.py b/lib/request/inject.py index 380bcc7c0..c520353ed 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -71,7 +71,7 @@ def __goInference(payload, expression): return value -def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload): +def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected=None): outputs = [] for field in expressionFieldsList: @@ -80,7 +80,12 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl expressionReplaced = expression.replace(expressionFields, field, 1) output = resume(expressionReplaced, payload) - if not output: + if not output or ( expected == "int" and not output.isdigit() ): + if output: + warnMsg = "expected value type %s, resumed '%s', " % (expected, output) + warnMsg += "sqlmap is going to retrieve the value again" + logger.warn(warnMsg) + output = __goInference(payload, expressionReplaced) outputs.append(output) @@ -88,7 +93,7 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl return outputs -def __goInferenceProxy(expression, fromUser=False): +def __goInferenceProxy(expression, fromUser=False, expected=None): """ Retrieve the output of a SQL query characted by character taking advantage of an blind SQL injection vulnerability on the affected @@ -108,7 +113,7 @@ def __goInferenceProxy(expression, fromUser=False): output = resume(expression, payload) - if output: + if output and ( expected == None or ( expected == "int" and output.isdigit() ) ): return output if kb.dbmsDetected: @@ -179,7 +184,7 @@ def __goInferenceProxy(expression, fromUser=False): count = resume(countedExpression, payload) if not stopLimit: - if not count: + if not count or not count.isdigit(): count = __goInference(payload, countedExpression) if count.isdigit() and int(count) > 0: @@ -268,7 +273,7 @@ def __goInferenceProxy(expression, fromUser=False): limitedExpr += "NOT IN (%s" % (limitStr % num) limitedExpr += "%s %s)" % (expressionFieldsList[0], fromFrom) - output = __goInferenceFields(limitedExpr, expressionFields, expressionFieldsList, payload) + output = __goInferenceFields(limitedExpr, expressionFields, expressionFieldsList, payload, expected) outputs.append(output) return outputs @@ -276,7 +281,7 @@ def __goInferenceProxy(expression, fromUser=False): elif kb.dbms == "Oracle" and expression.startswith("SELECT ") and " FROM " not in expression: expression = "%s FROM DUAL" % expression - outputs = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload) + outputs = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected) returnValue = ", ".join([output for output in outputs]) else: @@ -285,7 +290,7 @@ def __goInferenceProxy(expression, fromUser=False): return returnValue -def __goInband(expression): +def __goInband(expression, expected=None): """ Retrieve the output of a SQL query taking advantage of an inband SQL injection vulnerability on the affected parameter. @@ -304,7 +309,7 @@ def __goInband(expression): if condition: output = resume(expression, None) - if not output: + if not output or ( expected == "int" and not output.isdigit() ): partial = True if not output: @@ -355,7 +360,7 @@ def __goInband(expression): return data -def getValue(expression, blind=True, inband=True, fromUser=False): +def getValue(expression, blind=True, inband=True, fromUser=False, expected=None): """ Called each time sqlmap inject a SQL query on the SQL injection affected parameter. It can call a function to retrieve the output @@ -368,9 +373,9 @@ def getValue(expression, blind=True, inband=True, fromUser=False): value = None if inband and conf.unionUse and kb.dbms: - value = __goInband(expression) + value = __goInband(expression, expected) if blind and not value: - value = __goInferenceProxy(expression, fromUser) + value = __goInferenceProxy(expression, fromUser, expected) return value diff --git a/plugins/generic/enumeration.py b/plugins/generic/enumeration.py index 4c021e8b7..04b7ff0bf 100644 --- a/plugins/generic/enumeration.py +++ b/plugins/generic/enumeration.py @@ -135,9 +135,9 @@ class Enumeration: query = rootQuery["blind"]["count2"] else: query = rootQuery["blind"]["count"] - count = inject.getValue(query, inband=False) + count = inject.getValue(query, inband=False, expected="int") - if not len(count) or count == "0": + if not count.isdigit() or not len(count) or count == "0": errMsg = "unable to retrieve the number of database users" raise sqlmapNoneDataException, errMsg @@ -228,9 +228,9 @@ class Enumeration: query = rootQuery["blind"]["count2"] % user else: query = rootQuery["blind"]["count"] % user - count = inject.getValue(query, inband=False) + count = inject.getValue(query, inband=False, expected="int") - if not len(count) or count == "0": + if not count.isdigit() or not len(count) or count == "0": warnMsg = "unable to retrieve the number of password " warnMsg += "hashes for user '%s'" % user logger.warn(warnMsg) @@ -458,9 +458,9 @@ class Enumeration: query = rootQuery["blind"]["count"] % (conditionChar, queryUser) else: query = rootQuery["blind"]["count"] % queryUser - count = inject.getValue(query, inband=False) + count = inject.getValue(query, inband=False, expected="int") - if not len(count) or count == "0": + if not count.isdigit() or not len(count) or count == "0": warnMsg = "unable to retrieve the number of " warnMsg += "privileges for user '%s'" % user logger.warn(warnMsg) @@ -572,9 +572,9 @@ class Enumeration: query = rootQuery["blind"]["count2"] else: query = rootQuery["blind"]["count"] - count = inject.getValue(query, inband=False) + count = inject.getValue(query, inband=False, expected="int") - if not len(count) or count == "0": + if not count.isdigit() or not len(count) or count == "0": errMsg = "unable to retrieve the number of databases" raise sqlmapNoneDataException, errMsg @@ -662,9 +662,9 @@ class Enumeration: logger.info(logMsg) query = rootQuery["blind"]["count"] % db - count = inject.getValue(query, inband=False) + count = inject.getValue(query, inband=False, expected="int") - if not len(count) or count == "0": + if not count.isdigit() or not len(count) or count == "0": warnMsg = "unable to retrieve the number of " warnMsg += "tables for database '%s'" % db logger.warn(warnMsg) @@ -756,9 +756,9 @@ class Enumeration: elif kb.dbms == "Microsoft SQL Server": query = rootQuery["blind"]["count"] % (conf.db, conf.db, conf.tbl) - count = inject.getValue(query, inband=False) + count = inject.getValue(query, inband=False, expected="int") - if not len(count) or count == "0": + if not count.isdigit() or not len(count) or count == "0": errMsg = "unable to retrieve the number of columns " errMsg += "for table '%s' " % conf.tbl errMsg += "on database '%s'" % conf.db @@ -905,9 +905,9 @@ class Enumeration: query = rootQuery["blind"]["count"] % conf.tbl.upper() else: query = rootQuery["blind"]["count"] % (conf.db, conf.tbl) - count = inject.getValue(query, inband=False) + count = inject.getValue(query, inband=False, expected="int") - if not len(count) or count == "0": + if not count.isdigit() or not len(count) or count == "0": errMsg = "unable to retrieve the number of " if conf.col: errMsg += "columns '%s' " % colString