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
This commit is contained in:
Bernardo Damele 2008-11-02 19:21:19 +00:00
parent 03b90e0a3f
commit 206191d164
2 changed files with 31 additions and 26 deletions

View File

@ -71,7 +71,7 @@ def __goInference(payload, expression):
return value return value
def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload): def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected=None):
outputs = [] outputs = []
for field in expressionFieldsList: for field in expressionFieldsList:
@ -80,7 +80,12 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl
expressionReplaced = expression.replace(expressionFields, field, 1) expressionReplaced = expression.replace(expressionFields, field, 1)
output = resume(expressionReplaced, payload) 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) output = __goInference(payload, expressionReplaced)
outputs.append(output) outputs.append(output)
@ -88,7 +93,7 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl
return outputs 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 Retrieve the output of a SQL query characted by character taking
advantage of an blind SQL injection vulnerability on the affected advantage of an blind SQL injection vulnerability on the affected
@ -108,7 +113,7 @@ def __goInferenceProxy(expression, fromUser=False):
output = resume(expression, payload) output = resume(expression, payload)
if output: if output and ( expected == None or ( expected == "int" and output.isdigit() ) ):
return output return output
if kb.dbmsDetected: if kb.dbmsDetected:
@ -179,7 +184,7 @@ def __goInferenceProxy(expression, fromUser=False):
count = resume(countedExpression, payload) count = resume(countedExpression, payload)
if not stopLimit: if not stopLimit:
if not count: if not count or not count.isdigit():
count = __goInference(payload, countedExpression) count = __goInference(payload, countedExpression)
if count.isdigit() and int(count) > 0: if count.isdigit() and int(count) > 0:
@ -268,7 +273,7 @@ def __goInferenceProxy(expression, fromUser=False):
limitedExpr += "NOT IN (%s" % (limitStr % num) limitedExpr += "NOT IN (%s" % (limitStr % num)
limitedExpr += "%s %s)" % (expressionFieldsList[0], fromFrom) limitedExpr += "%s %s)" % (expressionFieldsList[0], fromFrom)
output = __goInferenceFields(limitedExpr, expressionFields, expressionFieldsList, payload) output = __goInferenceFields(limitedExpr, expressionFields, expressionFieldsList, payload, expected)
outputs.append(output) outputs.append(output)
return outputs return outputs
@ -276,7 +281,7 @@ def __goInferenceProxy(expression, fromUser=False):
elif kb.dbms == "Oracle" and expression.startswith("SELECT ") and " FROM " not in expression: elif kb.dbms == "Oracle" and expression.startswith("SELECT ") and " FROM " not in expression:
expression = "%s FROM DUAL" % 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]) returnValue = ", ".join([output for output in outputs])
else: else:
@ -285,7 +290,7 @@ def __goInferenceProxy(expression, fromUser=False):
return returnValue return returnValue
def __goInband(expression): def __goInband(expression, expected=None):
""" """
Retrieve the output of a SQL query taking advantage of an inband SQL Retrieve the output of a SQL query taking advantage of an inband SQL
injection vulnerability on the affected parameter. injection vulnerability on the affected parameter.
@ -304,7 +309,7 @@ def __goInband(expression):
if condition: if condition:
output = resume(expression, None) output = resume(expression, None)
if not output: if not output or ( expected == "int" and not output.isdigit() ):
partial = True partial = True
if not output: if not output:
@ -355,7 +360,7 @@ def __goInband(expression):
return data 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 Called each time sqlmap inject a SQL query on the SQL injection
affected parameter. It can call a function to retrieve the output 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 value = None
if inband and conf.unionUse and kb.dbms: if inband and conf.unionUse and kb.dbms:
value = __goInband(expression) value = __goInband(expression, expected)
if blind and not value: if blind and not value:
value = __goInferenceProxy(expression, fromUser) value = __goInferenceProxy(expression, fromUser, expected)
return value return value

View File

@ -135,9 +135,9 @@ class Enumeration:
query = rootQuery["blind"]["count2"] query = rootQuery["blind"]["count2"]
else: else:
query = rootQuery["blind"]["count"] 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" errMsg = "unable to retrieve the number of database users"
raise sqlmapNoneDataException, errMsg raise sqlmapNoneDataException, errMsg
@ -228,9 +228,9 @@ class Enumeration:
query = rootQuery["blind"]["count2"] % user query = rootQuery["blind"]["count2"] % user
else: else:
query = rootQuery["blind"]["count"] % user 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 = "unable to retrieve the number of password "
warnMsg += "hashes for user '%s'" % user warnMsg += "hashes for user '%s'" % user
logger.warn(warnMsg) logger.warn(warnMsg)
@ -458,9 +458,9 @@ class Enumeration:
query = rootQuery["blind"]["count"] % (conditionChar, queryUser) query = rootQuery["blind"]["count"] % (conditionChar, queryUser)
else: else:
query = rootQuery["blind"]["count"] % queryUser 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 = "unable to retrieve the number of "
warnMsg += "privileges for user '%s'" % user warnMsg += "privileges for user '%s'" % user
logger.warn(warnMsg) logger.warn(warnMsg)
@ -572,9 +572,9 @@ class Enumeration:
query = rootQuery["blind"]["count2"] query = rootQuery["blind"]["count2"]
else: else:
query = rootQuery["blind"]["count"] 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" errMsg = "unable to retrieve the number of databases"
raise sqlmapNoneDataException, errMsg raise sqlmapNoneDataException, errMsg
@ -662,9 +662,9 @@ class Enumeration:
logger.info(logMsg) logger.info(logMsg)
query = rootQuery["blind"]["count"] % db 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 = "unable to retrieve the number of "
warnMsg += "tables for database '%s'" % db warnMsg += "tables for database '%s'" % db
logger.warn(warnMsg) logger.warn(warnMsg)
@ -756,9 +756,9 @@ class Enumeration:
elif kb.dbms == "Microsoft SQL Server": elif kb.dbms == "Microsoft SQL Server":
query = rootQuery["blind"]["count"] % (conf.db, conf.db, conf.tbl) 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 = "unable to retrieve the number of columns "
errMsg += "for table '%s' " % conf.tbl errMsg += "for table '%s' " % conf.tbl
errMsg += "on database '%s'" % conf.db errMsg += "on database '%s'" % conf.db
@ -905,9 +905,9 @@ class Enumeration:
query = rootQuery["blind"]["count"] % conf.tbl.upper() query = rootQuery["blind"]["count"] % conf.tbl.upper()
else: else:
query = rootQuery["blind"]["count"] % (conf.db, conf.tbl) 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 " errMsg = "unable to retrieve the number of "
if conf.col: if conf.col:
errMsg += "columns '%s' " % colString errMsg += "columns '%s' " % colString