mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-05-10 02:33:44 +03:00
Major bug fix to make it work properly with MSSQL custom limited (SELECT
TOP ...) queries with both inferential blind and Full UNION query injection
This commit is contained in:
parent
2cc3bb2f6a
commit
9c42a883be
|
@ -285,7 +285,7 @@ class Agent:
|
||||||
if query.startswith("SELECT ") and "(SELECT " in query:
|
if query.startswith("SELECT ") and "(SELECT " in query:
|
||||||
fieldsSelectFrom = None
|
fieldsSelectFrom = None
|
||||||
|
|
||||||
return fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsToCastList, fieldsToCastStr
|
return fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, fieldsToCastList, fieldsToCastStr
|
||||||
|
|
||||||
|
|
||||||
def concatQuery(self, query):
|
def concatQuery(self, query):
|
||||||
|
@ -317,7 +317,7 @@ class Agent:
|
||||||
concatQuery = ""
|
concatQuery = ""
|
||||||
query = query.replace(", ", ",")
|
query = query.replace(", ", ",")
|
||||||
|
|
||||||
fieldsSelectFrom, fieldsSelect, fieldsNoSelect, _, fieldsToCastStr = self.getFields(query)
|
fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, _, fieldsToCastStr = self.getFields(query)
|
||||||
castedFields = self.nullCastConcatFields(fieldsToCastStr)
|
castedFields = self.nullCastConcatFields(fieldsToCastStr)
|
||||||
concatQuery = query.replace(fieldsToCastStr, castedFields, 1)
|
concatQuery = query.replace(fieldsToCastStr, castedFields, 1)
|
||||||
|
|
||||||
|
@ -348,7 +348,11 @@ class Agent:
|
||||||
concatQuery += " FROM DUAL"
|
concatQuery += " FROM DUAL"
|
||||||
|
|
||||||
elif kb.dbms == "Microsoft SQL Server":
|
elif kb.dbms == "Microsoft SQL Server":
|
||||||
if fieldsSelectFrom:
|
if fieldsSelectTop:
|
||||||
|
topNum = re.search("\ASELECT\s+TOP\s+([\d]+)\s+", concatQuery, re.I).group(1)
|
||||||
|
concatQuery = concatQuery.replace("SELECT TOP %s " % topNum, "TOP %s '%s'+" % (topNum, temp.start), 1)
|
||||||
|
concatQuery = concatQuery.replace(" FROM ", "+'%s' FROM " % temp.stop, 1)
|
||||||
|
elif fieldsSelectFrom:
|
||||||
concatQuery = concatQuery.replace("SELECT ", "'%s'+" % temp.start, 1)
|
concatQuery = concatQuery.replace("SELECT ", "'%s'+" % temp.start, 1)
|
||||||
concatQuery = concatQuery.replace(" FROM ", "+'%s' FROM " % temp.stop, 1)
|
concatQuery = concatQuery.replace(" FROM ", "+'%s' FROM " % temp.stop, 1)
|
||||||
elif fieldsSelect:
|
elif fieldsSelect:
|
||||||
|
@ -393,6 +397,11 @@ class Agent:
|
||||||
|
|
||||||
inbandQuery = self.prefixQuery(" UNION ALL SELECT ")
|
inbandQuery = self.prefixQuery(" UNION ALL SELECT ")
|
||||||
|
|
||||||
|
if query.startswith("TOP"):
|
||||||
|
topNum = re.search("\ATOP\s+([\d]+)\s+", query, re.I).group(1)
|
||||||
|
query = query[len("TOP %s " % topNum):]
|
||||||
|
inbandQuery += "TOP %s " % topNum
|
||||||
|
|
||||||
if not exprPosition:
|
if not exprPosition:
|
||||||
exprPosition = kb.unionPosition
|
exprPosition = kb.unionPosition
|
||||||
|
|
||||||
|
@ -472,10 +481,17 @@ class Agent:
|
||||||
if " ORDER BY " in limitedQuery:
|
if " ORDER BY " in limitedQuery:
|
||||||
limitedQuery = limitedQuery[:limitedQuery.index(" ORDER BY ")]
|
limitedQuery = limitedQuery[:limitedQuery.index(" ORDER BY ")]
|
||||||
|
|
||||||
|
if not limitedQuery.startswith("SELECT TOP "):
|
||||||
limitedQuery = limitedQuery.replace("SELECT ", (limitStr % 1), 1)
|
limitedQuery = limitedQuery.replace("SELECT ", (limitStr % 1), 1)
|
||||||
limitedQuery = "%s WHERE %s " % (limitedQuery, field)
|
limitedQuery = "%s WHERE %s " % (limitedQuery, field)
|
||||||
limitedQuery += "NOT IN (%s" % (limitStr % num)
|
limitedQuery += "NOT IN (%s" % (limitStr % num)
|
||||||
limitedQuery += "%s %s)" % (field, fromFrom)
|
limitedQuery += "%s %s)" % (field, fromFrom)
|
||||||
|
else:
|
||||||
|
topNums = re.search("\ASELECT\s+TOP\s+([\d]+)\s+.+?\s+FROM\s+.+?\s+WHERE\s+.+?\s+NOT\s+IN\s+\(SELECT\s+TOP\s+([\d]+)\s+", limitedQuery, re.I).groups()
|
||||||
|
quantityTopNums = topNums[0]
|
||||||
|
limitedQuery = limitedQuery.replace("SELECT TOP %s" % quantityTopNums, "SELECT TOP 1", 1)
|
||||||
|
startTopNums = topNums[1]
|
||||||
|
limitedQuery = limitedQuery.replace(" (SELECT TOP %s" % startTopNums, " (SELECT TOP %d" % num)
|
||||||
|
|
||||||
return limitedQuery
|
return limitedQuery
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ import sys
|
||||||
|
|
||||||
|
|
||||||
# sqlmap version and site
|
# sqlmap version and site
|
||||||
VERSION = "0.6.4-rc3"
|
VERSION = "0.6.4-rc4"
|
||||||
VERSION_STRING = "sqlmap/%s" % VERSION
|
VERSION_STRING = "sqlmap/%s" % VERSION
|
||||||
SITE = "http://sqlmap.sourceforge.net"
|
SITE = "http://sqlmap.sourceforge.net"
|
||||||
|
|
||||||
|
@ -73,6 +73,7 @@ MATCH_RATIO = 0.9
|
||||||
SQL_STATEMENTS = {
|
SQL_STATEMENTS = {
|
||||||
"SQL SELECT statement": (
|
"SQL SELECT statement": (
|
||||||
"select ",
|
"select ",
|
||||||
|
"select top ",
|
||||||
" from ",
|
" from ",
|
||||||
" from dual",
|
" from dual",
|
||||||
" where ",
|
" where ",
|
||||||
|
|
|
@ -131,7 +131,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
|
||||||
return output
|
return output
|
||||||
|
|
||||||
if kb.dbmsDetected:
|
if kb.dbmsDetected:
|
||||||
_, _, _, expressionFieldsList, expressionFields = agent.getFields(expression)
|
_, _, _, _, expressionFieldsList, expressionFields = agent.getFields(expression)
|
||||||
|
|
||||||
if len(expressionFieldsList) > 1:
|
if len(expressionFieldsList) > 1:
|
||||||
infoMsg = "the SQL query provided has more than a field. "
|
infoMsg = "the SQL query provided has more than a field. "
|
||||||
|
@ -159,7 +159,17 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
|
||||||
stopLimit = limitRegExp.group(int(limitGroupStop))
|
stopLimit = limitRegExp.group(int(limitGroupStop))
|
||||||
limitCond = int(stopLimit) > 1
|
limitCond = int(stopLimit) > 1
|
||||||
|
|
||||||
elif kb.dbms in ( "Oracle", "Microsoft SQL Server" ):
|
elif kb.dbms == "Microsoft SQL Server":
|
||||||
|
limitGroupStart = queries[kb.dbms].limitgroupstart
|
||||||
|
limitGroupStop = queries[kb.dbms].limitgroupstop
|
||||||
|
|
||||||
|
if limitGroupStart.isdigit():
|
||||||
|
startLimit = int(limitRegExp.group(int(limitGroupStart)))
|
||||||
|
|
||||||
|
stopLimit = limitRegExp.group(int(limitGroupStop))
|
||||||
|
limitCond = int(stopLimit) > 1
|
||||||
|
|
||||||
|
elif kb.dbms == "Oracle":
|
||||||
limitCond = False
|
limitCond = False
|
||||||
else:
|
else:
|
||||||
limitCond = True
|
limitCond = True
|
||||||
|
@ -178,6 +188,9 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
|
||||||
untilLimitChar = expression.index(queries[kb.dbms].limitstring)
|
untilLimitChar = expression.index(queries[kb.dbms].limitstring)
|
||||||
expression = expression[:untilLimitChar]
|
expression = expression[:untilLimitChar]
|
||||||
|
|
||||||
|
elif kb.dbms == "Microsoft SQL Server":
|
||||||
|
stopLimit += startLimit
|
||||||
|
|
||||||
if not stopLimit or stopLimit <= 1:
|
if not stopLimit or stopLimit <= 1:
|
||||||
if kb.dbms == "Oracle" and expression.endswith("FROM DUAL"):
|
if kb.dbms == "Oracle" and expression.endswith("FROM DUAL"):
|
||||||
test = "n"
|
test = "n"
|
||||||
|
|
|
@ -54,7 +54,7 @@ def bisection(payload, expression, length=None):
|
||||||
finalValue = ""
|
finalValue = ""
|
||||||
|
|
||||||
if kb.dbmsDetected:
|
if kb.dbmsDetected:
|
||||||
_, _, _, _, fieldToCastStr = agent.getFields(expression)
|
_, _, _, _, _, fieldToCastStr = agent.getFields(expression)
|
||||||
nulledCastedField = agent.nullAndCastField(fieldToCastStr)
|
nulledCastedField = agent.nullAndCastField(fieldToCastStr)
|
||||||
expressionReplaced = expression.replace(fieldToCastStr, nulledCastedField, 1)
|
expressionReplaced = expression.replace(fieldToCastStr, nulledCastedField, 1)
|
||||||
expressionUnescaped = unescaper.unescape(expressionReplaced)
|
expressionUnescaped = unescaper.unescape(expressionReplaced)
|
||||||
|
|
|
@ -159,7 +159,7 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False):
|
||||||
conf.paramNegative = True
|
conf.paramNegative = True
|
||||||
|
|
||||||
if conf.paramNegative == True and direct == False:
|
if conf.paramNegative == True and direct == False:
|
||||||
_, _, _, expressionFieldsList, expressionFields = agent.getFields(origExpr)
|
_, _, _, _, expressionFieldsList, expressionFields = agent.getFields(origExpr)
|
||||||
|
|
||||||
if len(expressionFieldsList) > 1:
|
if len(expressionFieldsList) > 1:
|
||||||
infoMsg = "the SQL query provided has more than a field. "
|
infoMsg = "the SQL query provided has more than a field. "
|
||||||
|
@ -187,7 +187,17 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False):
|
||||||
stopLimit = limitRegExp.group(int(limitGroupStop))
|
stopLimit = limitRegExp.group(int(limitGroupStop))
|
||||||
limitCond = int(stopLimit) > 1
|
limitCond = int(stopLimit) > 1
|
||||||
|
|
||||||
elif kb.dbms in ( "Oracle", "Microsoft SQL Server" ):
|
elif kb.dbms == "Microsoft SQL Server":
|
||||||
|
limitGroupStart = queries[kb.dbms].limitgroupstart
|
||||||
|
limitGroupStop = queries[kb.dbms].limitgroupstop
|
||||||
|
|
||||||
|
if limitGroupStart.isdigit():
|
||||||
|
startLimit = int(limitRegExp.group(int(limitGroupStart)))
|
||||||
|
|
||||||
|
stopLimit = limitRegExp.group(int(limitGroupStop))
|
||||||
|
limitCond = int(stopLimit) > 1
|
||||||
|
|
||||||
|
elif kb.dbms == "Oracle":
|
||||||
limitCond = False
|
limitCond = False
|
||||||
else:
|
else:
|
||||||
limitCond = True
|
limitCond = True
|
||||||
|
|
Loading…
Reference in New Issue
Block a user