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,15 +93,6 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl
else: else:
expressionReplaced = expression.replace(expressionFields, field, 1) expressionReplaced = expression.replace(expressionFields, field, 1)
if resumeValue:
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) output = __goInference(payload, expressionReplaced, charsetType, firstChar, lastChar, dump)
if isinstance(num, int): if isinstance(num, int):
@ -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,11 +214,7 @@ 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):
@ -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
partial = False
data = None
if output is None:
output = unionUse(expression, unpack=unpack, dump=dump) output = unionUse(expression, unpack=unpack, dump=dump)
if isinstance(output, basestring):
output = parseUnionPage(output, unique)
if isinstance(output, list): return output
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,21 +58,29 @@ 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
if retVal:
if PARTIAL_VALUE_MARKER in retVal:
partialValue = retVal.replace(PARTIAL_VALUE_MARKER, "")
dataToStdout("[%s] [INFO] resuming partial value: '%s'\r\n" % (time.strftime("%X"), safecharencode(partialValue)))
else:
dataToStdout("[%s] [INFO] resumed: %s\r\n" % (time.strftime("%X"), safecharencode(retVal)))
return 0, retVal
try:
# Set kb.partRun in case "common prediction" feature (a.k.a. "good # Set kb.partRun in case "common prediction" feature (a.k.a. "good
# samaritan") is used # samaritan") is used
kb.partRun = getPartRun() if conf.predictOutput else None kb.partRun = getPartRun() if conf.predictOutput else None
if "LENGTH(" in expression or "LEN(" in expression: if partialValue:
firstChar = len(partialValue)
elif "LENGTH(" in expression or "LEN(" in expression:
firstChar = 0 firstChar = 0
elif dump and conf.firstChar is not None and ( isinstance(conf.firstChar, int) or ( isinstance(conf.firstChar, basestring) and conf.firstChar.isdigit() ) ): 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 firstChar = int(conf.firstChar) - 1
@ -170,8 +178,8 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
""" """
forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_NOT_EQUALS_CHAR), (expressionUnescaped, idx, value)) 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) result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique)
return not result return not result
@ -325,6 +333,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
threadData.shared.value = [ None ] * length threadData.shared.value = [ None ] * length
threadData.shared.index = [ firstChar ] # As list for python nested function scoping threadData.shared.index = [ firstChar ] # As list for python nested function scoping
threadData.shared.start = firstChar
try: try:
def blindThread(): def blindThread():
@ -371,7 +380,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
if endCharIndex > conf.progressWidth: if endCharIndex > conf.progressWidth:
startCharIndex = endCharIndex - conf.progressWidth startCharIndex = endCharIndex - conf.progressWidth
count = 0 count = threadData.shared.start
for i in xrange(startCharIndex, endCharIndex + 1): for i in xrange(startCharIndex, endCharIndex + 1):
output += '_' if currentValue[i] is None else currentValue[i] output += '_' if currentValue[i] is None else currentValue[i]
@ -392,45 +401,27 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), filterControlChars(output))) dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), filterControlChars(output)))
if not kb.threadContinue:
if int(threading.currentThread().getName()) == numThreads - 1:
partialValue = unicode()
for v in threadData.shared.value:
if v is None:
break
elif isinstance(v, basestring):
partialValue += v
if len(partialValue) > 0:
dataToSessionFile(replaceNewlineTabs(partialValue))
runThreads(numThreads, blindThread, startThreadMsg=False) runThreads(numThreads, blindThread, startThreadMsg=False)
except KeyboardInterrupt: except KeyboardInterrupt:
raise abortedFlag = True
finally: finally:
value = threadData.shared.value value = map(lambda _: partialValue[_] if _ < len(partialValue) else threadData.shared.value[_], xrange(length))
infoMsg = None infoMsg = None
# If we have got one single character not correctly fetched it # If we have got one single character not correctly fetched it
# can mean that the connection to the target url was lost # can mean that the connection to the target url was lost
if None in value: if None in value:
for v in value: partialValue = "".join(_ for _ in value[:value.index(None)])
if isinstance(v, basestring) and v is not None:
partialValue += v
if partialValue: if partialValue:
finalValue = partialValue infoMsg = "\r[%s] [INFO] partially retrieved: %s" % (time.strftime("%X"), filterControlChars(partialValue))
infoMsg = "\r[%s] [INFO] partially retrieved: %s" % (time.strftime("%X"), filterControlChars(finalValue))
else: else:
finalValue = "".join(value) finalValue = "".join(value)
infoMsg = "\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), filterControlChars(finalValue)) 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: if conf.verbose in (1, 2) and not showEta and infoMsg:
dataToStdout(infoMsg) dataToStdout(infoMsg)
@ -445,9 +436,9 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
# Common prediction feature (a.k.a. "good samaritan") # Common prediction feature (a.k.a. "good samaritan")
# NOTE: to be used only when multi-threading is not set for # NOTE: to be used only when multi-threading is not set for
# the moment # the moment
if conf.predictOutput and len(finalValue) > 0 and kb.partRun is not None: if conf.predictOutput and len(partialValue) > 0 and kb.partRun is not None:
val = None val = None
commonValue, commonPattern, commonCharset, otherCharset = goGoodSamaritan(finalValue, asciiTbl) commonValue, commonPattern, commonCharset, otherCharset = goGoodSamaritan(partialValue, asciiTbl)
# If there is one single output in common-outputs, check # If there is one single output in common-outputs, check
# it via equal against the query output # it via equal against the query output
@ -461,8 +452,6 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
# Did we have luck? # Did we have luck?
if result: if result:
dataToSessionFile(replaceNewlineTabs(commonValue[index-1:]))
if showEta: if showEta:
etaProgressUpdate(time.time() - charStart, len(commonValue)) etaProgressUpdate(time.time() - charStart, len(commonValue))
elif conf.verbose in (1, 2): elif conf.verbose in (1, 2):
@ -472,7 +461,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
break break
# If there is a common pattern starting with finalValue, # If there is a common pattern starting with partialValue,
# check it via equal against the substring-query output # check it via equal against the substring-query output
if commonPattern is not None: if commonPattern is not None:
# Substring-query containing equals commonPattern # Substring-query containing equals commonPattern
@ -503,22 +492,26 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
val = getChar(index, asciiTbl) val = getChar(index, asciiTbl)
if val is None or ( lastChar > 0 and index > lastChar ): if val is None or ( lastChar > 0 and index > lastChar ):
finalValue = partialValue
break break
if kb.data.processChar: if kb.data.processChar:
val = kb.data.processChar(val) val = kb.data.processChar(val)
finalValue += val partialValue += val
dataToSessionFile(replaceNewlineTabs(val))
if showEta: if showEta:
etaProgressUpdate(time.time() - charStart, index) etaProgressUpdate(time.time() - charStart, index)
elif conf.verbose in (1, 2): elif conf.verbose in (1, 2):
dataToStdout(val) dataToStdout(val)
if len(finalValue) > INFERENCE_BLANK_BREAK and finalValue[-INFERENCE_BLANK_BREAK:].isspace(): if len(partialValue) > INFERENCE_BLANK_BREAK and partialValue[-INFERENCE_BLANK_BREAK:].isspace():
finalValue = partialValue
break 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,15 +157,6 @@ def __errorFields(expression, expressionFields, expressionFieldsList, expected=N
else: else:
expressionReplaced = expression.replace(expressionFields, field, 1) expressionReplaced = expression.replace(expressionFields, field, 1)
if resumeValue:
output = resume(expressionReplaced, None)
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 = __oneShotErrorUse(expressionReplaced, field) output = __oneShotErrorUse(expressionReplaced, field)
if not kb.threadContinue: if not kb.threadContinue:
@ -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,9 +278,6 @@ 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)
if not count or not count.isdigit():
_, _, _, _, _, _, countedExpressionFields, _ = agent.getFields(countedExpression) _, _, _, _, _, _, countedExpressionFields, _ = agent.getFields(countedExpression)
count = __oneShotErrorUse(countedExpression, countedExpressionFields) count = __oneShotErrorUse(countedExpression, countedExpressionFields)
@ -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,13 +232,7 @@ 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)
count = parseUnionPage(count)
if not count or not count.isdigit():
output = __oneShotUnionUse(countedExpression, unpack) output = __oneShotUnionUse(countedExpression, unpack)
if output:
count = parseUnionPage(output) count = parseUnionPage(output)
if isNumPosStrValue(count): if isNumPosStrValue(count):
@ -301,9 +294,6 @@ 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)
if not output:
output = __oneShotUnionUse(limitedExpr, unpack, True) output = __oneShotUnionUse(limitedExpr, unpack, True)
if not kb.threadContinue: if not kb.threadContinue:

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)