Another (better) patch for #1636

This commit is contained in:
Miroslav Stampar 2016-01-09 17:32:19 +01:00
parent 0f8a551227
commit 5908964db4
7 changed files with 37 additions and 37 deletions

View File

@ -2222,16 +2222,16 @@ def wasLastResponseDelayed():
# response times should be inside +-7*stdev([normal response times]) # response times should be inside +-7*stdev([normal response times])
# Math reference: http://www.answers.com/topic/standard-deviation # Math reference: http://www.answers.com/topic/standard-deviation
deviation = stdev(kb.responseTimes) deviation = stdev(kb.responseTimes.get(kb.responseTimeMode, []))
threadData = getCurrentThreadData() threadData = getCurrentThreadData()
if deviation and not conf.direct: if deviation and not conf.direct:
if len(kb.responseTimes) < MIN_TIME_RESPONSES: if len(kb.responseTimes[kb.responseTimeMode]) < MIN_TIME_RESPONSES:
warnMsg = "time-based standard deviation method used on a model " warnMsg = "time-based standard deviation method used on a model "
warnMsg += "with less than %d response times" % MIN_TIME_RESPONSES warnMsg += "with less than %d response times" % MIN_TIME_RESPONSES
logger.warn(warnMsg) logger.warn(warnMsg)
lowerStdLimit = average(kb.responseTimes) + TIME_STDEV_COEFF * deviation lowerStdLimit = average(kb.responseTimes[kb.responseTimeMode]) + TIME_STDEV_COEFF * deviation
retVal = (threadData.lastQueryDuration >= max(MIN_VALID_DELAYED_RESPONSE, lowerStdLimit)) retVal = (threadData.lastQueryDuration >= max(MIN_VALID_DELAYED_RESPONSE, lowerStdLimit))
if not kb.testMode and retVal: if not kb.testMode and retVal:

View File

@ -1891,7 +1891,9 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.reflectiveCounters = {REFLECTIVE_COUNTER.MISS: 0, REFLECTIVE_COUNTER.HIT: 0} kb.reflectiveCounters = {REFLECTIVE_COUNTER.MISS: 0, REFLECTIVE_COUNTER.HIT: 0}
kb.requestCounter = 0 kb.requestCounter = 0
kb.resendPostOnRedirect = None kb.resendPostOnRedirect = None
kb.responseTimes = [] kb.responseTimes = {}
kb.responseTimeMode = None
kb.responseTimePayload = None
kb.resumeValues = True kb.resumeValues = True
kb.safeCharEncode = False kb.safeCharEncode = False
kb.safeReq = AttribDict() kb.safeReq = AttribDict()
@ -1915,7 +1917,6 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.timeValidCharsRun = 0 kb.timeValidCharsRun = 0
kb.uChar = NULL kb.uChar = NULL
kb.unionDuplicates = False kb.unionDuplicates = False
kb.whereCollectTimes = False
kb.xpCmdshellAvailable = False kb.xpCmdshellAvailable = False
if flushAll: if flushAll:

View File

@ -61,6 +61,9 @@ URI_QUESTION_MARKER = "__QUESTION_MARK__"
ASTERISK_MARKER = "__ASTERISK_MARK__" ASTERISK_MARKER = "__ASTERISK_MARK__"
REPLACEMENT_MARKER = "__REPLACEMENT_MARK__" REPLACEMENT_MARKER = "__REPLACEMENT_MARK__"
RANDOM_INTEGER_MARKER = "[RANDINT]"
RANDOM_STRING_MARKER = "[RANDSTR]"
PAYLOAD_DELIMITER = "__PAYLOAD_DELIMITER__" PAYLOAD_DELIMITER = "__PAYLOAD_DELIMITER__"
CHAR_INFERENCE_MARK = "%c" CHAR_INFERENCE_MARK = "%c"
PRINTABLE_CHAR_REGEX = r"[^\x00-\x1f\x7f-\xff]" PRINTABLE_CHAR_REGEX = r"[^\x00-\x1f\x7f-\xff]"

View File

@ -97,6 +97,8 @@ from lib.core.settings import LARGE_CHUNK_TRIM_MARKER
from lib.core.settings import PAYLOAD_DELIMITER from lib.core.settings import PAYLOAD_DELIMITER
from lib.core.settings import PERMISSION_DENIED_REGEX from lib.core.settings import PERMISSION_DENIED_REGEX
from lib.core.settings import PLAIN_TEXT_CONTENT_TYPE from lib.core.settings import PLAIN_TEXT_CONTENT_TYPE
from lib.core.settings import RANDOM_INTEGER_MARKER
from lib.core.settings import RANDOM_STRING_MARKER
from lib.core.settings import REPLACEMENT_MARKER from lib.core.settings import REPLACEMENT_MARKER
from lib.core.settings import TEXT_CONTENT_TYPE_REGEX from lib.core.settings import TEXT_CONTENT_TYPE_REGEX
from lib.core.settings import UNENCODED_ORIGINAL_VALUE from lib.core.settings import UNENCODED_ORIGINAL_VALUE
@ -1020,34 +1022,37 @@ class Connect(object):
post = urlencode(post, spaceplus=kb.postSpaceToPlus) post = urlencode(post, spaceplus=kb.postSpaceToPlus)
if timeBasedCompare: if timeBasedCompare:
if len(kb.responseTimes) < MIN_TIME_RESPONSES: if len(kb.responseTimes.get(kb.responseTimeMode, [])) < MIN_TIME_RESPONSES:
clearConsoleLine() clearConsoleLine()
kb.responseTimes.setdefault(kb.responseTimeMode, [])
if conf.tor: if conf.tor:
warnMsg = "it's highly recommended to avoid usage of switch '--tor' for " warnMsg = "it's highly recommended to avoid usage of switch '--tor' for "
warnMsg += "time-based injections because of its high latency time" warnMsg += "time-based injections because of its high latency time"
singleTimeWarnMessage(warnMsg) singleTimeWarnMessage(warnMsg)
warnMsg = "[%s] [WARNING] time-based comparison requires " % time.strftime("%X") warnMsg = "[%s] [WARNING] %stime-based comparison requires " % (time.strftime("%X"), "(case) " if kb.responseTimeMode else "")
warnMsg += "larger statistical model, please wait" warnMsg += "larger statistical model, please wait"
dataToStdout(warnMsg) dataToStdout(warnMsg)
while len(kb.responseTimes) < MIN_TIME_RESPONSES: while len(kb.responseTimes[kb.responseTimeMode]) < MIN_TIME_RESPONSES:
Connect.queryPage(content=True) value = kb.responseTimePayload.replace(RANDOM_INTEGER_MARKER, str(randomInt(6))).replace(RANDOM_STRING_MARKER, randomStr()) if kb.responseTimePayload else kb.responseTimePayload
Connect.queryPage(value=value, content=True, raise404=False)
dataToStdout('.') dataToStdout('.')
dataToStdout("\n") dataToStdout(" (done)\n")
elif not kb.testMode: elif not kb.testMode:
warnMsg = "it is very important not to stress the network adapter " warnMsg = "it is very important to not stress the network adapter "
warnMsg += "during usage of time-based payloads to prevent potential " warnMsg += "during usage of time-based payloads to prevent potential "
warnMsg += "errors " warnMsg += "disruptions "
singleTimeWarnMessage(warnMsg) singleTimeWarnMessage(warnMsg)
if not kb.laggingChecked: if not kb.laggingChecked:
kb.laggingChecked = True kb.laggingChecked = True
deviation = stdev(kb.responseTimes) deviation = stdev(kb.responseTimes[kb.responseTimeMode])
if deviation > WARN_TIME_STDEV: if deviation > WARN_TIME_STDEV:
kb.adjustTimeDelay = ADJUST_TIME_DELAY.DISABLE kb.adjustTimeDelay = ADJUST_TIME_DELAY.DISABLE
@ -1115,7 +1120,8 @@ class Connect(object):
if timeBasedCompare: if timeBasedCompare:
return wasLastResponseDelayed() return wasLastResponseDelayed()
elif noteResponseTime: elif noteResponseTime:
kb.responseTimes.append(threadData.lastQueryDuration) kb.responseTimes.setdefault(kb.responseTimeMode, [])
kb.responseTimes[kb.responseTimeMode].append(threadData.lastQueryDuration)
if not response and removeReflection: if not response and removeReflection:
page = removeReflectiveValues(page, payload) page = removeReflectiveValues(page, payload)

View File

@ -432,6 +432,8 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE found = (value is not None) or (value is None and expectingNone) or count >= MAX_TECHNIQUES_PER_VALUE
if time and (isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED)) and not found: if time and (isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME) or isTechniqueAvailable(PAYLOAD.TECHNIQUE.STACKED)) and not found:
kb.responseTimeMode = re.sub(r"(?i)[^a-z]", "", re.sub(r"'[^']+'", "", expression)) if re.search(r"(?i)SELECT.+FROM", expression) else None
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME): if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME):
kb.technique = PAYLOAD.TECHNIQUE.TIME kb.technique = PAYLOAD.TECHNIQUE.TIME
else: else:
@ -441,7 +443,6 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
value = _goBooleanProxy(booleanExpression) value = _goBooleanProxy(booleanExpression)
else: else:
value = _goInferenceProxy(query, fromUser, batch, unpack, charsetType, firstChar, lastChar, dump) value = _goInferenceProxy(query, fromUser, batch, unpack, charsetType, firstChar, lastChar, dump)
else: else:
errMsg = "none of the injection types identified can be " errMsg = "none of the injection types identified can be "
errMsg += "leveraged to retrieve queries output" errMsg += "leveraged to retrieve queries output"
@ -449,6 +450,7 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
finally: finally:
kb.resumeValues = True kb.resumeValues = True
kb.responseTimeMode = None
conf.tbl = popValue() conf.tbl = popValue()
conf.db = popValue() conf.db = popValue()

View File

@ -47,8 +47,10 @@ from lib.core.settings import INFERENCE_NOT_EQUALS_CHAR
from lib.core.settings import MIN_TIME_RESPONSES from lib.core.settings import MIN_TIME_RESPONSES
from lib.core.settings import MAX_BISECTION_LENGTH from lib.core.settings import MAX_BISECTION_LENGTH
from lib.core.settings import MAX_TIME_REVALIDATION_STEPS from lib.core.settings import MAX_TIME_REVALIDATION_STEPS
from lib.core.settings import NULL
from lib.core.settings import PARTIAL_HEX_VALUE_MARKER from lib.core.settings import PARTIAL_HEX_VALUE_MARKER
from lib.core.settings import PARTIAL_VALUE_MARKER from lib.core.settings import PARTIAL_VALUE_MARKER
from lib.core.settings import RANDOM_INTEGER_MARKER
from lib.core.settings import VALID_TIME_CHARS_RUN_THRESHOLD from lib.core.settings import VALID_TIME_CHARS_RUN_THRESHOLD
from lib.core.threads import getCurrentThreadData from lib.core.threads import getCurrentThreadData
from lib.core.threads import runThreads from lib.core.threads import runThreads
@ -261,29 +263,23 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
while len(charTbl) != 1: while len(charTbl) != 1:
position = (len(charTbl) >> 1) position = (len(charTbl) >> 1)
posValue = charTbl[position] posValue = charTbl[position]
falsePayload = None
if "'%s'" % CHAR_INFERENCE_MARK not in payload: if "'%s'" % CHAR_INFERENCE_MARK not in payload:
forgedPayload = safeStringFormat(payload, (expressionUnescaped, idx, posValue)) forgedPayload = safeStringFormat(payload, (expressionUnescaped, idx, posValue))
falsePayload = safeStringFormat(payload, (expressionUnescaped, idx, RANDOM_INTEGER_MARKER))
else: else:
# e.g.: ... > '%c' -> ... > ORD(..) # e.g.: ... > '%c' -> ... > ORD(..)
markingValue = "'%s'" % CHAR_INFERENCE_MARK markingValue = "'%s'" % CHAR_INFERENCE_MARK
unescapedCharValue = unescaper.escape("'%s'" % decodeIntToUnicode(posValue)) unescapedCharValue = unescaper.escape("'%s'" % decodeIntToUnicode(posValue))
forgedPayload = safeStringFormat(payload, (expressionUnescaped, idx)).replace(markingValue, unescapedCharValue) forgedPayload = safeStringFormat(payload, (expressionUnescaped, idx)).replace(markingValue, unescapedCharValue)
falsePayload = safeStringFormat(payload, (expressionUnescaped, idx)).replace(markingValue, NULL)
if timeBasedCompare and kb.whereCollectTimes: if timeBasedCompare:
kb.responseTimes = [] if kb.responseTimeMode:
kb.responseTimePayload = falsePayload
warnMsg = "\n[%s] [WARNING] time-based comparison requires " % time.strftime("%X") else:
warnMsg += "larger statistical model, please wait" kb.responseTimePayload = None
dataToStdout(warnMsg)
while len(kb.responseTimes) < MIN_TIME_RESPONSES:
falseWherePayload = re.sub(r"\b%s\b" % posValue, str(randomInt(6)), forgedPayload)
Request.queryPage(falseWherePayload, content=True, raise404=False)
dataToStdout('.')
dataToStdout("\n")
kb.whereCollectTimes = False
result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False) result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique) incrementCounter(kb.technique)

View File

@ -236,10 +236,6 @@ class Entries:
query = whereQuery(query) query = whereQuery(query)
if conf.dumpWhere:
kb.whereCollectTimes = True
pushValue(kb.responseTimes)
count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
lengths = {} lengths = {}
@ -328,10 +324,6 @@ class Entries:
warnMsg = "Ctrl+C detected in dumping phase" warnMsg = "Ctrl+C detected in dumping phase"
logger.warn(warnMsg) logger.warn(warnMsg)
if conf.dumpWhere:
kb.responseTimes = popValue()
kb.whereCollectTimes = False
for column, columnEntries in entries.items(): for column, columnEntries in entries.items():
length = max(lengths[column], len(column)) length = max(lengths[column], len(column))