From 6a8b1046d48deff1ef5854f1b8275db24fd35800 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Tue, 19 Oct 2010 12:02:04 +0000 Subject: [PATCH] first successfull run of error based sqlmap in history :). tested --banner, --current-user, --current-db on 4 major DBMSes. still hidden from users (turn on flag error in getValue() in inject.py) --- lib/parse/queriesfile.py | 7 +++++ lib/request/inject.py | 51 ++++++++++++++++++++++++++++++++-- plugins/generic/enumeration.py | 2 ++ xml/queries.xml | 2 +- 4 files changed, 58 insertions(+), 4 deletions(-) diff --git a/lib/parse/queriesfile.py b/lib/parse/queriesfile.py index fc442488b..3659339a4 100644 --- a/lib/parse/queriesfile.py +++ b/lib/parse/queriesfile.py @@ -95,6 +95,13 @@ class queriesHandler(ContentHandler): data = sanitizeStr(attrs.get("query")) self.__queries.case = data + elif name == "error": + data = sanitizeStr(attrs.get("query")) + self.__queries.error = data + + data = sanitizeStr(attrs.get("regex")) + self.__queries.errorRegex = data + elif name == "inference": data = sanitizeStr(attrs.get("query")) self.__queries.inference = data diff --git a/lib/request/inject.py b/lib/request/inject.py index 41e49c7b1..48305e703 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -19,11 +19,14 @@ from lib.core.common import parseUnionPage from lib.core.common import popValue from lib.core.common import pushValue from lib.core.common import readInput +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.data import temp +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 @@ -326,7 +329,40 @@ def __goInband(expression, expected=None, sort=True, resumeValue=True, unpack=Tr return data -def getValue(expression, blind=True, inband=True, fromUser=False, expected=None, batch=False, unpack=True, sort=True, resumeValue=True, charsetType=None, firstChar=None, lastChar=None, dump=False, suppressOutput=False): +def __goError(expression, resumeValue=True): + """ + Retrieve the output of a SQL query taking advantage of an error SQL + injection vulnerability on the affected parameter. + """ + query = agent.prefixQuery(" %s" % temp.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 + + expressionUnescaped = unescaper.unescape(expression) + + debugMsg = "query: %s" % expressionUnescaped + logger.debug(debugMsg) + + forgedPayload = safeStringFormat(payload, expressionUnescaped) + result = Request.queryPage(urlencode(forgedPayload), content=True) + + match = re.search(temp.errorRegex, result[0], re.DOTALL | re.IGNORECASE) + + if match: + output = match.group('result') + + return output + + +def getValue(expression, blind=True, inband=True, error=False, 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 affected parameter. It can call a function to retrieve the output @@ -337,7 +373,7 @@ def getValue(expression, blind=True, inband=True, fromUser=False, expected=None, if suppressOutput: pushValue(conf.verbose) conf.verbose = 0 - + if conf.direct: value = direct(expression) else: @@ -347,7 +383,16 @@ def getValue(expression, blind=True, inband=True, fromUser=False, expected=None, expression = expression.replace("DISTINCT ", "") - if inband and kb.unionPosition: + if error: + value = __goError(expression) + + if not value: + warnMsg = "for some reasons it was not possible to retrieve " + warnMsg += "the query output through error SQL injection " + warnMsg += "technique, sqlmap is going %s" % ("inband" if inband and kb.unionPosition else "blind") + logger.warn(warnMsg) + + if inband and kb.unionPosition and not value: value = __goInband(expression, expected, sort, resumeValue, unpack, dump) if not value: diff --git a/plugins/generic/enumeration.py b/plugins/generic/enumeration.py index 1d7b43f5e..e4ac725cd 100644 --- a/plugins/generic/enumeration.py +++ b/plugins/generic/enumeration.py @@ -64,6 +64,8 @@ class Enumeration: kb.data.dumpedTable = {} temp.inference = queries[dbms].inference + temp.error = queries[dbms].error + temp.errorRegex = queries[dbms].errorRegex def getBanner(self): if not conf.getBanner: diff --git a/xml/queries.xml b/xml/queries.xml index d0191ce4d..a19634016 100644 --- a/xml/queries.xml +++ b/xml/queries.xml @@ -91,7 +91,7 @@ - +