mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-01-21 21:59:20 +00:00
Merge branch 'master' of github.com:sqlmapproject/sqlmap
This commit is contained in:
@@ -675,6 +675,71 @@ class Agent(object):
|
||||
|
||||
return unionQuery
|
||||
|
||||
def limitCondition(self, expression, dump=False):
|
||||
startLimit = 0
|
||||
stopLimit = None
|
||||
limitCond = True
|
||||
|
||||
limitRegExp = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query, expression, re.I)
|
||||
limitRegExp2 = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query2, expression, re.I)
|
||||
topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I)
|
||||
|
||||
if (limitRegExp or limitRegExp2) or (Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and topLimit):
|
||||
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE):
|
||||
limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
|
||||
limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query
|
||||
|
||||
if limitGroupStart.isdigit():
|
||||
if limitRegExp:
|
||||
startLimit = int(limitRegExp.group(int(limitGroupStart)))
|
||||
stopLimit = limitRegExp.group(int(limitGroupStop))
|
||||
elif limitRegExp2:
|
||||
startLimit = 0
|
||||
stopLimit = limitRegExp2.group(int(limitGroupStart))
|
||||
limitCond = int(stopLimit) > 1
|
||||
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
|
||||
if limitRegExp:
|
||||
limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
|
||||
limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query
|
||||
|
||||
if limitGroupStart.isdigit():
|
||||
startLimit = int(limitRegExp.group(int(limitGroupStart)))
|
||||
|
||||
stopLimit = limitRegExp.group(int(limitGroupStop))
|
||||
limitCond = int(stopLimit) > 1
|
||||
elif topLimit:
|
||||
startLimit = 0
|
||||
stopLimit = int(topLimit.group(1))
|
||||
limitCond = int(stopLimit) > 1
|
||||
|
||||
elif Backend.isDbms(DBMS.ORACLE):
|
||||
limitCond = False
|
||||
|
||||
# We assume that only queries NOT containing a "LIMIT #, 1"
|
||||
# (or equivalent depending on the back-end DBMS) can return
|
||||
# multiple entries
|
||||
if limitCond:
|
||||
if (limitRegExp or limitRegExp2) and stopLimit is not None:
|
||||
stopLimit = int(stopLimit)
|
||||
|
||||
# From now on we need only the expression until the " LIMIT "
|
||||
# (or equivalent, depending on the back-end DBMS) word
|
||||
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE):
|
||||
stopLimit += startLimit
|
||||
_ = expression.index(queries[Backend.getIdentifiedDbms()].limitstring.query)
|
||||
expression = expression[:_]
|
||||
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
|
||||
stopLimit += startLimit
|
||||
elif dump:
|
||||
if conf.limitStart:
|
||||
startLimit = conf.limitStart - 1
|
||||
if conf.limitStop:
|
||||
stopLimit = conf.limitStop
|
||||
|
||||
return expression, limitCond, topLimit, startLimit, stopLimit
|
||||
|
||||
def limitQuery(self, num, query, field=None, uniqueField=None):
|
||||
"""
|
||||
Take in input a query string and return its limited query string.
|
||||
|
||||
@@ -661,6 +661,9 @@ def filePathToString(filePath):
|
||||
|
||||
return strRepl
|
||||
|
||||
def singleTimeDebugMessage(message):
|
||||
singleTimeLogMessage(message, logging.DEBUG)
|
||||
|
||||
def singleTimeWarnMessage(message):
|
||||
singleTimeLogMessage(message, logging.WARN)
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ def liveTest():
|
||||
if case.hasAttribute("name"):
|
||||
name = case.getAttribute("name")
|
||||
|
||||
if conf.runCase and ((conf.runCase.isdigit() and conf.runCase != count) or not re.search(conf.runCase, name, re.DOTALL)):
|
||||
if conf.runCase and ((conf.runCase.isdigit() and conf.runCase != count) or not re.search(conf.runCase, name, re.DOTALL | re.I)):
|
||||
continue
|
||||
|
||||
if case.getElementsByTagName("switches"):
|
||||
@@ -206,7 +206,7 @@ def runCase(switches=None, parse=None):
|
||||
retVal = False
|
||||
|
||||
if parse and retVal:
|
||||
ifile = open(conf.dumper.getOutputFile(), 'r')
|
||||
ifile = open(conf.dumper.getOutputFile(), "rb")
|
||||
content = ifile.read()
|
||||
ifile.close()
|
||||
for item in parse:
|
||||
|
||||
@@ -139,8 +139,6 @@ def _goInferenceProxy(expression, fromUser=False, batch=False, unpack=True, char
|
||||
startLimit = 0
|
||||
stopLimit = None
|
||||
outputs = BigArray()
|
||||
untilLimitChar = None
|
||||
untilOrderChar = None
|
||||
|
||||
if not unpack:
|
||||
return _goInference(payload, expression, charsetType, firstChar, lastChar, dump)
|
||||
@@ -160,69 +158,18 @@ def _goInferenceProxy(expression, fromUser=False, batch=False, unpack=True, char
|
||||
|
||||
# If we have been here from SQL query/shell we have to check if
|
||||
# the SQL query might return multiple entries and in such case
|
||||
# forge the SQL limiting the query output one entry per time
|
||||
# NOTE: I assume that only queries that get data from a table
|
||||
# forge the SQL limiting the query output one entry at a time
|
||||
# NOTE: we assume that only queries that get data from a table
|
||||
# can return multiple entries
|
||||
if fromUser and " FROM " in expression.upper() and ((Backend.getIdentifiedDbms() \
|
||||
not in FROM_DUMMY_TABLE) or (Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and not \
|
||||
expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]))) \
|
||||
and not re.search(SQL_SCALAR_REGEX, expression, re.I):
|
||||
expression, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression)
|
||||
|
||||
limitCond = True
|
||||
limitRegExp = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query, expression, re.I)
|
||||
limitRegExp2 = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query2, expression, re.I)
|
||||
topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I)
|
||||
|
||||
if (limitRegExp or limitRegExp2) or (Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and topLimit):
|
||||
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE):
|
||||
limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
|
||||
limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query
|
||||
|
||||
if limitGroupStart.isdigit():
|
||||
if limitRegExp2:
|
||||
startLimit = 0
|
||||
stopLimit = limitRegExp2.group(int(limitGroupStart))
|
||||
else:
|
||||
startLimit = int(limitRegExp.group(int(limitGroupStart)))
|
||||
stopLimit = limitRegExp.group(int(limitGroupStop))
|
||||
limitCond = int(stopLimit) > 1
|
||||
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
|
||||
if limitRegExp:
|
||||
limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
|
||||
limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query
|
||||
|
||||
if limitGroupStart.isdigit():
|
||||
startLimit = int(limitRegExp.group(int(limitGroupStart)))
|
||||
|
||||
stopLimit = limitRegExp.group(int(limitGroupStop))
|
||||
limitCond = int(stopLimit) > 1
|
||||
elif topLimit:
|
||||
startLimit = 0
|
||||
stopLimit = int(topLimit.group(1))
|
||||
limitCond = int(stopLimit) > 1
|
||||
|
||||
elif Backend.isDbms(DBMS.ORACLE):
|
||||
limitCond = False
|
||||
|
||||
# We assume that only queries NOT containing a "LIMIT #, 1"
|
||||
# (or equivalent depending on the back-end DBMS) can return
|
||||
# multiple entries
|
||||
if limitCond:
|
||||
if (limitRegExp or limitRegExp2) and stopLimit is not None:
|
||||
stopLimit = int(stopLimit)
|
||||
|
||||
# From now on we need only the expression until the " LIMIT "
|
||||
# (or equivalent, depending on the back-end DBMS) word
|
||||
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE):
|
||||
stopLimit += startLimit
|
||||
untilLimitChar = expression.index(queries[Backend.getIdentifiedDbms()].limitstring.query)
|
||||
expression = expression[:untilLimitChar]
|
||||
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
|
||||
stopLimit += startLimit
|
||||
|
||||
test = True
|
||||
|
||||
if not stopLimit or stopLimit <= 1:
|
||||
if Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]):
|
||||
test = False
|
||||
@@ -232,9 +179,9 @@ def _goInferenceProxy(expression, fromUser=False, batch=False, unpack=True, char
|
||||
countFirstField = queries[Backend.getIdentifiedDbms()].count.query % expressionFieldsList[0]
|
||||
countedExpression = expression.replace(expressionFields, countFirstField, 1)
|
||||
|
||||
if re.search(" ORDER BY ", expression, re.I):
|
||||
untilOrderChar = countedExpression.index(" ORDER BY ")
|
||||
countedExpression = countedExpression[:untilOrderChar]
|
||||
if " ORDER BY " in expression.upper():
|
||||
_ = countedExpression.upper().rindex(" ORDER BY ")
|
||||
countedExpression = countedExpression[:_]
|
||||
|
||||
if not stopLimit:
|
||||
count = _goInference(payload, countedExpression, charsetType=CHARSET_TYPE.DIGITS, firstChar=firstChar, lastChar=lastChar)
|
||||
|
||||
@@ -238,14 +238,13 @@ def errorUse(expression, dump=False):
|
||||
stopLimit = None
|
||||
output = None
|
||||
outputs = None
|
||||
untilLimitChar = None
|
||||
|
||||
_, _, _, _, _, expressionFieldsList, expressionFields, _ = agent.getFields(expression)
|
||||
|
||||
# We have to check if the SQL query might return multiple entries
|
||||
# and in such case forge the SQL limiting the query output one
|
||||
# entry per time
|
||||
# NOTE: I assume that only queries that get data from a table can
|
||||
# entry at a time
|
||||
# NOTE: we assume that only queries that get data from a table can
|
||||
# return multiple entries
|
||||
if (dump and (conf.limitStart or conf.limitStop)) or (" FROM " in \
|
||||
expression.upper() and ((Backend.getIdentifiedDbms() not in FROM_DUMMY_TABLE) \
|
||||
@@ -253,70 +252,13 @@ def errorUse(expression, dump=False):
|
||||
expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]))) \
|
||||
and ("(CASE" not in expression.upper() or ("(CASE" in expression.upper() and "WHEN use" in expression))) \
|
||||
and not re.search(SQL_SCALAR_REGEX, expression, re.I):
|
||||
expression, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression, dump)
|
||||
|
||||
limitCond = True
|
||||
limitRegExp = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query, expression, re.I)
|
||||
limitRegExp2 = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query2, expression, re.I)
|
||||
topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I)
|
||||
|
||||
if (limitRegExp or limitRegExp2) or (Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and topLimit):
|
||||
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE):
|
||||
limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
|
||||
limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query
|
||||
|
||||
if limitGroupStart.isdigit():
|
||||
if limitRegExp2:
|
||||
startLimit = 0
|
||||
stopLimit = limitRegExp2.group(int(limitGroupStart))
|
||||
else:
|
||||
startLimit = int(limitRegExp.group(int(limitGroupStart)))
|
||||
stopLimit = limitRegExp.group(int(limitGroupStop))
|
||||
limitCond = int(stopLimit) > 1
|
||||
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
|
||||
if limitRegExp:
|
||||
limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
|
||||
limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query
|
||||
|
||||
if limitGroupStart.isdigit():
|
||||
startLimit = int(limitRegExp.group(int(limitGroupStart)))
|
||||
|
||||
stopLimit = limitRegExp.group(int(limitGroupStop))
|
||||
limitCond = int(stopLimit) > 1
|
||||
elif topLimit:
|
||||
startLimit = 0
|
||||
stopLimit = int(topLimit.group(1))
|
||||
limitCond = int(stopLimit) > 1
|
||||
|
||||
elif Backend.isDbms(DBMS.ORACLE):
|
||||
limitCond = False
|
||||
|
||||
# I assume that only queries NOT containing a "LIMIT #, 1"
|
||||
# (or equivalent depending on the back-end DBMS) can return
|
||||
# multiple entries
|
||||
if limitCond:
|
||||
if (limitRegExp or limitRegExp2) and stopLimit is not None:
|
||||
stopLimit = int(stopLimit)
|
||||
|
||||
# From now on we need only the expression until the " LIMIT "
|
||||
# (or equivalent, depending on the back-end DBMS) word
|
||||
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE):
|
||||
stopLimit += startLimit
|
||||
untilLimitChar = expression.index(queries[Backend.getIdentifiedDbms()].limitstring.query)
|
||||
expression = expression[:untilLimitChar]
|
||||
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
|
||||
stopLimit += startLimit
|
||||
elif dump:
|
||||
if conf.limitStart:
|
||||
startLimit = conf.limitStart - 1
|
||||
if conf.limitStop:
|
||||
stopLimit = conf.limitStop
|
||||
|
||||
# Count the number of SQL query entries output
|
||||
countedExpression = expression.replace(expressionFields, queries[Backend.getIdentifiedDbms()].count.query % ('*' if len(expressionFieldsList) > 1 else expressionFields), 1)
|
||||
|
||||
if " ORDER BY " in expression:
|
||||
if " ORDER BY " in expression.upper():
|
||||
_ = countedExpression.upper().rindex(" ORDER BY ")
|
||||
countedExpression = countedExpression[:_]
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ from lib.core.common import isNumPosStrValue
|
||||
from lib.core.common import listToStrValue
|
||||
from lib.core.common import parseUnionPage
|
||||
from lib.core.common import removeReflectiveValues
|
||||
from lib.core.common import singleTimeDebugMessage
|
||||
from lib.core.common import singleTimeWarnMessage
|
||||
from lib.core.common import wasLastRequestDBMSError
|
||||
from lib.core.convert import htmlunescape
|
||||
@@ -159,14 +160,17 @@ def unionUse(expression, unpack=True, dump=False):
|
||||
|
||||
_, _, _, _, _, expressionFieldsList, expressionFields, _ = agent.getFields(origExpr)
|
||||
|
||||
if expressionFieldsList and len(expressionFieldsList) > 1 and " ORDER BY " in expression.upper():
|
||||
# No need for it in multicolumn dumps (one row is retrieved per request) and just slowing down on large table dumps
|
||||
expression = expression[:expression.upper().rindex(" ORDER BY ")]
|
||||
if expressionFieldsList and len(expressionFieldsList) > 1 and "ORDER BY" in expression.upper():
|
||||
# Removed ORDER BY clause because UNION does not play well with it
|
||||
expression = re.sub("\s*ORDER BY\s+[\w,]+", "", expression, re.I)
|
||||
debugMsg = "stripping ORDER BY clause from statement because "
|
||||
debugMsg += "it does not play well with UNION query SQL injection"
|
||||
singleTimeDebugMessage(debugMsg)
|
||||
|
||||
# We have to check if the SQL query might return multiple entries
|
||||
# and in such case forge the SQL limiting the query output one
|
||||
# entry per time
|
||||
# NOTE: I assume that only queries that get data from a table can
|
||||
# if the technique is partial UNION query and in such case forge the
|
||||
# SQL limiting the query output one entry at a time
|
||||
# NOTE: we assume that only queries that get data from a table can
|
||||
# return multiple entries
|
||||
if (kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.NEGATIVE or \
|
||||
(dump and (conf.limitStart or conf.limitStop))) and \
|
||||
@@ -174,66 +178,9 @@ def unionUse(expression, unpack=True, dump=False):
|
||||
not in FROM_DUMMY_TABLE) or (Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE \
|
||||
and not expression.upper().endswith(FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]))) \
|
||||
and not re.search(SQL_SCALAR_REGEX, expression, re.I):
|
||||
expression, limitCond, topLimit, startLimit, stopLimit = agent.limitCondition(expression, dump)
|
||||
|
||||
limitCond = True
|
||||
limitRegExp = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query, expression, re.I)
|
||||
limitRegExp2 = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query2, expression, re.I)
|
||||
topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I)
|
||||
|
||||
if (limitRegExp or limitRegExp2) or (Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) and topLimit):
|
||||
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE):
|
||||
limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
|
||||
limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query
|
||||
|
||||
if limitGroupStart.isdigit():
|
||||
if limitRegExp2:
|
||||
startLimit = 0
|
||||
stopLimit = limitRegExp2.group(int(limitGroupStart))
|
||||
else:
|
||||
startLimit = int(limitRegExp.group(int(limitGroupStart)))
|
||||
stopLimit = limitRegExp.group(int(limitGroupStop))
|
||||
limitCond = int(stopLimit) > 1
|
||||
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
|
||||
if limitRegExp:
|
||||
limitGroupStart = queries[Backend.getIdentifiedDbms()].limitgroupstart.query
|
||||
limitGroupStop = queries[Backend.getIdentifiedDbms()].limitgroupstop.query
|
||||
|
||||
if limitGroupStart.isdigit():
|
||||
startLimit = int(limitRegExp.group(int(limitGroupStart)))
|
||||
|
||||
stopLimit = limitRegExp.group(int(limitGroupStop))
|
||||
limitCond = int(stopLimit) > 1
|
||||
elif topLimit:
|
||||
startLimit = 0
|
||||
stopLimit = int(topLimit.group(1))
|
||||
limitCond = int(stopLimit) > 1
|
||||
|
||||
elif Backend.isDbms(DBMS.ORACLE):
|
||||
limitCond = False
|
||||
|
||||
# I assume that only queries NOT containing a "LIMIT #, 1"
|
||||
# (or equivalent depending on the back-end DBMS) can return
|
||||
# multiple entries
|
||||
if limitCond:
|
||||
if (limitRegExp or limitRegExp2) and stopLimit is not None:
|
||||
stopLimit = int(stopLimit)
|
||||
|
||||
# From now on we need only the expression until the " LIMIT "
|
||||
# (or equivalent, depending on the back-end DBMS) word
|
||||
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL, DBMS.SQLITE):
|
||||
stopLimit += startLimit
|
||||
untilLimitChar = expression.index(queries[Backend.getIdentifiedDbms()].limitstring.query)
|
||||
expression = expression[:untilLimitChar]
|
||||
|
||||
elif Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE):
|
||||
stopLimit += startLimit
|
||||
elif dump:
|
||||
if conf.limitStart:
|
||||
startLimit = conf.limitStart - 1
|
||||
if conf.limitStop:
|
||||
stopLimit = conf.limitStop
|
||||
|
||||
# Count the number of SQL query entries output
|
||||
countedExpression = expression.replace(expressionFields, queries[Backend.getIdentifiedDbms()].count.query % ('*' if len(expressionFieldsList) > 1 else expressionFields), 1)
|
||||
|
||||
@@ -362,7 +309,6 @@ def unionUse(expression, unpack=True, dump=False):
|
||||
kb.suppressResumeInfo = False
|
||||
|
||||
if not value and not abortedFlag:
|
||||
expression = re.sub("\s*ORDER BY\s+[\w,]+", "", expression, re.I) # full union doesn't play well with ORDER BY
|
||||
value = _oneShotUnionUse(expression, unpack)
|
||||
|
||||
duration = calculateDeltaSeconds(start)
|
||||
|
||||
Reference in New Issue
Block a user