diff --git a/lib/controller/checks.py b/lib/controller/checks.py index 8d5d3569a..e5babab32 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -14,6 +14,7 @@ import time from difflib import SequenceMatcher from lib.core.agent import agent +from lib.core.common import average from lib.core.common import beep from lib.core.common import calculateDeltaSeconds from lib.core.common import extractRegexResult @@ -45,7 +46,8 @@ from lib.core.exception import sqlmapSiteTooDynamic from lib.core.exception import sqlmapUserQuitException from lib.core.session import setString from lib.core.session import setRegexp -from lib.core.settings import TIME_MIN_DELTA +from lib.core.settings import MIN_DURATION_RATIO +from lib.core.settings import TIME_TOLERANCE from lib.request.connect import Connect as Request from lib.request.templates import getPageTemplate from plugins.dbms.firebird.syntax import Syntax as Firebird @@ -352,23 +354,17 @@ def checkSqlInjection(place, parameter, value): # Perform the test's request and check how long # it takes to get the response back start = time.time() - _ = Request.queryPage(reqPayload, place) + _ = Request.queryPage(reqPayload, place, noteResponseTime = False) duration = calculateDeltaSeconds(start) - - trueResult = (check.isdigit() and duration >= int(check)) or (check == "[DELAYED]" and duration >= max(TIME_MIN_DELTA, kb.responseTime)) + + trueResult = (check.isdigit() and abs(duration - int(check) - average(kb.responseTimes)) < TIME_TOLERANCE)\ + or (check == "[DELAYED]" and duration >= MIN_DURATION_RATIO * max(kb.responseTimes)) if trueResult: - start = time.time() - _ = Request.queryPage(reqPayload, place) - duration = calculateDeltaSeconds(start) + infoMsg = "%s parameter '%s' is '%s' injectable " % (place, parameter, title) + logger.info(infoMsg) - trueResult = (check.isdigit() and duration >= int(check)) or (check == "[DELAYED]" and duration >= max(TIME_MIN_DELTA, kb.responseTime)) - - if trueResult: - infoMsg = "%s parameter '%s' is '%s' injectable " % (place, parameter, title) - logger.info(infoMsg) - - injectable = True + injectable = True # Restore value of socket timeout socket.setdefaulttimeout(popValue()) @@ -763,9 +759,7 @@ def checkConnection(suppressOutput=False): logger.info(infoMsg) try: - start = time.time() page, _ = Request.queryPage(content=True) - kb.responseTime = time.time() - start kb.originalPage = kb.pageTemplate = page except sqlmapConnectionException, errMsg: errMsg = getUnicode(errMsg) diff --git a/lib/core/common.py b/lib/core/common.py index ef085000f..f78030b75 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1276,12 +1276,17 @@ def readXmlFile(xmlFile): xfile.close() return retVal -def calculateDeltaSeconds(start, epsilon=0.1): +def average(values): """ - Returns elapsed time from start till now (including expected - error set by epsilon parameter) + Computes the arithmetic mean of a list of numbers. """ - return time.time() - start - kb.responseTime + epsilon + return sum(values, 0.0) / len(values) + +def calculateDeltaSeconds(start): + """ + Returns elapsed time from start till now + """ + return time.time() - start def initCommonOutputs(): kb.commonOutputs = {} diff --git a/lib/core/option.py b/lib/core/option.py index 6c26c23a2..69d888f65 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -1173,7 +1173,7 @@ def __setKnowledgeBaseAttributes(): kb.proxyAuthHeader = None kb.queryCounter = 0 kb.redirectSetCookie = None - kb.responseTime = 0 + kb.responseTimes = [] kb.resumedQueries = {} kb.retriesCount = 0 kb.tamperFunctions = [] diff --git a/lib/core/settings.py b/lib/core/settings.py index b6168d086..b4dedbfdb 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -48,8 +48,9 @@ DUMP_STOP_MARKER = "__STOP__" PAYLOAD_DELIMITER = "\x00" -# minimum difference of loading time in seconds for delayed time payloads -TIME_MIN_DELTA = 2 +# time testing settings +TIME_TOLERANCE = 0.5 +MIN_DURATION_RATIO = 1.5 # System variables IS_WIN = subprocess.mswindows diff --git a/lib/request/connect.py b/lib/request/connect.py index c0332f753..8850f5541 100644 --- a/lib/request/connect.py +++ b/lib/request/connect.py @@ -320,7 +320,7 @@ class Connect: return page, responseHeaders @staticmethod - def queryPage(value=None, place=None, content=False, getSeqMatcher=False, silent=False, method=None, auxHeaders=None, response=False, raise404 = None): + def queryPage(value=None, place=None, content=False, getSeqMatcher=False, silent=False, method=None, auxHeaders=None, response=False, raise404 = None, noteResponseTime = True): """ This method calls a function to get the target url page content and returns its page MD5 hash or a boolean value in case of @@ -339,6 +339,7 @@ class Connect: uri = None raise404 = place != PLACE.URI if raise404 is None else raise404 toUrlencode = { PLACE.GET: True, PLACE.POST: True, PLACE.COOKIE: conf.cookieUrlencode, PLACE.UA: True, PLACE.URI: False } + start = time.time() if not place: place = kb.injection.place @@ -412,6 +413,9 @@ class Connect: if conf.cj: conf.cj.clear() + if noteResponseTime: + kb.responseTimes.append(time.time() - start) + if content or response: return page, headers elif getSeqMatcher: