gazillion changes, nothing will work, muhahaha

This commit is contained in:
Miroslav Stampar 2012-02-17 14:22:48 +00:00
parent dcf7277a0f
commit aee269cc14
8 changed files with 492 additions and 549 deletions

View File

@ -61,6 +61,7 @@ from lib.core.convert import unicodeencode
from lib.core.convert import urldecode from lib.core.convert import urldecode
from lib.core.convert import urlencode from lib.core.convert import urlencode
from lib.core.enums import DBMS from lib.core.enums import DBMS
from lib.core.enums import EXPECTED
from lib.core.enums import HTTPHEADER from lib.core.enums import HTTPHEADER
from lib.core.enums import HTTPMETHOD from lib.core.enums import HTTPMETHOD
from lib.core.enums import OS from lib.core.enums import OS
@ -2206,10 +2207,10 @@ def trimAlphaNum(value):
def isNumPosStrValue(value): def isNumPosStrValue(value):
""" """
Returns True if value is a string with a positive integer representation Returns True if value is a string (or integer) with a positive integer representation
""" """
return value and isinstance(value, basestring) and value.isdigit() and value != "0" return (value and isinstance(value, basestring) and value.isdigit() and value != "0") or (isinstance(value, int) and value != 0)
@cachedmethod @cachedmethod
def aliasToDbmsEnum(dbms): def aliasToDbmsEnum(dbms):
@ -3096,3 +3097,36 @@ def getCounter(technique):
""" """
return kb.counters.get(technique, 0) return kb.counters.get(technique, 0)
def extractExpectedValue(value, expected):
"""
Extracts and returns expected value by a given type
"""
if not expected:
return value
value = unArrayizeValue(value)
if isNoneValue(value):
value = None
elif expected == EXPECTED.BOOL:
if isinstance(value, int):
value = bool(value)
elif isinstance(value, basestring):
value = value.strip().lower()
if value in ("true", "false"):
value = value == "true"
elif value in ("1", "-1"):
value = True
elif value == "0":
value = False
else:
value = None
elif expected == EXPECTED.INT:
if isinstance(value, basestring):
if value.isdigit():
value = int(value)
else:
value = None
return value

View File

@ -1467,6 +1467,7 @@ 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.responseTimes = [] kb.responseTimes = []
kb.resumedQueries = {} kb.resumedQueries = {}
kb.resumeValues = True
kb.safeCharEncode = False kb.safeCharEncode = False
kb.singleLogFlags = set() kb.singleLogFlags = set()
kb.skipOthersDbms = None kb.skipOthersDbms = None

View File

@ -57,6 +57,8 @@ DUMP_DEL_MARKER = "__DEL__"
PARAMETER_AMP_MARKER = "__AMP__" PARAMETER_AMP_MARKER = "__AMP__"
PARAMETER_SEMICOLON_MARKER = "__SEMICOLON__" PARAMETER_SEMICOLON_MARKER = "__SEMICOLON__"
PARTIAL_VALUE_MARKER = "__PARTIAL__"
URI_QUESTION_MARKER = "__QUESTION_MARK__" URI_QUESTION_MARKER = "__QUESTION_MARK__"
PAYLOAD_DELIMITER = "\x00" PAYLOAD_DELIMITER = "\x00"

View File

@ -17,8 +17,10 @@ from lib.core.common import calculateDeltaSeconds
from lib.core.common import cleanQuery from lib.core.common import cleanQuery
from lib.core.common import dataToSessionFile from lib.core.common import dataToSessionFile
from lib.core.common import expandAsteriskForColumns from lib.core.common import expandAsteriskForColumns
from lib.core.common import extractExpectedValue
from lib.core.common import getPublicTypeMembers from lib.core.common import getPublicTypeMembers
from lib.core.common import initTechnique from lib.core.common import initTechnique
from lib.core.common import isNoneValue
from lib.core.common import isNumPosStrValue from lib.core.common import isNumPosStrValue
from lib.core.common import isTechniqueAvailable from lib.core.common import isTechniqueAvailable
from lib.core.common import parseUnionPage from lib.core.common import parseUnionPage
@ -72,7 +74,7 @@ def __goInference(payload, expression, charsetType=None, firstChar=None, lastCha
return value return value
def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected=None, num=None, resumeValue=True, charsetType=None, firstChar=None, lastChar=None, dump=False): def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected=None, num=None, charsetType=None, firstChar=None, lastChar=None, dump=False):
outputs = [] outputs = []
origExpr = None origExpr = None
@ -91,16 +93,7 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl
else: else:
expressionReplaced = expression.replace(expressionFields, field, 1) expressionReplaced = expression.replace(expressionFields, field, 1)
if resumeValue: output = __goInference(payload, expressionReplaced, charsetType, firstChar, lastChar, dump)
output = resume(expressionReplaced, payload)
if not output or (expected == EXPECTED.INT and not output.isdigit()):
if output:
warnMsg = "expected value type %s, resumed '%s', " % (expected, output)
warnMsg += "sqlmap is going to retrieve the value again"
logger.warn(warnMsg)
output = __goInference(payload, expressionReplaced, charsetType, firstChar, lastChar, dump)
if isinstance(num, int): if isinstance(num, int):
expression = origExpr expression = origExpr
@ -109,7 +102,7 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl
return outputs return outputs
def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, resumeValue=True, unpack=True, charsetType=None, firstChar=None, lastChar=None, dump=False): def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, unpack=True, charsetType=None, firstChar=None, lastChar=None, dump=False):
""" """
Retrieve the output of a SQL query characted by character taking Retrieve the output of a SQL query characted by character taking
advantage of an blind SQL injection vulnerability on the affected advantage of an blind SQL injection vulnerability on the affected
@ -129,14 +122,6 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
untilLimitChar = None untilLimitChar = None
untilOrderChar = None untilOrderChar = None
if resumeValue:
output = resume(expression, payload)
else:
output = None
if output and (expected is None or (expected == EXPECTED.INT and output.isdigit())):
return output
if not unpack: if not unpack:
return __goInference(payload, expression, charsetType, firstChar, lastChar, dump) return __goInference(payload, expression, charsetType, firstChar, lastChar, dump)
@ -229,12 +214,8 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
untilOrderChar = countedExpression.index(" ORDER BY ") untilOrderChar = countedExpression.index(" ORDER BY ")
countedExpression = countedExpression[:untilOrderChar] countedExpression = countedExpression[:untilOrderChar]
if resumeValue:
count = resume(countedExpression, payload)
if not stopLimit: if not stopLimit:
if not count or not count.isdigit(): count = __goInference(payload, countedExpression, 2, firstChar, lastChar)
count = __goInference(payload, countedExpression, 2, firstChar, lastChar)
if isNumPosStrValue(count): if isNumPosStrValue(count):
count = int(count) count = int(count)
@ -298,17 +279,12 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
return None return None
elif (not count or int(count) == 0) and (not stopLimit or stopLimit == 0): elif (not stopLimit or stopLimit == 0):
if not count:
warnMsg = "the SQL query provided does not "
warnMsg += "return any output"
logger.warn(warnMsg)
return None return None
try: try:
for num in xrange(startLimit, stopLimit): for num in xrange(startLimit, stopLimit):
output = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, num, resumeValue=resumeValue, charsetType=charsetType, firstChar=firstChar, lastChar=lastChar, dump=dump) output = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, num, charsetType=charsetType, firstChar=firstChar, lastChar=lastChar, dump=dump)
outputs.append(output) outputs.append(output)
except KeyboardInterrupt: except KeyboardInterrupt:
@ -321,12 +297,12 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
elif Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and expression.upper().startswith("SELECT ") and " FROM " not in expression.upper(): elif Backend.getIdentifiedDbms() in FROM_DUMMY_TABLE and expression.upper().startswith("SELECT ") and " FROM " not in expression.upper():
expression += FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()] expression += FROM_DUMMY_TABLE[Backend.getIdentifiedDbms()]
outputs = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, resumeValue=resumeValue, charsetType=charsetType, firstChar=firstChar, lastChar=lastChar, dump=dump) outputs = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, charsetType=charsetType, firstChar=firstChar, lastChar=lastChar, dump=dump)
returnValue = ", ".join(output for output in outputs) returnValue = ", ".join(output for output in outputs)
return returnValue return returnValue
def __goBooleanProxy(expression, resumeValue=True): def __goBooleanProxy(expression):
""" """
Retrieve the output of a boolean based SQL query Retrieve the output of a boolean based SQL query
""" """
@ -340,54 +316,37 @@ def __goBooleanProxy(expression, resumeValue=True):
payload = agent.payload(newValue=query) payload = agent.payload(newValue=query)
timeBasedCompare = kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED) timeBasedCompare = kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)
if resumeValue: output = conf.hashDB.retrieve(expression) if not any([conf.flushSession, conf.freshQueries, not kb.resumeValues]) else None
output = resume(expression, payload)
else:
output = None
if not output: if not output:
output = Request.queryPage(payload, timeBasedCompare=timeBasedCompare, raise404=False) output = Request.queryPage(payload, timeBasedCompare=timeBasedCompare, raise404=False)
if output is not None:
conf.hashDB.write(expression, output)
return output return output
def __goError(expression, expected=None, resumeValue=True, dump=False): def __goError(expression, expected=None, dump=False):
""" """
Retrieve the output of a SQL query taking advantage of an error-based Retrieve the output of a SQL query taking advantage of an error-based
SQL injection vulnerability on the affected parameter. SQL injection vulnerability on the affected parameter.
""" """
output = None output = errorUse(expression, expected, dump)
if resumeValue:
output = resume(expression, None)
if output and expected == EXPECTED.INT and not output.isdigit():
output = None
if output is None:
output = errorUse(expression, expected, resumeValue, dump)
return output return output
def __goInband(expression, expected=None, unique=True, resumeValue=True, unpack=True, dump=False): def __goInband(expression, expected=None, unique=True, unpack=True, dump=False):
""" """
Retrieve the output of a SQL query taking advantage of an inband SQL Retrieve the output of a SQL query taking advantage of an inband SQL
injection vulnerability on the affected parameter. injection vulnerability on the affected parameter.
""" """
output = None output = unionUse(expression, unpack=unpack, dump=dump)
partial = False if isinstance(output, basestring):
data = None output = parseUnionPage(output, unique)
if output is None: return output
output = unionUse(expression, unpack=unpack, dump=dump)
if isinstance(output, list):
data = output
else:
data = parseUnionPage(output, unique)
return data
def getValue(expression, blind=True, inband=True, error=True, time=True, fromUser=False, expected=None, batch=False, unpack=True, unique=True, resumeValue=True, charsetType=None, firstChar=None, lastChar=None, dump=False, suppressOutput=None, expectingNone=False, safeCharEncode=True): def getValue(expression, blind=True, inband=True, error=True, time=True, fromUser=False, expected=None, batch=False, unpack=True, unique=True, resumeValue=True, charsetType=None, firstChar=None, lastChar=None, dump=False, suppressOutput=None, expectingNone=False, safeCharEncode=True):
""" """
@ -398,6 +357,7 @@ def getValue(expression, blind=True, inband=True, error=True, time=True, fromUse
""" """
kb.safeCharEncode = safeCharEncode kb.safeCharEncode = safeCharEncode
kb.resumeValues = resumeValue
if suppressOutput is not None: if suppressOutput is not None:
pushValue(getCurrentThreadData().disableStdOut) pushValue(getCurrentThreadData().disableStdOut)
@ -433,9 +393,9 @@ def getValue(expression, blind=True, inband=True, error=True, time=True, fromUse
kb.technique = PAYLOAD.TECHNIQUE.UNION kb.technique = PAYLOAD.TECHNIQUE.UNION
if expected == EXPECTED.BOOL: if expected == EXPECTED.BOOL:
value = __goInband(forgeCaseExpression, expected, unique, resumeValue, unpack, dump) value = __goInband(forgeCaseExpression, expected, unique, unpack, dump)
else: else:
value = __goInband(query, expected, unique, resumeValue, unpack, dump) value = __goInband(query, expected, unique, unpack, dump)
count += 1 count += 1
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
@ -444,9 +404,9 @@ def getValue(expression, blind=True, inband=True, error=True, time=True, fromUse
kb.technique = PAYLOAD.TECHNIQUE.ERROR kb.technique = PAYLOAD.TECHNIQUE.ERROR
if expected == EXPECTED.BOOL: if expected == EXPECTED.BOOL:
value = __goError(forgeCaseExpression, expected, resumeValue, dump) value = __goError(forgeCaseExpression, expected, dump)
else: else:
value = __goError(query, expected, resumeValue, dump) value = __goError(query, expected, dump)
count += 1 count += 1
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
@ -455,9 +415,9 @@ def getValue(expression, blind=True, inband=True, error=True, time=True, fromUse
kb.technique = PAYLOAD.TECHNIQUE.BOOLEAN kb.technique = PAYLOAD.TECHNIQUE.BOOLEAN
if expected == EXPECTED.BOOL: if expected == EXPECTED.BOOL:
value = __goBooleanProxy(booleanExpression, resumeValue) value = __goBooleanProxy(booleanExpression)
else: else:
value = __goInferenceProxy(query, fromUser, expected, batch, resumeValue, unpack, charsetType, firstChar, lastChar, dump) value = __goInferenceProxy(query, fromUser, expected, batch, unpack, charsetType, firstChar, lastChar, dump)
count += 1 count += 1
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
@ -469,9 +429,9 @@ def getValue(expression, blind=True, inband=True, error=True, time=True, fromUse
kb.technique = PAYLOAD.TECHNIQUE.STACKED kb.technique = PAYLOAD.TECHNIQUE.STACKED
if expected == EXPECTED.BOOL: if expected == EXPECTED.BOOL:
value = __goBooleanProxy(booleanExpression, resumeValue) value = __goBooleanProxy(booleanExpression)
else: else:
value = __goInferenceProxy(query, fromUser, expected, batch, resumeValue, unpack, charsetType, firstChar, lastChar, dump) value = __goInferenceProxy(query, fromUser, expected, batch, unpack, charsetType, firstChar, lastChar, dump)
if value and isinstance(value, basestring): if value and isinstance(value, basestring):
value = value.strip() value = value.strip()
@ -481,28 +441,13 @@ def getValue(expression, blind=True, inband=True, error=True, time=True, fromUse
raise sqlmapNotVulnerableException, errMsg raise sqlmapNotVulnerableException, errMsg
finally: finally:
kb.resumeValues = True
if suppressOutput is not None: if suppressOutput is not None:
getCurrentThreadData().disableStdOut = popValue() getCurrentThreadData().disableStdOut = popValue()
if value and expected == EXPECTED.BOOL:
if isinstance(value, basestring):
value = value.strip().lower()
if value in ("true", "false"):
value = value == "true"
elif value in ("1", "-1"):
value = True
elif value == "0":
value = False
else:
value = None
elif isinstance(value, int):
value = bool(value)
elif value == [None]:
value = None
kb.safeCharEncode = False kb.safeCharEncode = False
return value return extractExpectedValue(value, expected)
def goStacked(expression, silent=False): def goStacked(expression, silent=False):
kb.technique = PAYLOAD.TECHNIQUE.STACKED kb.technique = PAYLOAD.TECHNIQUE.STACKED

View File

@ -13,7 +13,6 @@ import traceback
from lib.core.agent import agent from lib.core.agent import agent
from lib.core.common import Backend from lib.core.common import Backend
from lib.core.common import dataToSessionFile
from lib.core.common import dataToStdout from lib.core.common import dataToStdout
from lib.core.common import decodeIntToUnicode from lib.core.common import decodeIntToUnicode
from lib.core.common import filterControlChars from lib.core.common import filterControlChars
@ -46,6 +45,7 @@ from lib.core.settings import INFERENCE_GREATER_CHAR
from lib.core.settings import INFERENCE_EQUALS_CHAR from lib.core.settings import INFERENCE_EQUALS_CHAR
from lib.core.settings import INFERENCE_NOT_EQUALS_CHAR from lib.core.settings import INFERENCE_NOT_EQUALS_CHAR
from lib.core.settings import MAX_TIME_REVALIDATION_STEPS from lib.core.settings import MAX_TIME_REVALIDATION_STEPS
from lib.core.settings import PARTIAL_VALUE_MARKER
from lib.core.settings import PYVERSION from lib.core.settings import PYVERSION
from lib.core.threads import getCurrentThreadData from lib.core.threads import getCurrentThreadData
from lib.core.threads import runThreads from lib.core.threads import runThreads
@ -58,466 +58,459 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
on an affected host on an affected host
""" """
retVal = conf.hashDB.retrieve(expression) if not any([conf.flushSession, conf.freshQueries]) else None partialValue = u""
finalValue = None
if retVal: abortedFlag = False
return 0, retVal
partialValue = ""
finalValue = ""
asciiTbl = getCharset(charsetType) asciiTbl = getCharset(charsetType)
timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED))
retVal = conf.hashDB.retrieve(expression) if not any([conf.flushSession, conf.freshQueries, not kb.resumeValues]) else None
# Set kb.partRun in case "common prediction" feature (a.k.a. "good if retVal:
# samaritan") is used if PARTIAL_VALUE_MARKER in retVal:
kb.partRun = getPartRun() if conf.predictOutput else None partialValue = retVal.replace(PARTIAL_VALUE_MARKER, "")
dataToStdout("[%s] [INFO] resuming partial value: '%s'\r\n" % (time.strftime("%X"), safecharencode(partialValue)))
if "LENGTH(" in expression or "LEN(" in expression:
firstChar = 0
elif dump and conf.firstChar is not None and ( isinstance(conf.firstChar, int) or ( isinstance(conf.firstChar, basestring) and conf.firstChar.isdigit() ) ):
firstChar = int(conf.firstChar) - 1
elif firstChar is None:
firstChar = 0
elif ( isinstance(firstChar, basestring) and firstChar.isdigit() ) or isinstance(firstChar, int):
firstChar = int(firstChar) - 1
if "LENGTH(" in expression or "LEN(" in expression:
lastChar = 0
elif dump and conf.lastChar is not None and ( isinstance(conf.lastChar, int) or ( isinstance(conf.lastChar, basestring) and conf.lastChar.isdigit() ) ):
lastChar = int(conf.lastChar)
elif lastChar in ( None, "0" ):
lastChar = 0
elif ( isinstance(lastChar, basestring) and lastChar.isdigit() ) or isinstance(lastChar, int):
lastChar = int(lastChar)
if Backend.getDbms():
_, _, _, _, _, _, fieldToCastStr, _ = agent.getFields(expression)
nulledCastedField = agent.nullAndCastField(fieldToCastStr)
expressionReplaced = expression.replace(fieldToCastStr, nulledCastedField, 1)
expressionUnescaped = unescaper.unescape(expressionReplaced)
else:
expressionUnescaped = unescaper.unescape(expression)
if length and not isinstance(length, int) and length.isdigit():
length = int(length)
if length == 0:
return 0, ""
if lastChar > 0 and length > ( lastChar - firstChar ):
length = ( lastChar - firstChar )
showEta = conf.eta and isinstance(length, int)
numThreads = min(conf.threads, length)
if showEta:
progress = ProgressBar(maxValue=length)
progressTime = []
if timeBasedCompare and conf.threads > 1:
warnMsg = "multi-threading is considered unsafe in time-based data retrieval. Going to switch it off automatically"
singleTimeWarnMessage(warnMsg)
if numThreads > 1:
if not timeBasedCompare:
debugMsg = "starting %d thread%s" % (numThreads, ("s" if numThreads > 1 else ""))
logger.debug(debugMsg)
else: else:
numThreads = 1 dataToStdout("[%s] [INFO] resumed: %s\r\n" % (time.strftime("%X"), safecharencode(retVal)))
return 0, retVal
if conf.threads == 1 and not timeBasedCompare: try:
warnMsg = "running in a single-thread mode. Please consider " # Set kb.partRun in case "common prediction" feature (a.k.a. "good
warnMsg += "usage of option '--threads' for faster data retrieval" # samaritan") is used
singleTimeWarnMessage(warnMsg) kb.partRun = getPartRun() if conf.predictOutput else None
if conf.verbose in (1, 2) and not showEta: if partialValue:
if isinstance(length, int) and conf.threads > 1: firstChar = len(partialValue)
dataToStdout("[%s] [INFO] retrieved: %s" % (time.strftime("%X"), "_" * min(length, conf.progressWidth))) elif "LENGTH(" in expression or "LEN(" in expression:
dataToStdout("\r[%s] [INFO] retrieved: " % time.strftime("%X")) firstChar = 0
elif dump and conf.firstChar is not None and ( isinstance(conf.firstChar, int) or ( isinstance(conf.firstChar, basestring) and conf.firstChar.isdigit() ) ):
firstChar = int(conf.firstChar) - 1
elif firstChar is None:
firstChar = 0
elif ( isinstance(firstChar, basestring) and firstChar.isdigit() ) or isinstance(firstChar, int):
firstChar = int(firstChar) - 1
if "LENGTH(" in expression or "LEN(" in expression:
lastChar = 0
elif dump and conf.lastChar is not None and ( isinstance(conf.lastChar, int) or ( isinstance(conf.lastChar, basestring) and conf.lastChar.isdigit() ) ):
lastChar = int(conf.lastChar)
elif lastChar in ( None, "0" ):
lastChar = 0
elif ( isinstance(lastChar, basestring) and lastChar.isdigit() ) or isinstance(lastChar, int):
lastChar = int(lastChar)
if Backend.getDbms():
_, _, _, _, _, _, fieldToCastStr, _ = agent.getFields(expression)
nulledCastedField = agent.nullAndCastField(fieldToCastStr)
expressionReplaced = expression.replace(fieldToCastStr, nulledCastedField, 1)
expressionUnescaped = unescaper.unescape(expressionReplaced)
else: else:
dataToStdout("[%s] [INFO] retrieved: " % time.strftime("%X")) expressionUnescaped = unescaper.unescape(expression)
hintlock = threading.Lock() if length and not isinstance(length, int) and length.isdigit():
length = int(length)
def tryHint(idx): if length == 0:
hintlock.acquire() return 0, ""
hintValue = kb.hintValue
hintlock.release()
if hintValue is not None and len(hintValue) >= idx: if lastChar > 0 and length > ( lastChar - firstChar ):
if Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.MAXDB, DBMS.DB2): length = ( lastChar - firstChar )
posValue = hintValue[idx-1]
showEta = conf.eta and isinstance(length, int)
numThreads = min(conf.threads, length)
if showEta:
progress = ProgressBar(maxValue=length)
progressTime = []
if timeBasedCompare and conf.threads > 1:
warnMsg = "multi-threading is considered unsafe in time-based data retrieval. Going to switch it off automatically"
singleTimeWarnMessage(warnMsg)
if numThreads > 1:
if not timeBasedCompare:
debugMsg = "starting %d thread%s" % (numThreads, ("s" if numThreads > 1 else ""))
logger.debug(debugMsg)
else: else:
posValue = ord(hintValue[idx-1]) numThreads = 1
forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, posValue)) if conf.threads == 1 and not timeBasedCompare:
result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False) warnMsg = "running in a single-thread mode. Please consider "
incrementCounter(kb.technique) warnMsg += "usage of option '--threads' for faster data retrieval"
singleTimeWarnMessage(warnMsg)
if result: if conf.verbose in (1, 2) and not showEta:
return hintValue[idx-1] if isinstance(length, int) and conf.threads > 1:
dataToStdout("[%s] [INFO] retrieved: %s" % (time.strftime("%X"), "_" * min(length, conf.progressWidth)))
hintlock.acquire() dataToStdout("\r[%s] [INFO] retrieved: " % time.strftime("%X"))
kb.hintValue = None
hintlock.release()
return None
def validateChar(idx, value):
"""
Used in time-based inference (in case that original and retrieved
value are not equal there will be a deliberate delay).
"""
forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_NOT_EQUALS_CHAR), (expressionUnescaped, idx, value))
incrementCounter(kb.technique)
result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
return not result
def getChar(idx, charTbl=asciiTbl, continuousOrder=True, expand=charsetType is None, shiftTable=None):
"""
continuousOrder means that distance between each two neighbour's
numerical values is exactly 1
"""
result = tryHint(idx)
if result:
return result
originalTbl = list(charTbl)
if continuousOrder and shiftTable is None:
# Used for gradual expanding into unicode charspace
shiftTable = [5, 4]
if CHAR_INFERENCE_MARK in payload and ord('\n') in charTbl:
charTbl.remove(ord('\n'))
if len(charTbl) == 1:
forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, charTbl[0]))
result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique)
if result:
return decodeIntToUnicode(charTbl[0])
else: else:
return None dataToStdout("[%s] [INFO] retrieved: " % time.strftime("%X"))
maxChar = maxValue = charTbl[-1] hintlock = threading.Lock()
minChar = minValue = charTbl[0]
while len(charTbl) != 1: def tryHint(idx):
position = (len(charTbl) >> 1) hintlock.acquire()
posValue = charTbl[position] hintValue = kb.hintValue
hintlock.release()
if CHAR_INFERENCE_MARK not in payload: if hintValue is not None and len(hintValue) >= idx:
forgedPayload = safeStringFormat(payload, (expressionUnescaped, idx, posValue)) if Backend.getIdentifiedDbms() in (DBMS.SQLITE, DBMS.ACCESS, DBMS.MAXDB, DBMS.DB2):
else: posValue = hintValue[idx-1]
# e.g.: ... > '%c' -> ... > ORD(..)
markingValue = "'%s'" % CHAR_INFERENCE_MARK
unescapedCharValue = unescaper.unescape("'%s'" % decodeIntToUnicode(posValue))
forgedPayload = safeStringFormat(payload, (expressionUnescaped, idx)).replace(markingValue, unescapedCharValue)
result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique)
if result:
minValue = posValue
if type(charTbl) != xrange:
charTbl = charTbl[position:]
else: else:
# xrange() - extended virtual charset used for memory/space optimization posValue = ord(hintValue[idx-1])
charTbl = xrange(charTbl[position], charTbl[-1] + 1)
else:
maxValue = posValue
if type(charTbl) != xrange: forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, posValue))
charTbl = charTbl[:position] result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
else: incrementCounter(kb.technique)
charTbl = xrange(charTbl[0], charTbl[position])
if result:
return hintValue[idx-1]
hintlock.acquire()
kb.hintValue = None
hintlock.release()
return None
def validateChar(idx, value):
"""
Used in time-based inference (in case that original and retrieved
value are not equal there will be a deliberate delay).
"""
forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_NOT_EQUALS_CHAR), (expressionUnescaped, idx, value))
result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique)
return not result
def getChar(idx, charTbl=asciiTbl, continuousOrder=True, expand=charsetType is None, shiftTable=None):
"""
continuousOrder means that distance between each two neighbour's
numerical values is exactly 1
"""
result = tryHint(idx)
if result:
return result
originalTbl = list(charTbl)
if continuousOrder and shiftTable is None:
# Used for gradual expanding into unicode charspace
shiftTable = [5, 4]
if CHAR_INFERENCE_MARK in payload and ord('\n') in charTbl:
charTbl.remove(ord('\n'))
if len(charTbl) == 1: if len(charTbl) == 1:
if continuousOrder: forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, charTbl[0]))
if maxValue == 1: result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
return None incrementCounter(kb.technique)
# Going beyond the original charset if result:
elif minValue == maxChar: return decodeIntToUnicode(charTbl[0])
# If the original charTbl was [0,..,127] new one
# will be [128,..,128*16-1] or from 128 to 2047
# and instead of making a HUGE list with all the
# elements we use a xrange, which is a virtual
# list
if expand and shiftTable:
charTbl = xrange(maxChar + 1, (maxChar + 1) << shiftTable.pop())
originalTbl = list(charTbl)
maxChar = maxValue = charTbl[-1]
minChar = minValue = charTbl[0]
else:
return None
else:
retVal = minValue + 1
if retVal in originalTbl or (retVal == ord('\n') and CHAR_INFERENCE_MARK in payload):
if timeBasedCompare and not validateChar(idx, retVal):
if not kb.originalTimeDelay:
kb.originalTimeDelay = conf.timeSec
if (conf.timeSec - kb.originalTimeDelay) < MAX_TIME_REVALIDATION_STEPS:
errMsg = "invalid character detected. retrying.."
logger.error(errMsg)
warnMsg = "increasing time delay to %d second%s " % (conf.timeSec, 's' if conf.timeSec > 1 else '')
logger.warn(warnMsg)
conf.timeSec += 1
if kb.adjustTimeDelay:
dbgMsg = "turning off auto-adjustment mechanism"
logger.debug(dbgMsg)
kb.adjustTimeDelay = False
return getChar(idx, originalTbl, continuousOrder, expand, shiftTable)
else:
errMsg = "unable to properly validate last character value ('%s').." % decodeIntToUnicode(retVal)
logger.error(errMsg)
conf.timeSec = kb.originalTimeDelay
return decodeIntToUnicode(retVal)
else:
return decodeIntToUnicode(retVal)
else:
return None
else: else:
if minValue == maxChar or maxValue == minChar:
return None
# If we are working with non-continuous elements, set
# both minValue and character afterwards are possible
# candidates
for retVal in (originalTbl[originalTbl.index(minValue)], originalTbl[originalTbl.index(minValue) + 1]):
forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, retVal))
result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique)
if result:
return decodeIntToUnicode(retVal)
return None return None
def etaProgressUpdate(charTime, index): maxChar = maxValue = charTbl[-1]
if len(progressTime) <= ( (length * 3) / 100 ): minChar = minValue = charTbl[0]
eta = 0
else:
midTime = sum(progressTime) / len(progressTime)
midTimeWithLatest = (midTime + charTime) / 2
eta = midTimeWithLatest * (length - index) / conf.threads
progressTime.append(charTime) while len(charTbl) != 1:
progress.update(index) position = (len(charTbl) >> 1)
progress.draw(eta) posValue = charTbl[position]
# Go multi-threading (--threads > 1) if CHAR_INFERENCE_MARK not in payload:
if conf.threads > 1 and isinstance(length, int) and length > 1: forgedPayload = safeStringFormat(payload, (expressionUnescaped, idx, posValue))
value = [] else:
threadData = getCurrentThreadData() # e.g.: ... > '%c' -> ... > ORD(..)
markingValue = "'%s'" % CHAR_INFERENCE_MARK
unescapedCharValue = unescaper.unescape("'%s'" % decodeIntToUnicode(posValue))
forgedPayload = safeStringFormat(payload, (expressionUnescaped, idx)).replace(markingValue, unescapedCharValue)
threadData.shared.value = [ None ] * length result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
threadData.shared.index = [ firstChar ] # As list for python nested function scoping incrementCounter(kb.technique)
try: if result:
def blindThread(): minValue = posValue
threadData = getCurrentThreadData()
while kb.threadContinue: if type(charTbl) != xrange:
kb.locks.index.acquire() charTbl = charTbl[position:]
else:
# xrange() - extended virtual charset used for memory/space optimization
charTbl = xrange(charTbl[position], charTbl[-1] + 1)
else:
maxValue = posValue
if threadData.shared.index[0] >= length: if type(charTbl) != xrange:
charTbl = charTbl[:position]
else:
charTbl = xrange(charTbl[0], charTbl[position])
if len(charTbl) == 1:
if continuousOrder:
if maxValue == 1:
return None
# Going beyond the original charset
elif minValue == maxChar:
# If the original charTbl was [0,..,127] new one
# will be [128,..,128*16-1] or from 128 to 2047
# and instead of making a HUGE list with all the
# elements we use a xrange, which is a virtual
# list
if expand and shiftTable:
charTbl = xrange(maxChar + 1, (maxChar + 1) << shiftTable.pop())
originalTbl = list(charTbl)
maxChar = maxValue = charTbl[-1]
minChar = minValue = charTbl[0]
else:
return None
else:
retVal = minValue + 1
if retVal in originalTbl or (retVal == ord('\n') and CHAR_INFERENCE_MARK in payload):
if timeBasedCompare and not validateChar(idx, retVal):
if not kb.originalTimeDelay:
kb.originalTimeDelay = conf.timeSec
if (conf.timeSec - kb.originalTimeDelay) < MAX_TIME_REVALIDATION_STEPS:
errMsg = "invalid character detected. retrying.."
logger.error(errMsg)
warnMsg = "increasing time delay to %d second%s " % (conf.timeSec, 's' if conf.timeSec > 1 else '')
logger.warn(warnMsg)
conf.timeSec += 1
if kb.adjustTimeDelay:
dbgMsg = "turning off auto-adjustment mechanism"
logger.debug(dbgMsg)
kb.adjustTimeDelay = False
return getChar(idx, originalTbl, continuousOrder, expand, shiftTable)
else:
errMsg = "unable to properly validate last character value ('%s').." % decodeIntToUnicode(retVal)
logger.error(errMsg)
conf.timeSec = kb.originalTimeDelay
return decodeIntToUnicode(retVal)
else:
return decodeIntToUnicode(retVal)
else:
return None
else:
if minValue == maxChar or maxValue == minChar:
return None
# If we are working with non-continuous elements, set
# both minValue and character afterwards are possible
# candidates
for retVal in (originalTbl[originalTbl.index(minValue)], originalTbl[originalTbl.index(minValue) + 1]):
forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, retVal))
result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique)
if result:
return decodeIntToUnicode(retVal)
return None
def etaProgressUpdate(charTime, index):
if len(progressTime) <= ( (length * 3) / 100 ):
eta = 0
else:
midTime = sum(progressTime) / len(progressTime)
midTimeWithLatest = (midTime + charTime) / 2
eta = midTimeWithLatest * (length - index) / conf.threads
progressTime.append(charTime)
progress.update(index)
progress.draw(eta)
# Go multi-threading (--threads > 1)
if conf.threads > 1 and isinstance(length, int) and length > 1:
value = []
threadData = getCurrentThreadData()
threadData.shared.value = [ None ] * length
threadData.shared.index = [ firstChar ] # As list for python nested function scoping
threadData.shared.start = firstChar
try:
def blindThread():
threadData = getCurrentThreadData()
while kb.threadContinue:
kb.locks.index.acquire()
if threadData.shared.index[0] >= length:
kb.locks.index.release()
return
threadData.shared.index[0] += 1
curidx = threadData.shared.index[0]
kb.locks.index.release() kb.locks.index.release()
return if kb.threadContinue:
charStart = time.time()
val = getChar(curidx)
if val is None:
val = INFERENCE_UNKNOWN_CHAR
else:
break
threadData.shared.index[0] += 1 kb.locks.value.acquire()
curidx = threadData.shared.index[0] threadData.shared.value[curidx - 1] = val
kb.locks.index.release() currentValue = list(threadData.shared.value)
kb.locks.value.release()
if kb.threadContinue: if kb.threadContinue:
charStart = time.time() if showEta:
val = getChar(curidx) etaProgressUpdate(time.time() - charStart, threadData.shared.index[0])
if val is None: elif conf.verbose >= 1:
val = INFERENCE_UNKNOWN_CHAR startCharIndex = 0
else: endCharIndex = 0
break
kb.locks.value.acquire() for i in xrange(length):
threadData.shared.value[curidx-1] = val if currentValue[i] is not None:
currentValue = list(threadData.shared.value) endCharIndex = max(endCharIndex, i)
kb.locks.value.release()
if kb.threadContinue: output = ''
if showEta:
etaProgressUpdate(time.time() - charStart, threadData.shared.index[0])
elif conf.verbose >= 1:
startCharIndex = 0
endCharIndex = 0
for i in xrange(length): if endCharIndex > conf.progressWidth:
if currentValue[i] is not None: startCharIndex = endCharIndex - conf.progressWidth
endCharIndex = max(endCharIndex, i)
output = '' count = threadData.shared.start
if endCharIndex > conf.progressWidth: for i in xrange(startCharIndex, endCharIndex + 1):
startCharIndex = endCharIndex - conf.progressWidth output += '_' if currentValue[i] is None else currentValue[i]
count = 0 for i in xrange(length):
count += 1 if currentValue[i] is not None else 0
for i in xrange(startCharIndex, endCharIndex + 1): if startCharIndex > 0:
output += '_' if currentValue[i] is None else currentValue[i] output = '..' + output[2:]
for i in xrange(length): if (endCharIndex - startCharIndex == conf.progressWidth) and (endCharIndex < length-1):
count += 1 if currentValue[i] is not None else 0 output = output[:-2] + '..'
if startCharIndex > 0: if conf.verbose in (1, 2) and not showEta:
output = '..' + output[2:] output += '_' * (min(length, conf.progressWidth) - len(output))
status = ' %d/%d (%d%s)' % (count, length, round(100.0*count/length), '%')
output += status if count != length else " "*len(status)
if (endCharIndex - startCharIndex == conf.progressWidth) and (endCharIndex < length-1): dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), filterControlChars(output)))
output = output[:-2] + '..'
if conf.verbose in (1, 2) and not showEta: runThreads(numThreads, blindThread, startThreadMsg=False)
output += '_' * (min(length, conf.progressWidth) - len(output))
status = ' %d/%d (%d%s)' % (count, length, round(100.0*count/length), '%')
output += status if count != length else " "*len(status)
dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), filterControlChars(output))) except KeyboardInterrupt:
abortedFlag = True
if not kb.threadContinue: finally:
if int(threading.currentThread().getName()) == numThreads - 1: value = map(lambda _: partialValue[_] if _ < len(partialValue) else threadData.shared.value[_], xrange(length))
partialValue = unicode()
for v in threadData.shared.value:
if v is None:
break
elif isinstance(v, basestring):
partialValue += v
if len(partialValue) > 0: infoMsg = None
dataToSessionFile(replaceNewlineTabs(partialValue))
runThreads(numThreads, blindThread, startThreadMsg=False) # If we have got one single character not correctly fetched it
# can mean that the connection to the target url was lost
if None in value:
partialValue = "".join(_ for _ in value[:value.index(None)])
except KeyboardInterrupt: if partialValue:
raise infoMsg = "\r[%s] [INFO] partially retrieved: %s" % (time.strftime("%X"), filterControlChars(partialValue))
finally:
value = threadData.shared.value
infoMsg = None
# If we have got one single character not correctly fetched it
# can mean that the connection to the target url was lost
if None in value:
for v in value:
if isinstance(v, basestring) and v is not None:
partialValue += v
if partialValue:
finalValue = partialValue
infoMsg = "\r[%s] [INFO] partially retrieved: %s" % (time.strftime("%X"), filterControlChars(finalValue))
else:
finalValue = "".join(value)
infoMsg = "\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), filterControlChars(finalValue))
if isinstance(finalValue, basestring) and len(finalValue) > 0:
dataToSessionFile(replaceNewlineTabs(finalValue))
if conf.verbose in (1, 2) and not showEta and infoMsg:
dataToStdout(infoMsg)
# No multi-threading (--threads = 1)
else:
index = firstChar
while True:
index += 1
charStart = time.time()
# Common prediction feature (a.k.a. "good samaritan")
# NOTE: to be used only when multi-threading is not set for
# the moment
if conf.predictOutput and len(finalValue) > 0 and kb.partRun is not None:
val = None
commonValue, commonPattern, commonCharset, otherCharset = goGoodSamaritan(finalValue, asciiTbl)
# If there is one single output in common-outputs, check
# it via equal against the query output
if commonValue is not None:
# One-shot query containing equals commonValue
testValue = unescaper.unescape("'%s'" % commonValue) if "'" not in commonValue else unescaper.unescape("%s" % commonValue, quote=False)
query = agent.prefixQuery(safeStringFormat("AND (%s) = %s", (expressionUnescaped, testValue)))
query = agent.suffixQuery(query)
result = Request.queryPage(agent.payload(newValue=query), timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique)
# Did we have luck?
if result:
dataToSessionFile(replaceNewlineTabs(commonValue[index-1:]))
if showEta:
etaProgressUpdate(time.time() - charStart, len(commonValue))
elif conf.verbose in (1, 2):
dataToStdout(commonValue[index-1:])
finalValue = commonValue
break
# If there is a common pattern starting with finalValue,
# check it via equal against the substring-query output
if commonPattern is not None:
# Substring-query containing equals commonPattern
subquery = queries[Backend.getIdentifiedDbms()].substring.query % (expressionUnescaped, 1, len(commonPattern))
testValue = unescaper.unescape("'%s'" % commonPattern) if "'" not in commonPattern else unescaper.unescape("%s" % commonPattern, quote=False)
query = agent.prefixQuery(safeStringFormat("AND (%s) = %s", (subquery, testValue)))
query = agent.suffixQuery(query)
result = Request.queryPage(agent.payload(newValue=query), timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique)
# Did we have luck?
if result:
val = commonPattern[index-1:]
index += len(val)-1
# Otherwise if there is no commonValue (single match from
# txt/common-outputs.txt) and no commonPattern
# (common pattern) use the returned common charset only
# to retrieve the query output
if not val and commonCharset:
val = getChar(index, commonCharset, False)
# If we had no luck with commonValue and common charset,
# use the returned other charset
if not val:
val = getChar(index, otherCharset, otherCharset == asciiTbl)
else: else:
val = getChar(index, asciiTbl) finalValue = "".join(value)
infoMsg = "\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), filterControlChars(finalValue))
if val is None or ( lastChar > 0 and index > lastChar ): if conf.verbose in (1, 2) and not showEta and infoMsg:
break dataToStdout(infoMsg)
if kb.data.processChar: # No multi-threading (--threads = 1)
val = kb.data.processChar(val) else:
index = firstChar
finalValue += val while True:
dataToSessionFile(replaceNewlineTabs(val)) index += 1
charStart = time.time()
if showEta: # Common prediction feature (a.k.a. "good samaritan")
etaProgressUpdate(time.time() - charStart, index) # NOTE: to be used only when multi-threading is not set for
elif conf.verbose in (1, 2): # the moment
dataToStdout(val) if conf.predictOutput and len(partialValue) > 0 and kb.partRun is not None:
val = None
commonValue, commonPattern, commonCharset, otherCharset = goGoodSamaritan(partialValue, asciiTbl)
if len(finalValue) > INFERENCE_BLANK_BREAK and finalValue[-INFERENCE_BLANK_BREAK:].isspace(): # If there is one single output in common-outputs, check
break # it via equal against the query output
if commonValue is not None:
# One-shot query containing equals commonValue
testValue = unescaper.unescape("'%s'" % commonValue) if "'" not in commonValue else unescaper.unescape("%s" % commonValue, quote=False)
query = agent.prefixQuery(safeStringFormat("AND (%s) = %s", (expressionUnescaped, testValue)))
query = agent.suffixQuery(query)
result = Request.queryPage(agent.payload(newValue=query), timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique)
# Did we have luck?
if result:
if showEta:
etaProgressUpdate(time.time() - charStart, len(commonValue))
elif conf.verbose in (1, 2):
dataToStdout(commonValue[index-1:])
finalValue = commonValue
break
# If there is a common pattern starting with partialValue,
# check it via equal against the substring-query output
if commonPattern is not None:
# Substring-query containing equals commonPattern
subquery = queries[Backend.getIdentifiedDbms()].substring.query % (expressionUnescaped, 1, len(commonPattern))
testValue = unescaper.unescape("'%s'" % commonPattern) if "'" not in commonPattern else unescaper.unescape("%s" % commonPattern, quote=False)
query = agent.prefixQuery(safeStringFormat("AND (%s) = %s", (subquery, testValue)))
query = agent.suffixQuery(query)
result = Request.queryPage(agent.payload(newValue=query), timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique)
# Did we have luck?
if result:
val = commonPattern[index-1:]
index += len(val)-1
# Otherwise if there is no commonValue (single match from
# txt/common-outputs.txt) and no commonPattern
# (common pattern) use the returned common charset only
# to retrieve the query output
if not val and commonCharset:
val = getChar(index, commonCharset, False)
# If we had no luck with commonValue and common charset,
# use the returned other charset
if not val:
val = getChar(index, otherCharset, otherCharset == asciiTbl)
else:
val = getChar(index, asciiTbl)
if val is None or ( lastChar > 0 and index > lastChar ):
finalValue = partialValue
break
if kb.data.processChar:
val = kb.data.processChar(val)
partialValue += val
if showEta:
etaProgressUpdate(time.time() - charStart, index)
elif conf.verbose in (1, 2):
dataToStdout(val)
if len(partialValue) > INFERENCE_BLANK_BREAK and partialValue[-INFERENCE_BLANK_BREAK:].isspace():
finalValue = partialValue
break
except KeyboardInterrupt:
abortedFlag = True
if conf.verbose in (1, 2) or showEta: if conf.verbose in (1, 2) or showEta:
dataToStdout("\n") dataToStdout("\n")
@ -526,11 +519,16 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
infoMsg = "retrieved: %s" % filterControlChars(finalValue) infoMsg = "retrieved: %s" % filterControlChars(finalValue)
logger.info(infoMsg) logger.info(infoMsg)
if not partialValue: if finalValue is not None:
conf.hashDB.write(expression, finalValue) conf.hashDB.write(expression, finalValue)
dataToSessionFile("]\n") else:
conf.hashDB.write(expression, "%s%s" % (PARTIAL_VALUE_MARKER, partialValue))
if kb.threadException: if kb.threadException:
raise sqlmapThreadException, "something unexpected happened inside the threads" raise sqlmapThreadException, "something unexpected happened inside the threads"
return getCounter(kb.technique), safecharencode(finalValue) if kb.safeCharEncode else finalValue if abortedFlag:
raise KeyboardInterrupt
_ = finalValue or partialValue
return getCounter(kb.technique), safecharencode(_) if kb.safeCharEncode else _

View File

@ -45,10 +45,9 @@ from lib.core.threads import getCurrentThreadData
from lib.core.threads import runThreads from lib.core.threads import runThreads
from lib.core.unescaper import unescaper from lib.core.unescaper import unescaper
from lib.request.connect import Connect as Request from lib.request.connect import Connect as Request
from lib.utils.resume import resume
def __oneShotErrorUse(expression, field): def __oneShotErrorUse(expression, field):
retVal = conf.hashDB.retrieve(expression) if not any([conf.flushSession, conf.freshQueries]) else None retVal = conf.hashDB.retrieve(expression) if not any([conf.flushSession, conf.freshQueries, not kb.resumeValues]) else None
threadData = getCurrentThreadData() threadData = getCurrentThreadData()
threadData.resumed = retVal is not None threadData.resumed = retVal is not None
@ -137,7 +136,7 @@ def __oneShotErrorUse(expression, field):
return safecharencode(retVal) if kb.safeCharEncode else retVal return safecharencode(retVal) if kb.safeCharEncode else retVal
def __errorFields(expression, expressionFields, expressionFieldsList, expected=None, num=None, resumeValue=True): def __errorFields(expression, expressionFields, expressionFieldsList, expected=None, num=None):
outputs = [] outputs = []
origExpr = None origExpr = None
@ -158,22 +157,13 @@ def __errorFields(expression, expressionFields, expressionFieldsList, expected=N
else: else:
expressionReplaced = expression.replace(expressionFields, field, 1) expressionReplaced = expression.replace(expressionFields, field, 1)
if resumeValue: output = __oneShotErrorUse(expressionReplaced, field)
output = resume(expressionReplaced, None)
if not output or (expected == EXPECTED.INT and not output.isdigit()): if not kb.threadContinue:
if output: return None
warnMsg = "expected value type %s, resumed '%s', " % (expected, output)
warnMsg += "sqlmap is going to retrieve the value again"
logger.warn(warnMsg)
output = __oneShotErrorUse(expressionReplaced, field) if output is not None:
dataToStdout("[%s] [INFO] %s: %s\r\n" % (time.strftime("%X"), "resumed" if threadData.resumed else "retrieved", safecharencode(output)))
if not kb.threadContinue:
return None
if output is not None:
dataToStdout("[%s] [INFO] %s: %s\r\n" % (time.strftime("%X"), "resumed" if threadData.resumed else "retrieved", safecharencode(output)))
if isinstance(num, int): if isinstance(num, int):
expression = origExpr expression = origExpr
@ -194,7 +184,7 @@ def __errorReplaceChars(value):
return retVal return retVal
def errorUse(expression, expected=None, resumeValue=True, dump=False): def errorUse(expression, expected=None, dump=False):
""" """
Retrieve the output of a SQL query taking advantage of the error-based Retrieve the output of a SQL query taking advantage of the error-based
SQL injection vulnerability on the affected parameter. SQL injection vulnerability on the affected parameter.
@ -207,18 +197,11 @@ def errorUse(expression, expected=None, resumeValue=True, dump=False):
start = time.time() start = time.time()
startLimit = 0 startLimit = 0
stopLimit = None stopLimit = None
output = None
outputs = [] outputs = []
untilLimitChar = None untilLimitChar = None
untilOrderChar = None untilOrderChar = None
if resumeValue:
output = resume(expression, None)
else:
output = None
if output and (expected is None or (expected == EXPECTED.INT and output.isdigit())):
return output
_, _, _, _, _, expressionFieldsList, expressionFields, _ = agent.getFields(expression) _, _, _, _, _, expressionFieldsList, expressionFields, _ = agent.getFields(expression)
# We have to check if the SQL query might return multiple entries # We have to check if the SQL query might return multiple entries
@ -295,11 +278,8 @@ def errorUse(expression, expected=None, resumeValue=True, dump=False):
if " ORDER BY " in expression: if " ORDER BY " in expression:
countedExpression = countedExpression[:countedExpression.index(" ORDER BY ")] countedExpression = countedExpression[:countedExpression.index(" ORDER BY ")]
count = resume(countedExpression, None) _, _, _, _, _, _, countedExpressionFields, _ = agent.getFields(countedExpression)
count = __oneShotErrorUse(countedExpression, countedExpressionFields)
if not count or not count.isdigit():
_, _, _, _, _, _, countedExpressionFields, _ = agent.getFields(countedExpression)
count = __oneShotErrorUse(countedExpression, countedExpressionFields)
if isNumPosStrValue(count): if isNumPosStrValue(count):
if isinstance(stopLimit, int) and stopLimit > 0: if isinstance(stopLimit, int) and stopLimit > 0:
@ -360,7 +340,7 @@ def errorUse(expression, expected=None, resumeValue=True, dump=False):
finally: finally:
kb.locks.limits.release() kb.locks.limits.release()
output = __errorFields(expression, expressionFields, expressionFieldsList, expected, num, resumeValue) output = __errorFields(expression, expressionFields, expressionFieldsList, expected, num)
if not kb.threadContinue: if not kb.threadContinue:
break break

View File

@ -43,10 +43,9 @@ from lib.core.threads import getCurrentThreadData
from lib.core.threads import runThreads from lib.core.threads import runThreads
from lib.core.unescaper import unescaper from lib.core.unescaper import unescaper
from lib.request.connect import Connect as Request from lib.request.connect import Connect as Request
from lib.utils.resume import resume
def __oneShotUnionUse(expression, unpack=True, limited=False): def __oneShotUnionUse(expression, unpack=True, limited=False):
retVal = conf.hashDB.retrieve(expression) if not any([conf.flushSession, conf.freshQueries]) else None retVal = conf.hashDB.retrieve(expression) if not any([conf.flushSession, conf.freshQueries, not kb.resumeValues]) else None
threadData = getCurrentThreadData() threadData = getCurrentThreadData()
threadData.resumed = retVal is not None threadData.resumed = retVal is not None
@ -233,14 +232,8 @@ def unionUse(expression, unpack=True, dump=False):
_ = countedExpression.upper().rindex(" ORDER BY ") _ = countedExpression.upper().rindex(" ORDER BY ")
countedExpression = countedExpression[:_] countedExpression = countedExpression[:_]
count = resume(countedExpression, None) output = __oneShotUnionUse(countedExpression, unpack)
count = parseUnionPage(count) count = parseUnionPage(output)
if not count or not count.isdigit():
output = __oneShotUnionUse(countedExpression, unpack)
if output:
count = parseUnionPage(output)
if isNumPosStrValue(count): if isNumPosStrValue(count):
if isinstance(stopLimit, int) and stopLimit > 0: if isinstance(stopLimit, int) and stopLimit > 0:
@ -301,10 +294,7 @@ def unionUse(expression, unpack=True, dump=False):
field = None field = None
limitedExpr = agent.limitQuery(num, expression, field) limitedExpr = agent.limitQuery(num, expression, field)
output = resume(limitedExpr, None) output = __oneShotUnionUse(limitedExpr, unpack, True)
if not output:
output = __oneShotUnionUse(limitedExpr, unpack, True)
if not kb.threadContinue: if not kb.threadContinue:
break break

View File

@ -69,13 +69,6 @@ def queryOutputLength(expression, payload):
infoMsg = "retrieving the length of query output" infoMsg = "retrieving the length of query output"
logger.info(infoMsg) logger.info(infoMsg)
output = resume(lengthExpr, payload)
if output:
return 0, output, regExpr
dataToSessionFile("[%s][%s][%s][%s][" % (conf.url, kb.injection.place, conf.parameters[kb.injection.place], lengthExpr))
start = time.time() start = time.time()
lengthExprUnescaped = unescaper.unescape(lengthExpr) lengthExprUnescaped = unescaper.unescape(lengthExpr)
count, length = bisection(payload, lengthExprUnescaped, charsetType=2) count, length = bisection(payload, lengthExprUnescaped, charsetType=2)