From 9149d77cc81f6cdf2683780f53d7ddd629412de9 Mon Sep 17 00:00:00 2001 From: Bernardo Damele Date: Wed, 19 Dec 2012 12:17:56 +0000 Subject: [PATCH] removed duplicate code - fixes issue #310 --- lib/core/agent.py | 65 +++++++++++++++++++++++++++++++++++ lib/request/inject.py | 67 ++++--------------------------------- lib/techniques/error/use.py | 66 +++--------------------------------- lib/techniques/union/use.py | 65 +++-------------------------------- 4 files changed, 80 insertions(+), 183 deletions(-) diff --git a/lib/core/agent.py b/lib/core/agent.py index c97401f62..487eaf174 100644 --- a/lib/core/agent.py +++ b/lib/core/agent.py @@ -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 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 + _ = 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. diff --git a/lib/request/inject.py b/lib/request/inject.py index 82dae2431..bab81c138 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -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) diff --git a/lib/techniques/error/use.py b/lib/techniques/error/use.py index 7c997665d..4d2e9e4d8 100644 --- a/lib/techniques/error/use.py +++ b/lib/techniques/error/use.py @@ -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[:_] diff --git a/lib/techniques/union/use.py b/lib/techniques/union/use.py index 0512972c7..ce14b19c5 100644 --- a/lib/techniques/union/use.py +++ b/lib/techniques/union/use.py @@ -164,9 +164,9 @@ def unionUse(expression, unpack=True, dump=False): expression = expression[:expression.upper().rindex(" ORDER BY ")] # 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 +174,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)