From 934adb5e8deb327e04437543833550ab74748fa5 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Wed, 20 Oct 2010 09:09:04 +0000 Subject: [PATCH] code refactoring --- lib/controller/action.py | 2 +- lib/request/inject.py | 61 ++--------------- lib/techniques/error/{error.py => test.py} | 2 +- lib/techniques/error/use.py | 79 ++++++++++++++++++++++ 4 files changed, 87 insertions(+), 57 deletions(-) rename lib/techniques/error/{error.py => test.py} (96%) create mode 100644 lib/techniques/error/use.py diff --git a/lib/controller/action.py b/lib/controller/action.py index f3a527a70..014d3aa09 100644 --- a/lib/controller/action.py +++ b/lib/controller/action.py @@ -16,7 +16,7 @@ from lib.core.data import paths from lib.core.exception import sqlmapUnsupportedDBMSException from lib.core.settings import SUPPORTED_DBMS from lib.techniques.blind.timebased import timeTest -from lib.techniques.error.error import errorTest +from lib.techniques.error.test import errorTest from lib.techniques.inband.union.test import unionTest from lib.techniques.outband.stacked import stackedTest diff --git a/lib/request/inject.py b/lib/request/inject.py index 713258a0b..d3eb6af26 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -28,16 +28,18 @@ from lib.core.data import conf from lib.core.data import kb from lib.core.data import logger from lib.core.data import queries -from lib.core.settings import ERROR_SPACE -from lib.core.settings import ERROR_EMPTY_CHAR from lib.core.unescaper import unescaper from lib.request.connect import Connect as Request from lib.request.direct import direct from lib.techniques.inband.union.use import unionUse from lib.techniques.blind.inference import bisection +from lib.techniques.error.use import errorUse from lib.utils.resume import queryOutputLength from lib.utils.resume import resume +from lib.core.settings import ERROR_SPACE +from lib.core.settings import ERROR_EMPTY_CHAR + def __goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None): start = time.time() @@ -333,57 +335,6 @@ def __goInband(expression, expected=None, sort=True, resumeValue=True, unpack=Tr return data -def __goError(expression, resumeValue=True): - """ - Retrieve the output of a SQL query taking advantage of an error SQL - injection vulnerability on the affected parameter. - """ - logic = conf.logic - randInt = randomInt(1) - query = agent.prefixQuery(" %s" % queries[kb.misc.testedDbms].error) - query = agent.postfixQuery(query) - payload = agent.payload(newValue=query) - - if resumeValue: - output = resume(expression, payload) - else: - output = None - - if output and ( expected is None or ( expected == "int" and output.isdigit() ) ): - return output - - if kb.dbmsDetected: - _, _, _, _, _, _, fieldToCastStr = agent.getFields(expression) - nulledCastedField = agent.nullAndCastField(fieldToCastStr) - if kb.dbms == "MySQL": - nulledCastedField = nulledCastedField.replace("CHAR(10000)", "CHAR(255)") #fix for that 'Subquery returns more than 1 row' - expressionReplaced = expression.replace(fieldToCastStr, nulledCastedField, 1) - expressionUnescaped = unescaper.unescape(expressionReplaced) - else: - expressionUnescaped = unescaper.unescape(expression) - - debugMsg = "query: %s" % expressionUnescaped - logger.debug(debugMsg) - - forgedPayload = safeStringFormat(payload, (logic, randInt, expressionUnescaped)) - result = Request.queryPage(urlencode(forgedPayload), content=True) - - match = re.search(queries[kb.misc.testedDbms].errorRegex, result[0], re.DOTALL | re.IGNORECASE) - if match: - output = match.group('result') - if output: - output = output.replace(ERROR_SPACE, " ").replace(ERROR_EMPTY_CHAR, "") - - if kb.misc.testedDbms == 'MySQL': - output = output[:-1] - - if conf.verbose > 0: - infoMsg = "retrieved: %s" % replaceNewlineTabs(output, stdout=True) - logger.info(infoMsg) - - return output - - def getValue(expression, blind=True, inband=True, error=True, fromUser=False, expected=None, batch=False, unpack=True, sort=True, resumeValue=True, charsetType=None, firstChar=None, lastChar=None, dump=False, suppressOutput=False): """ Called each time sqlmap inject a SQL query on the SQL injection @@ -406,7 +357,7 @@ def getValue(expression, blind=True, inband=True, error=True, fromUser=False, ex expression = expression.replace("DISTINCT ", "") if error and conf.errorTest: - value = __goError(expression) + value = errorUse(expression) if not value: warnMsg = "for some reasons it was not possible to retrieve " @@ -465,6 +416,6 @@ def goError(expression): if conf.direct: return direct(expression), None - result = __goError(expression) + result = errorUse(expression) return result diff --git a/lib/techniques/error/error.py b/lib/techniques/error/test.py similarity index 96% rename from lib/techniques/error/error.py rename to lib/techniques/error/test.py index 7a5b9cf1f..a98931449 100644 --- a/lib/techniques/error/error.py +++ b/lib/techniques/error/test.py @@ -29,7 +29,7 @@ def errorTest(): infoMsg += "'%s' with %s condition syntax" % (kb.injParameter, conf.logic) logger.info(infoMsg) - randInt = getUnicode(randomInt(1)) + randInt = getUnicode(randomInt(1)) query = queries[kb.dbms].case % ("%s=%s" % (randInt, randInt)) result = inject.goError(query) diff --git a/lib/techniques/error/use.py b/lib/techniques/error/use.py new file mode 100644 index 000000000..66f309b8f --- /dev/null +++ b/lib/techniques/error/use.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python + +""" +$Id$ + +Copyright (c) 2006-2010 sqlmap developers (http://sqlmap.sourceforge.net/) +See the file 'doc/COPYING' for copying permission +""" + +import re +import time + +from lib.core.agent import agent +from lib.core.common import getUnicode +from lib.core.common import randomInt +from lib.core.common import replaceNewlineTabs +from lib.core.common import safeStringFormat +from lib.core.convert import urlencode +from lib.core.data import conf +from lib.core.data import kb +from lib.core.data import logger +from lib.core.data import queries +from lib.core.session import setError +from lib.core.unescaper import unescaper +from lib.request.connect import Connect as Request +from lib.utils.resume import resume + +from lib.core.settings import ERROR_SPACE +from lib.core.settings import ERROR_EMPTY_CHAR + +def errorUse(expression, resumeValue=True): + """ + Retrieve the output of a SQL query taking advantage of an error SQL + injection vulnerability on the affected parameter. + """ + logic = conf.logic + randInt = randomInt(1) + query = agent.prefixQuery(" %s" % queries[kb.misc.testedDbms].error) + query = agent.postfixQuery(query) + payload = agent.payload(newValue=query) + + if resumeValue: + output = resume(expression, payload) + else: + output = None + + if output and ( expected is None or ( expected == "int" and output.isdigit() ) ): + return output + + if kb.dbmsDetected: + _, _, _, _, _, _, fieldToCastStr = agent.getFields(expression) + nulledCastedField = agent.nullAndCastField(fieldToCastStr) + if kb.dbms == "MySQL": + nulledCastedField = nulledCastedField.replace("CHAR(10000)", "CHAR(255)") #fix for that 'Subquery returns more than 1 row' + expressionReplaced = expression.replace(fieldToCastStr, nulledCastedField, 1) + expressionUnescaped = unescaper.unescape(expressionReplaced) + else: + expressionUnescaped = unescaper.unescape(expression) + + debugMsg = "query: %s" % expressionUnescaped + logger.debug(debugMsg) + + forgedPayload = safeStringFormat(payload, (logic, randInt, expressionUnescaped)) + result = Request.queryPage(urlencode(forgedPayload), content=True) + + match = re.search(queries[kb.misc.testedDbms].errorRegex, result[0], re.DOTALL | re.IGNORECASE) + if match: + output = match.group('result') + if output: + output = output.replace(ERROR_SPACE, " ").replace(ERROR_EMPTY_CHAR, "") + + if kb.misc.testedDbms == 'MySQL': + output = output[:-1] + + if conf.verbose > 0: + infoMsg = "retrieved: %s" % replaceNewlineTabs(output, stdout=True) + logger.info(infoMsg) + + return output