From 30d679196863dc4f3fe0955f99566b78cb072b66 Mon Sep 17 00:00:00 2001 From: Miroslav Stampar Date: Sun, 16 Jan 2011 17:52:42 +0000 Subject: [PATCH] update regarding time based data retrieval --- lib/core/common.py | 29 ++++++++++++++++++++--------- lib/core/option.py | 2 ++ lib/core/settings.py | 12 +++++++++--- lib/parse/cmdline.py | 3 ++- lib/request/inject.py | 4 +++- lib/techniques/blind/inference.py | 9 +++++++-- 6 files changed, 43 insertions(+), 16 deletions(-) diff --git a/lib/core/common.py b/lib/core/common.py index 739758233..702facfbe 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -73,6 +73,7 @@ from lib.core.settings import DUMP_TAB_MARKER from lib.core.settings import DUMP_START_MARKER from lib.core.settings import DUMP_STOP_MARKER from lib.core.settings import MIN_TIME_RESPONSES +from lib.core.settings import TIME_DEFAULT_DELAY from lib.core.settings import TIME_STDEV_COEFF from lib.core.settings import DYNAMICITY_MARK_LENGTH from lib.core.threads import getCurrentThreadData @@ -1588,21 +1589,31 @@ def wasLastRequestDelayed(): warnMsg += "with less than %d response times" % MIN_TIME_RESPONSES logger.warn(warnMsg) - lowerLimit = average(kb.responseTimes) + TIME_STDEV_COEFF * deviation - retVal = (threadData.lastQueryDuration >= lowerLimit) + lowerStdLimit = average(kb.responseTimes) + TIME_STDEV_COEFF * deviation + retVal = (threadData.lastQueryDuration >= lowerStdLimit) - if not kb.testMode and retVal: - newVal = int(ceil((1 - (threadData.lastQueryDuration - lowerLimit) / threadData.lastQueryDuration) * conf.timeSec)) - if newVal and newVal != conf.timeSec: - clearConsoleLine(True) - warnMsg = "adjusting time delay to %d seconds" % newVal - logger.warn(warnMsg) - conf.timeSec = newVal + if not kb.testMode and retVal and conf.timeSec == TIME_DEFAULT_DELAY: + adjustTimeDelay(threadData.lastQueryDuration, lowerStdLimit) return retVal else: return threadData.lastQueryDuration - conf.timeSec +def adjustTimeDelay(lastQueryDuration, lowerStdLimit): + """ + Adjusts time delay in time based data retrieval + """ + + candidate = 1 + int(ceil((1 - (lastQueryDuration - lowerStdLimit) / lastQueryDuration) * conf.timeSec)) + + if candidate: + kb.delayCandidates = [candidate] + kb.delayCandidates[:-1] + if all([x == candidate for x in kb.delayCandidates]) and candidate < conf.timeSec: + clearConsoleLine(True) + warnMsg = "adjusting time delay to %d seconds" % candidate + logger.warn(warnMsg) + conf.timeSec = candidate + def extractErrorMessage(page): """ Returns reported error message from page if it founds one diff --git a/lib/core/option.py b/lib/core/option.py index 19d4e9bc6..5a2fb8706 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -77,6 +77,7 @@ from lib.core.settings import FIREBIRD_ALIASES from lib.core.settings import MAXDB_ALIASES from lib.core.settings import SYBASE_ALIASES from lib.core.settings import UNKNOWN_DBMS_VERSION +from lib.core.settings import TIME_DELAY_CANDIDATES from lib.core.update import update from lib.parse.configfile import configFileParser from lib.parse.payloads import loadPayloads @@ -1116,6 +1117,7 @@ def __setKnowledgeBaseAttributes(flushAll=True): # Active (extensive) back-end DBMS fingerprint kb.dbmsVersion = [ UNKNOWN_DBMS_VERSION ] + kb.delayCandidates = TIME_DELAY_CANDIDATES * [0] kb.dep = None kb.docRoot = None kb.dynamicMarkings = [] diff --git a/lib/core/settings.py b/lib/core/settings.py index b19843fa0..7996addf7 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -56,16 +56,22 @@ CHAR_INFERENCE_MARK = "%c" NON_CONTROL_CHAR_REGEX = r'[^\x00-\x1f]' # coefficient used for a time-based query delay checking (must be >= 7) -TIME_STDEV_COEFF = 10 +TIME_STDEV_COEFF = 10 + +# length of queue for candidates for time delay adjustment +TIME_DELAY_CANDIDATES = 3 + +# default time delay in seconds +TIME_DEFAULT_DELAY = 5 # maximum number of techniques used in inject.py/getValue() per one value MAX_TECHNIQUES_PER_VALUE = 2 # suffix used for naming meta databases in DBMS(es) without explicit database name -METADB_SUFFIX = "_masterdb" +METADB_SUFFIX = "_masterdb" # minimum time response set needed for time-comparison based on standard deviation -MIN_TIME_RESPONSES = 15 +MIN_TIME_RESPONSES = 15 # after these number of blanks at the end inference should stop (just in case) INFERENCE_BLANK_BREAK = 10 diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index ee64a88fe..87d3baa13 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -16,6 +16,7 @@ from optparse import SUPPRESS_HELP from lib.core.convert import utf8decode from lib.core.data import logger +from lib.core.settings import TIME_DEFAULT_DELAY from lib.core.settings import VERSION_STRING def cmdLineParser(): @@ -223,7 +224,7 @@ def cmdLineParser(): "the default blind SQL injection technique.") techniques.add_option("--time-sec", dest="timeSec", - type="int", default=5, + type="int", default=TIME_DEFAULT_DELAY, help="Seconds to delay the DBMS response " "(default 5)") diff --git a/lib/request/inject.py b/lib/request/inject.py index 8dc1cf43c..99b9fea8b 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -49,7 +49,9 @@ from lib.utils.resume import resume def __goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None): start = time.time() - if ( conf.eta or conf.threads > 1 ) and getIdentifiedDBMS(): + timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) + + if ( conf.eta or conf.threads > 1 ) and getIdentifiedDBMS() and not timeBasedCompare: _, length, _ = queryOutputLength(expression, payload) else: length = None diff --git a/lib/techniques/blind/inference.py b/lib/techniques/blind/inference.py index 3615989e2..77c2aeec6 100644 --- a/lib/techniques/blind/inference.py +++ b/lib/techniques/blind/inference.py @@ -99,8 +99,13 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None progressTime = [] if numThreads > 1: - debugMsg = "starting %d thread%s" % (numThreads, ("s" if numThreads > 1 else "")) - logger.debug(debugMsg) + if not timeBasedCompare: + debugMsg = "starting %d thread%s" % (numThreads, ("s" if numThreads > 1 else "")) + logger.debug(debugMsg) + else: + debugMsg = "multi-threading is not considered safe in time-based data retrieval" + logger.debug(debugMsg) + numThreads = 1 if conf.verbose in (1, 2) and not showEta: if isinstance(length, int) and conf.threads > 1: