Major bug fix to make partial UNION query sql injection work properly

also on Microsoft SQL Server
This commit is contained in:
Bernardo Damele 2008-12-22 19:36:01 +00:00
parent 064029cb2d
commit 1f7810e46a
3 changed files with 50 additions and 25 deletions

View File

@ -81,6 +81,14 @@ class Agent:
return retValue
def fullPayload(self, query):
query = self.prefixQuery(query)
query = self.postfixQuery(query)
payload = self.payload(newValue=query)
return payload
def prefixQuery(self, string):
"""
This method defines how the input string has to be escaped
@ -396,32 +404,32 @@ class Agent:
inbandQuery += ", "
if element == exprPosition:
if " FROM " in query and not query.startswith("SELECT ") and not "(SELECT " in query:
conditionIndex = query.rindex(" FROM ")
inbandQuery += "%s" % query[:conditionIndex]
if " FROM " in query and not query.startswith("SELECT "):
conditionIndex = query.index(" FROM ")
inbandQuery += query[:conditionIndex]
else:
inbandQuery += "%s" % query
inbandQuery += query
else:
inbandQuery += "NULL"
if " FROM " in query and not query.startswith("SELECT ") and not "(SELECT " in query:
conditionIndex = query.rindex(" FROM ")
inbandQuery += "%s" % query[conditionIndex:]
if " FROM " in query and not query.startswith("SELECT "):
conditionIndex = query.index(" FROM ")
inbandQuery += query[conditionIndex:]
if " ORDER BY " in inbandQuery and "(SELECT " in inbandQuery:
orderIndex = inbandQuery.index(" ORDER BY ")
inbandQuery += inbandQuery[orderIndex:].replace(")", "")
if kb.dbms == "Oracle":
if " FROM " not in inbandQuery:
inbandQuery += " FROM DUAL"
if " ORDER BY " in inbandQuery:
orderIndex = inbandQuery.index(" ORDER BY ")
inbandQuery = inbandQuery[:orderIndex]
inbandQuery = self.postfixQuery(inbandQuery, kb.unionComment)
return inbandQuery
def limitQuery(self, num, query, fieldsList=None):
def limitQuery(self, num, query, field):
"""
Take in input a query string and return its limited query string.
@ -436,8 +444,8 @@ class Agent:
@param query: query to be processed
@type query: C{str}
@param fieldsList: list of fields within the query
@type fieldsList: C{list}
@param field: field within the query
@type field: C{list}
@return: limited query string
@rtype: C{str}
@ -453,13 +461,12 @@ class Agent:
limitStr = queries[kb.dbms].limit % (num, 1)
limitedQuery += " %s" % limitStr
# TODO: fix for Partial UNION query SQL injection technique both
# Oracle and Microsoft SQL Server
# TODO: fix Partial UNION query SQL injection technique for Oracle
elif kb.dbms == "Oracle":
if query.startswith("SELECT "):
limitedQuery = "%s FROM (%s, %s" % (untilFrom, untilFrom, limitStr)
else:
limitedQuery = "%s FROM (SELECT %s, %s" % (untilFrom, ", ".join(field for field in fieldsList), limitStr)
limitedQuery = "%s FROM (SELECT %s, %s" % (untilFrom, field, limitStr)
limitedQuery = limitedQuery % fromFrom
limitedQuery += "=%d" % (num + 1)
@ -469,9 +476,9 @@ class Agent:
limitedQuery = limitedQuery[:untilOrderChar]
limitedQuery = limitedQuery.replace("SELECT ", (limitStr % 1), 1)
limitedQuery = "%s WHERE %s " % (limitedQuery, fieldsList[0])
limitedQuery = "%s WHERE %s " % (limitedQuery, field)
limitedQuery += "NOT IN (%s" % (limitStr % num)
limitedQuery += "%s %s)" % (fieldsList[0], fromFrom)
limitedQuery += "%s %s)" % (field, fromFrom)
return limitedQuery

View File

@ -70,13 +70,23 @@ def __goInference(payload, expression):
return value
def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected=None):
outputs = []
def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected=None, num=None):
outputs = []
origExpr = None
for field in expressionFieldsList:
output = None
if isinstance(num, int):
origExpr = expression
expression = agent.limitQuery(num, expression, field)
expressionReplaced = expression.replace(expressionFields, field, 1)
if " ORDER BY " in expressionReplaced and "(SELECT " in expressionReplaced:
orderIndex = expressionReplaced.index(" ORDER BY ")
expressionReplaced += expressionReplaced[orderIndex:].replace(")", "")
output = resume(expressionReplaced, payload)
if not output or ( expected == "int" and not output.isdigit() ):
@ -87,6 +97,9 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl
output = __goInference(payload, expressionReplaced)
if isinstance(num, int):
expression = origExpr
outputs.append(output)
return outputs
@ -252,9 +265,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
return None
for num in xrange(startLimit, stopLimit):
limitedExpr = agent.limitQuery(num, expression, expressionFieldsList)
output = __goInferenceFields(limitedExpr, expressionFields, expressionFieldsList, payload, expected)
output = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, num)
outputs.append(output)
return outputs

View File

@ -261,7 +261,14 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False):
return
for num in xrange(startLimit, stopLimit):
limitedExpr = agent.limitQuery(num, expression, expressionFieldsList)
orderBy = re.search(" ORDER BY ([\w\_]+)", expression, re.I)
if orderBy:
field = orderBy.group(1)
else:
field = expressionFieldsList[0]
limitedExpr = agent.limitQuery(num, expression, field)
output = unionUse(limitedExpr, direct=True, unescape=False)
if output: