diff --git a/lib/core/settings.py b/lib/core/settings.py index e9cca1b53..fd7f7be1c 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -333,3 +333,6 @@ RESULTS_FILE_FORMAT = 'results-%I%M%p_%m%d%Y.csv' # Official web page with the list of Python supported codecs CODECS_LIST_PAGE = 'http://docs.python.org/library/codecs.html#standard-encodings' + +# Simple regular expression used to distinguish scalar from multiple-row commands (not sole condition) +SQL_SCALAR_REGEX = r"\A(SELECT(?!\s+DISTINCT\(?))?\s*\w*\(" diff --git a/lib/request/inject.py b/lib/request/inject.py index 1e458e59c..13f5dfe43 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -40,6 +40,7 @@ from lib.core.exception import sqlmapUserQuitException from lib.core.settings import FROM_TABLE from lib.core.settings import MIN_TIME_RESPONSES from lib.core.settings import MAX_TECHNIQUES_PER_VALUE +from lib.core.settings import SQL_SCALAR_REGEX from lib.core.threads import getCurrentThreadData from lib.core.unescaper import unescaper from lib.request.connect import Connect as Request @@ -158,7 +159,8 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r # can return multiple entries if fromUser and " FROM " in expression.upper() and ((Backend.getIdentifiedDbms() \ not in FROM_TABLE) or (Backend.getIdentifiedDbms() in FROM_TABLE and not \ - expression.upper().endswith(FROM_TABLE[Backend.getIdentifiedDbms()]))): + expression.upper().endswith(FROM_TABLE[Backend.getIdentifiedDbms()]))) \ + and not re.search(SQL_SCALAR_REGEX, expression, re.I): limitRegExp = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query, expression, re.I) topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I) diff --git a/lib/techniques/error/use.py b/lib/techniques/error/use.py index ef64d9c42..b5ad1c3a0 100644 --- a/lib/techniques/error/use.py +++ b/lib/techniques/error/use.py @@ -36,6 +36,7 @@ from lib.core.exception import sqlmapConnectionException from lib.core.settings import FROM_TABLE from lib.core.settings import MYSQL_ERROR_CHUNK_LENGTH from lib.core.settings import MSSQL_ERROR_CHUNK_LENGTH +from lib.core.settings import SQL_SCALAR_REGEX from lib.core.settings import TURN_OFF_RESUME_INFO_LIMIT from lib.core.threads import getCurrentThreadData from lib.core.unescaper import unescaper @@ -218,7 +219,7 @@ def errorUse(expression, expected=None, resumeValue=True, dump=False): or (Backend.getIdentifiedDbms() in FROM_TABLE and not \ expression.upper().endswith(FROM_TABLE[Backend.getIdentifiedDbms()]))) \ and ("(CASE" not in expression.upper() or ("(CASE" in expression.upper() and "WHEN use" in expression))) \ - and not any(map(lambda x: x in expression.upper(), ["COUNT(*)", "EXISTS(", "MAX(", "MIN(", "COUNT(DISTINCT"])): + and not re.search(SQL_SCALAR_REGEX, expression, re.I): limitRegExp = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query, expression, re.I) topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I) diff --git a/lib/techniques/inband/union/use.py b/lib/techniques/inband/union/use.py index f7458f3ba..4fd82a552 100644 --- a/lib/techniques/inband/union/use.py +++ b/lib/techniques/inband/union/use.py @@ -34,6 +34,7 @@ from lib.core.enums import PAYLOAD from lib.core.exception import sqlmapConnectionException from lib.core.exception import sqlmapSyntaxException from lib.core.settings import FROM_TABLE +from lib.core.settings import SQL_SCALAR_REGEX from lib.core.settings import TURN_OFF_RESUME_INFO_LIMIT from lib.core.unescaper import unescaper from lib.request.connect import Connect as Request @@ -150,7 +151,7 @@ def unionUse(expression, unpack=True, dump=False): " FROM " in expression.upper() and ((Backend.getIdentifiedDbms() \ not in FROM_TABLE) or (Backend.getIdentifiedDbms() in FROM_TABLE \ and not expression.upper().endswith(FROM_TABLE[Backend.getIdentifiedDbms()]))) \ - and not any(map(lambda x: x in expression.upper(), ["(CASE", "COUNT(*)", "EXISTS(", "MAX(", "MIN(", "COUNT(DISTINCT"])): + and not re.search(SQL_SCALAR_REGEX, expression, re.I): limitRegExp = re.search(queries[Backend.getIdentifiedDbms()].limitregexp.query, expression, re.I) topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I)