From 194a9e7b88933d6ba941d229062c44ce09022207 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Fri, 25 Jan 2013 12:34:57 +0100 Subject: [PATCH] Implementation for an Issue #377 --- lib/controller/checks.py | 48 ++++++++++++++++++++++++++++++++++------ lib/core/common.py | 1 + lib/core/option.py | 1 + lib/core/settings.py | 3 +++ 4 files changed, 46 insertions(+), 7 deletions(-) diff --git a/lib/controller/checks.py b/lib/controller/checks.py index e9c387b41..3af3adc4a 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -22,6 +22,7 @@ from lib.core.common import extractTextTagContent from lib.core.common import findDynamicContent from lib.core.common import Format from lib.core.common import getLastRequestHTTPError +from lib.core.common import getPublicTypeMembers from lib.core.common import getSortedInjectionTests from lib.core.common import getUnicode from lib.core.common import intersect @@ -42,6 +43,8 @@ from lib.core.data import kb from lib.core.data import logger from lib.core.datatype import AttribDict from lib.core.datatype import InjectionDict +from lib.core.dicts import FROM_DUMMY_TABLE +from lib.core.enums import DBMS from lib.core.enums import HEURISTIC_TEST from lib.core.enums import HTTPHEADER from lib.core.enums import HTTPMETHOD @@ -55,7 +58,7 @@ from lib.core.exception import SqlmapUserQuitException from lib.core.settings import FORMAT_EXCEPTION_STRINGS from lib.core.settings import HEURISTIC_CHECK_ALPHABET from lib.core.settings import SUHOSIN_MAX_VALUE_LENGTH -from lib.core.settings import UNKNOWN_DBMS_VERSION +from lib.core.settings import UNKNOWN_DBMS from lib.core.settings import LOWER_RATIO_BOUND from lib.core.settings import UPPER_RATIO_BOUND from lib.core.settings import IDS_WAF_CHECK_PAYLOAD @@ -441,11 +444,21 @@ def checkSqlInjection(place, parameter, value): configUnion(test.request.char, test.request.columns) if not Backend.getIdentifiedDbms(): - warnMsg = "using unescaped version of the test " - warnMsg += "because of zero knowledge of the " - warnMsg += "back-end DBMS. You can try to " - warnMsg += "explicitly set it using option '--dbms'" - singleTimeWarnMessage(warnMsg) + if not kb.heuristicDbms: + kb.heuristicDbms = heuristicCheckDbms(injection) or UNKNOWN_DBMS + + if kb.heuristicDbms == UNKNOWN_DBMS: + warnMsg = "using unescaped version of the test " + warnMsg += "because of zero knowledge of the " + warnMsg += "back-end DBMS. You can try to " + warnMsg += "explicitly set it using option '--dbms'" + singleTimeWarnMessage(warnMsg) + else: + warnMsg = "heuristic test showed that the back-end DBMS " + warnMsg += "could be '%s' " % kb.heuristicDbms + singleTimeWarnMessage(warnMsg) + + Backend.forceDbms(kb.heuristicDbms) if unionExtended: infoMsg = "automatically extending ranges " @@ -582,6 +595,27 @@ def checkSqlInjection(place, parameter, value): return injection +def heuristicCheckDbms(injection): + retVal = None + + if not Backend.getIdentifiedDbms() and len(injection.data) == 1 and PAYLOAD.TECHNIQUE.BOOLEAN in injection.data: + pushValue(kb.injection) + kb.injection = injection + randStr1, randStr2 = randomStr(), randomStr() + + for dbms in getPublicTypeMembers(DBMS, True): + Backend.forceDbms(dbms) + + if checkBooleanExpression("(SELECT '%s'%s)='%s'" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), randStr1)): + if not checkBooleanExpression("(SELECT '%s'%s)='%s'" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), randStr2)): + retVal = dbms + break + + Backend.flushForcedDbms() + kb.injection = popValue() + + return retVal + def checkFalsePositives(injection): """ Checks for false positives (only in single special cases) @@ -723,7 +757,7 @@ def heuristicCheckSqlInjection(place, parameter): kb.ignoreCasted = readInput(message, default='Y' if conf.multipleTargets else 'N').upper() != 'N' elif result: - infoMsg += "be injectable (possible DBMS: %s)" % (Format.getErrorParsedDBMSes() or UNKNOWN_DBMS_VERSION) + infoMsg += "be injectable (possible DBMS: %s)" % (Format.getErrorParsedDBMSes() or UNKNOWN_DBMS) logger.info(infoMsg) else: diff --git a/lib/core/common.py b/lib/core/common.py index 141eda6b4..9d19ff8b9 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -122,6 +122,7 @@ from lib.core.settings import SUPPORTED_DBMS from lib.core.settings import TEXT_TAG_REGEX from lib.core.settings import TIME_STDEV_COEFF from lib.core.settings import UNICODE_ENCODING +from lib.core.settings import UNKNOWN_DBMS from lib.core.settings import UNKNOWN_DBMS_VERSION from lib.core.settings import URI_QUESTION_MARKER from lib.core.settings import URLENCODE_CHAR_LIMIT diff --git a/lib/core/option.py b/lib/core/option.py index b40027877..f5579dc64 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -1526,6 +1526,7 @@ def _setKnowledgeBaseAttributes(flushAll=True): kb.fileReadMode = False kb.forcedDbms = None kb.headersFp = {} + kb.heuristicDbms = None kb.heuristicTest = None kb.hintValue = None kb.htmlFp = [] diff --git a/lib/core/settings.py b/lib/core/settings.py index 873880730..22dc012c6 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -111,6 +111,9 @@ INFERENCE_EQUALS_CHAR = "=" # Character used for operation "not-equals" in inference INFERENCE_NOT_EQUALS_CHAR = "!=" +# String used for representation of unknown dbms +UNKNOWN_DBMS = "Unknown" + # String used for representation of unknown dbms version UNKNOWN_DBMS_VERSION = "Unknown"