Patching silent per-thread issue with technique switching (fixes #3784)

This commit is contained in:
Miroslav Stampar 2019-07-01 10:43:05 +02:00
parent 32e09c8dfb
commit 3abd3e1a8d
9 changed files with 74 additions and 53 deletions

View File

@ -12,6 +12,7 @@ from lib.core.common import Backend
from lib.core.common import extractRegexResult from lib.core.common import extractRegexResult
from lib.core.common import filterNone from lib.core.common import filterNone
from lib.core.common import getSQLSnippet from lib.core.common import getSQLSnippet
from lib.core.common import getTechnique
from lib.core.common import isDBMSVersionAtLeast from lib.core.common import isDBMSVersionAtLeast
from lib.core.common import isNumber from lib.core.common import isNumber
from lib.core.common import isTechniqueAvailable from lib.core.common import isTechniqueAvailable
@ -89,8 +90,8 @@ class Agent(object):
if kb.forceWhere: if kb.forceWhere:
where = kb.forceWhere where = kb.forceWhere
elif where is None and isTechniqueAvailable(kb.technique): elif where is None and isTechniqueAvailable(getTechnique()):
where = kb.injection.data[kb.technique].where where = kb.injection.data[getTechnique()].where
if kb.injection.place is not None: if kb.injection.place is not None:
place = kb.injection.place place = kb.injection.place
@ -234,8 +235,8 @@ class Agent(object):
expression = unescaper.escape(expression) expression = unescaper.escape(expression)
query = None query = None
if where is None and kb.technique and kb.technique in kb.injection.data: if where is None and getTechnique() is not None and getTechnique() in kb.injection.data:
where = kb.injection.data[kb.technique].where where = kb.injection.data[getTechnique()].where
# If we are replacing (<where>) the parameter original value with # If we are replacing (<where>) the parameter original value with
# our payload do not prepend with the prefix # our payload do not prepend with the prefix
@ -244,7 +245,7 @@ class Agent(object):
# If the technique is stacked queries (<stype>) do not put a space # If the technique is stacked queries (<stype>) do not put a space
# after the prefix or it is in GROUP BY / ORDER BY (<clause>) # after the prefix or it is in GROUP BY / ORDER BY (<clause>)
elif kb.technique == PAYLOAD.TECHNIQUE.STACKED: elif getTechnique() == PAYLOAD.TECHNIQUE.STACKED:
query = kb.injection.prefix query = kb.injection.prefix
elif kb.injection.clause == [2, 3] or kb.injection.clause == [2] or kb.injection.clause == [3]: elif kb.injection.clause == [2, 3] or kb.injection.clause == [2] or kb.injection.clause == [3]:
query = kb.injection.prefix query = kb.injection.prefix
@ -282,9 +283,9 @@ class Agent(object):
# Take default values if None # Take default values if None
suffix = kb.injection.suffix if kb.injection and suffix is None else suffix suffix = kb.injection.suffix if kb.injection and suffix is None else suffix
if kb.technique and kb.technique in kb.injection.data: if getTechnique() is not None and getTechnique() in kb.injection.data:
where = kb.injection.data[kb.technique].where if where is None else where where = kb.injection.data[getTechnique()].where if where is None else where
comment = kb.injection.data[kb.technique].comment if comment is None else comment comment = kb.injection.data[getTechnique()].comment if comment is None else comment
if Backend.getIdentifiedDbms() == DBMS.ACCESS and any((comment or "").startswith(_) for _ in ("--", "[GENERIC_SQL_COMMENT]")): if Backend.getIdentifiedDbms() == DBMS.ACCESS and any((comment or "").startswith(_) for _ in ("--", "[GENERIC_SQL_COMMENT]")):
comment = queries[DBMS.ACCESS].comment.query comment = queries[DBMS.ACCESS].comment.query

View File

@ -1125,6 +1125,20 @@ def readInput(message, default=None, checkBatch=True, boolean=False):
return retVal or "" return retVal or ""
def setTechnique(technique):
"""
Thread-safe setting of currently used technique (Note: dealing with cases of per-thread technique switching)
"""
getCurrentThreadData().technique = technique
def getTechnique():
"""
Thread-safe getting of currently used technique
"""
return getCurrentThreadData().technique or kb.technique
def randomRange(start=0, stop=1000, seed=None): def randomRange(start=0, stop=1000, seed=None):
""" """
Returns random integer value in given range Returns random integer value in given range
@ -3231,18 +3245,16 @@ def isHeavyQueryBased(technique=None):
Returns True whether current (kb.)technique is heavy-query based Returns True whether current (kb.)technique is heavy-query based
>>> pushValue(kb.injection.data) >>> pushValue(kb.injection.data)
>>> pushValue(kb.technique) >>> setTechnique(PAYLOAD.TECHNIQUE.STACKED)
>>> kb.technique = PAYLOAD.TECHNIQUE.STACKED >>> kb.injection.data[getTechnique()] = [test for test in getSortedInjectionTests() if "heavy" in test["title"].lower()][0]
>>> kb.injection.data[kb.technique] = [test for test in getSortedInjectionTests() if "heavy" in test["title"].lower()][0]
>>> isHeavyQueryBased() >>> isHeavyQueryBased()
True True
>>> kb.technique = popValue()
>>> kb.injection.data = popValue() >>> kb.injection.data = popValue()
""" """
retVal = False retVal = False
technique = technique or kb.technique technique = technique or getTechnique()
if isTechniqueAvailable(technique): if isTechniqueAvailable(technique):
data = getTechniqueData(technique) data = getTechniqueData(technique)
@ -3630,7 +3642,7 @@ def unhandledExceptionMessage():
errMsg += "Python version: %s\n" % PYVERSION errMsg += "Python version: %s\n" % PYVERSION
errMsg += "Operating system: %s\n" % platform.platform() errMsg += "Operating system: %s\n" % platform.platform()
errMsg += "Command line: %s\n" % re.sub(r".+?\bsqlmap\.py\b", "sqlmap.py", getUnicode(" ".join(sys.argv), encoding=sys.stdin.encoding)) errMsg += "Command line: %s\n" % re.sub(r".+?\bsqlmap\.py\b", "sqlmap.py", getUnicode(" ".join(sys.argv), encoding=sys.stdin.encoding))
errMsg += "Technique: %s\n" % (enumValueToNameLookup(PAYLOAD.TECHNIQUE, kb.technique) if kb.get("technique") else ("DIRECT" if conf.get("direct") else None)) errMsg += "Technique: %s\n" % (enumValueToNameLookup(PAYLOAD.TECHNIQUE, getTechnique()) if getTechnique() is not None else ("DIRECT" if conf.get("direct") else None))
errMsg += "Back-end DBMS:" errMsg += "Back-end DBMS:"
if Backend.getDbms() is not None: if Backend.getDbms() is not None:

View File

@ -18,7 +18,7 @@ from lib.core.enums import OS
from thirdparty.six import unichr as _unichr from thirdparty.six import unichr as _unichr
# sqlmap version (<major>.<minor>.<month>.<monthly commit>) # sqlmap version (<major>.<minor>.<month>.<monthly commit>)
VERSION = "1.3.6.58" VERSION = "1.3.7.0"
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable" TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34} TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE) VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)

View File

@ -63,6 +63,7 @@ class _ThreadData(threading.local):
self.retriesCount = 0 self.retriesCount = 0
self.seqMatcher = difflib.SequenceMatcher(None) self.seqMatcher = difflib.SequenceMatcher(None)
self.shared = shared self.shared = shared
self.technique = None
self.validationRun = 0 self.validationRun = 0
self.valueStack = [] self.valueStack = []
@ -113,6 +114,7 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio
kb.threadContinue = True kb.threadContinue = True
kb.threadException = False kb.threadException = False
kb.technique = ThreadData.technique
if threadChoice and numThreads == 1 and not (kb.injection.data and not any(_ not in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED) for _ in kb.injection.data)): if threadChoice and numThreads == 1 and not (kb.injection.data and not any(_ not in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED) for _ in kb.injection.data)):
while True: while True:
@ -206,6 +208,7 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio
finally: finally:
kb.threadContinue = True kb.threadContinue = True
kb.threadException = False kb.threadException = False
kb.technique = None
for lock in kb.locks.values(): for lock in kb.locks.values():
if lock.locked(): if lock.locked():

View File

@ -19,6 +19,7 @@ from lib.core.common import expandAsteriskForColumns
from lib.core.common import extractExpectedValue from lib.core.common import extractExpectedValue
from lib.core.common import filterNone from lib.core.common import filterNone
from lib.core.common import getPublicTypeMembers from lib.core.common import getPublicTypeMembers
from lib.core.common import getTechnique
from lib.core.common import getTechniqueData from lib.core.common import getTechniqueData
from lib.core.common import hashDBRetrieve from lib.core.common import hashDBRetrieve
from lib.core.common import hashDBWrite from lib.core.common import hashDBWrite
@ -31,6 +32,7 @@ from lib.core.common import popValue
from lib.core.common import pushValue from lib.core.common import pushValue
from lib.core.common import randomStr from lib.core.common import randomStr
from lib.core.common import readInput from lib.core.common import readInput
from lib.core.common import setTechnique
from lib.core.common import singleTimeWarnMessage from lib.core.common import singleTimeWarnMessage
from lib.core.compat import xrange from lib.core.compat import xrange
from lib.core.data import conf from lib.core.data import conf
@ -88,7 +90,7 @@ def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar
if value is not None: if value is not None:
return value return value
timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) timeBasedCompare = (getTechnique() in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED))
if timeBasedCompare and conf.threads > 1 and kb.forceThreads is None: if timeBasedCompare and conf.threads > 1 and kb.forceThreads is None:
msg = "multi-threading is considered unsafe in " msg = "multi-threading is considered unsafe in "
@ -160,9 +162,9 @@ def _goInferenceProxy(expression, fromUser=False, batch=False, unpack=True, char
parameter through a bisection algorithm. parameter through a bisection algorithm.
""" """
initTechnique(kb.technique) initTechnique(getTechnique())
query = agent.prefixQuery(kb.injection.data[kb.technique].vector) query = agent.prefixQuery(kb.injection.data[getTechnique()].vector)
query = agent.suffixQuery(query) query = agent.suffixQuery(query)
payload = agent.payload(newValue=query) payload = agent.payload(newValue=query)
count = None count = None
@ -307,10 +309,10 @@ def _goBooleanProxy(expression):
Retrieve the output of a boolean based SQL query Retrieve the output of a boolean based SQL query
""" """
initTechnique(kb.technique) initTechnique(getTechnique())
if conf.dnsDomain: if conf.dnsDomain:
query = agent.prefixQuery(kb.injection.data[kb.technique].vector) query = agent.prefixQuery(kb.injection.data[getTechnique()].vector)
query = agent.suffixQuery(query) query = agent.suffixQuery(query)
payload = agent.payload(newValue=query) payload = agent.payload(newValue=query)
output = _goDns(payload, expression) output = _goDns(payload, expression)
@ -318,13 +320,13 @@ def _goBooleanProxy(expression):
if output is not None: if output is not None:
return output return output
vector = kb.injection.data[kb.technique].vector vector = kb.injection.data[getTechnique()].vector
vector = vector.replace(INFERENCE_MARKER, expression) vector = vector.replace(INFERENCE_MARKER, expression)
query = agent.prefixQuery(vector) query = agent.prefixQuery(vector)
query = agent.suffixQuery(query) query = agent.suffixQuery(query)
payload = agent.payload(newValue=query) payload = agent.payload(newValue=query)
timeBasedCompare = kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED) timeBasedCompare = getTechnique() in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)
output = hashDBRetrieve(expression, checkConf=True) output = hashDBRetrieve(expression, checkConf=True)
@ -401,7 +403,7 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
if not conf.forceDns: if not conf.forceDns:
if union and isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION): if union and isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION):
kb.technique = PAYLOAD.TECHNIQUE.UNION setTechnique(PAYLOAD.TECHNIQUE.UNION)
kb.forcePartialUnion = kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector[8] kb.forcePartialUnion = kb.injection.data[PAYLOAD.TECHNIQUE.UNION].vector[8]
fallback = not expected and kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.ORIGINAL and not kb.forcePartialUnion fallback = not expected and kb.injection.data[PAYLOAD.TECHNIQUE.UNION].where == PAYLOAD.WHERE.ORIGINAL and not kb.forcePartialUnion
@ -433,7 +435,7 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
singleTimeWarnMessage(warnMsg) singleTimeWarnMessage(warnMsg)
if error and any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) and not found: if error and any(isTechniqueAvailable(_) for _ in (PAYLOAD.TECHNIQUE.ERROR, PAYLOAD.TECHNIQUE.QUERY)) and not found:
kb.technique = PAYLOAD.TECHNIQUE.ERROR if isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) else PAYLOAD.TECHNIQUE.QUERY setTechnique(PAYLOAD.TECHNIQUE.ERROR if isTechniqueAvailable(PAYLOAD.TECHNIQUE.ERROR) else PAYLOAD.TECHNIQUE.QUERY)
value = errorUse(forgeCaseExpression if expected == EXPECTED.BOOL else query, dump) value = errorUse(forgeCaseExpression if expected == EXPECTED.BOOL else query, 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
@ -446,7 +448,7 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
singleTimeWarnMessage(warnMsg) singleTimeWarnMessage(warnMsg)
if blind and isTechniqueAvailable(PAYLOAD.TECHNIQUE.BOOLEAN) and not found: if blind and isTechniqueAvailable(PAYLOAD.TECHNIQUE.BOOLEAN) and not found:
kb.technique = PAYLOAD.TECHNIQUE.BOOLEAN setTechnique(PAYLOAD.TECHNIQUE.BOOLEAN)
if expected == EXPECTED.BOOL: if expected == EXPECTED.BOOL:
value = _goBooleanProxy(booleanExpression) value = _goBooleanProxy(booleanExpression)
@ -461,9 +463,9 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
kb.responseTimeMode = "%s|%s" % (match.group(1), match.group(2)) if match else None kb.responseTimeMode = "%s|%s" % (match.group(1), match.group(2)) if match else None
if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME): if isTechniqueAvailable(PAYLOAD.TECHNIQUE.TIME):
kb.technique = PAYLOAD.TECHNIQUE.TIME setTechnique(PAYLOAD.TECHNIQUE.TIME)
else: else:
kb.technique = PAYLOAD.TECHNIQUE.STACKED setTechnique(PAYLOAD.TECHNIQUE.STACKED)
if expected == EXPECTED.BOOL: if expected == EXPECTED.BOOL:
value = _goBooleanProxy(booleanExpression) value = _goBooleanProxy(booleanExpression)
@ -505,12 +507,12 @@ def getValue(expression, blind=True, union=True, error=True, time=True, fromUser
def goStacked(expression, silent=False): def goStacked(expression, silent=False):
if PAYLOAD.TECHNIQUE.STACKED in kb.injection.data: if PAYLOAD.TECHNIQUE.STACKED in kb.injection.data:
kb.technique = PAYLOAD.TECHNIQUE.STACKED setTechnique(PAYLOAD.TECHNIQUE.STACKED)
else: else:
for technique in getPublicTypeMembers(PAYLOAD.TECHNIQUE, True): for technique in getPublicTypeMembers(PAYLOAD.TECHNIQUE, True):
_ = getTechniqueData(technique) _ = getTechniqueData(technique)
if _ and "stacked" in _["title"].lower(): if _ and "stacked" in _["title"].lower():
kb.technique = technique setTechnique(technique)
break break
expression = cleanQuery(expression) expression = cleanQuery(expression)

View File

@ -20,6 +20,7 @@ from lib.core.common import getAutoDirectories
from lib.core.common import getManualDirectories from lib.core.common import getManualDirectories
from lib.core.common import getPublicTypeMembers from lib.core.common import getPublicTypeMembers
from lib.core.common import getSQLSnippet from lib.core.common import getSQLSnippet
from lib.core.common import getTechnique
from lib.core.common import isTechniqueAvailable from lib.core.common import isTechniqueAvailable
from lib.core.common import isWindowsDriveLetterPath from lib.core.common import isWindowsDriveLetterPath
from lib.core.common import normalizePath from lib.core.common import normalizePath
@ -147,8 +148,8 @@ class Web(object):
uplQuery = getUnicode(fileContent).replace(SHELL_WRITABLE_DIR_TAG, directory.replace('/', '\\\\') if Backend.isOs(OS.WINDOWS) else directory) uplQuery = getUnicode(fileContent).replace(SHELL_WRITABLE_DIR_TAG, directory.replace('/', '\\\\') if Backend.isOs(OS.WINDOWS) else directory)
query = "" query = ""
if isTechniqueAvailable(kb.technique): if isTechniqueAvailable(getTechnique()):
where = kb.injection.data[kb.technique].where where = kb.injection.data[getTechnique()].where
if where == PAYLOAD.WHERE.NEGATIVE: if where == PAYLOAD.WHERE.NEGATIVE:
randInt = randomInt() randInt = randomInt()

View File

@ -22,6 +22,7 @@ from lib.core.common import filterControlChars
from lib.core.common import getCharset from lib.core.common import getCharset
from lib.core.common import getCounter from lib.core.common import getCounter
from lib.core.common import getPartRun from lib.core.common import getPartRun
from lib.core.common import getTechnique
from lib.core.common import goGoodSamaritan from lib.core.common import goGoodSamaritan
from lib.core.common import hashDBRetrieve from lib.core.common import hashDBRetrieve
from lib.core.common import hashDBWrite from lib.core.common import hashDBWrite
@ -80,7 +81,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
asciiTbl = getCharset(charsetType) asciiTbl = getCharset(charsetType)
threadData = getCurrentThreadData() threadData = getCurrentThreadData()
timeBasedCompare = (kb.technique in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED)) timeBasedCompare = (getTechnique() in (PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED))
retVal = hashDBRetrieve(expression, checkConf=True) retVal = hashDBRetrieve(expression, checkConf=True)
if retVal: if retVal:
@ -201,7 +202,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
forgedPayload = agent.extractPayload(payload) forgedPayload = agent.extractPayload(payload)
forgedPayload = safeStringFormat(forgedPayload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, posValue)).replace(markingValue, unescapedCharValue) forgedPayload = safeStringFormat(forgedPayload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, posValue)).replace(markingValue, unescapedCharValue)
result = Request.queryPage(agent.replacePayload(payload, forgedPayload), timeBasedCompare=timeBasedCompare, raise404=False) result = Request.queryPage(agent.replacePayload(payload, forgedPayload), timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique) incrementCounter(getTechnique())
if result: if result:
return hintValue[idx - 1] return hintValue[idx - 1]
@ -228,13 +229,13 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
result = not Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False) result = not Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
if result and timeBasedCompare and kb.injection.data[kb.technique].trueCode: if result and timeBasedCompare and kb.injection.data[getTechnique()].trueCode:
result = threadData.lastCode == kb.injection.data[kb.technique].trueCode result = threadData.lastCode == kb.injection.data[getTechnique()].trueCode
if not result: if not result:
warnMsg = "detected HTTP code '%s' in validation phase is differing from expected '%s'" % (threadData.lastCode, kb.injection.data[kb.technique].trueCode) warnMsg = "detected HTTP code '%s' in validation phase is differing from expected '%s'" % (threadData.lastCode, kb.injection.data[getTechnique()].trueCode)
singleTimeWarnMessage(warnMsg) singleTimeWarnMessage(warnMsg)
incrementCounter(kb.technique) incrementCounter(getTechnique())
return result return result
@ -269,7 +270,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
elif len(charTbl) == 1: elif len(charTbl) == 1:
forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, charTbl[0])) forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, charTbl[0]))
result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False) result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique) incrementCounter(getTechnique())
if result: if result:
return decodeIntToUnicode(charTbl[0]) return decodeIntToUnicode(charTbl[0])
@ -338,10 +339,10 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
kb.responseTimePayload = None kb.responseTimePayload = None
result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False) result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique) incrementCounter(getTechnique())
if not timeBasedCompare: if not timeBasedCompare:
unexpectedCode |= threadData.lastCode not in (kb.injection.data[kb.technique].falseCode, kb.injection.data[kb.technique].trueCode) unexpectedCode |= threadData.lastCode not in (kb.injection.data[getTechnique()].falseCode, kb.injection.data[getTechnique()].trueCode)
if unexpectedCode: if unexpectedCode:
warnMsg = "unexpected HTTP code '%s' detected. Will use (extra) validation step in similar cases" % threadData.lastCode warnMsg = "unexpected HTTP code '%s' detected. Will use (extra) validation step in similar cases" % threadData.lastCode
singleTimeWarnMessage(warnMsg) singleTimeWarnMessage(warnMsg)
@ -439,7 +440,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, "&%d%s" % (mask, INFERENCE_GREATER_CHAR)), (expressionUnescaped, idx, 0)) forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, "&%d%s" % (mask, INFERENCE_GREATER_CHAR)), (expressionUnescaped, idx, 0))
result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False) result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique) incrementCounter(getTechnique())
if result: if result:
candidates = [_ for _ in candidates if _ & mask > 0] candidates = [_ for _ in candidates if _ & mask > 0]
@ -451,7 +452,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
if candidates: if candidates:
forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, candidates[0])) forgedPayload = safeStringFormat(payload.replace(INFERENCE_GREATER_CHAR, INFERENCE_EQUALS_CHAR), (expressionUnescaped, idx, candidates[0]))
result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False) result = Request.queryPage(forgedPayload, timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique) incrementCounter(getTechnique())
if result: if result:
return decodeIntToUnicode(candidates[0]) return decodeIntToUnicode(candidates[0])
@ -569,12 +570,12 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
# One-shot query containing equals commonValue # One-shot query containing equals commonValue
testValue = unescaper.escape("'%s'" % commonValue) if "'" not in commonValue else unescaper.escape("%s" % commonValue, quote=False) testValue = unescaper.escape("'%s'" % commonValue) if "'" not in commonValue else unescaper.escape("%s" % commonValue, quote=False)
query = kb.injection.data[kb.technique].vector query = kb.injection.data[getTechnique()].vector
query = agent.prefixQuery(query.replace(INFERENCE_MARKER, "(%s)%s%s" % (expressionUnescaped, INFERENCE_EQUALS_CHAR, testValue))) query = agent.prefixQuery(query.replace(INFERENCE_MARKER, "(%s)%s%s" % (expressionUnescaped, INFERENCE_EQUALS_CHAR, testValue)))
query = agent.suffixQuery(query) query = agent.suffixQuery(query)
result = Request.queryPage(agent.payload(newValue=query), timeBasedCompare=timeBasedCompare, raise404=False) result = Request.queryPage(agent.payload(newValue=query), timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique) incrementCounter(getTechnique())
# Did we have luck? # Did we have luck?
if result: if result:
@ -593,12 +594,12 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
subquery = queries[Backend.getIdentifiedDbms()].substring.query % (expressionUnescaped, 1, len(commonPattern)) subquery = queries[Backend.getIdentifiedDbms()].substring.query % (expressionUnescaped, 1, len(commonPattern))
testValue = unescaper.escape("'%s'" % commonPattern) if "'" not in commonPattern else unescaper.escape("%s" % commonPattern, quote=False) testValue = unescaper.escape("'%s'" % commonPattern) if "'" not in commonPattern else unescaper.escape("%s" % commonPattern, quote=False)
query = kb.injection.data[kb.technique].vector query = kb.injection.data[getTechnique()].vector
query = agent.prefixQuery(query.replace(INFERENCE_MARKER, "(%s)=%s" % (subquery, testValue))) query = agent.prefixQuery(query.replace(INFERENCE_MARKER, "(%s)=%s" % (subquery, testValue)))
query = agent.suffixQuery(query) query = agent.suffixQuery(query)
result = Request.queryPage(agent.payload(newValue=query), timeBasedCompare=timeBasedCompare, raise404=False) result = Request.queryPage(agent.payload(newValue=query), timeBasedCompare=timeBasedCompare, raise404=False)
incrementCounter(kb.technique) incrementCounter(getTechnique())
# Did we have luck? # Did we have luck?
if result: if result:
@ -678,7 +679,7 @@ def bisection(payload, expression, length=None, charsetType=None, firstChar=None
_ = finalValue or partialValue _ = finalValue or partialValue
return getCounter(kb.technique), safecharencode(_) if kb.safeCharEncode else _ return getCounter(getTechnique()), safecharencode(_) if kb.safeCharEncode else _
def queryOutputLength(expression, payload): def queryOutputLength(expression, payload):
""" """

View File

@ -21,6 +21,7 @@ from lib.core.common import extractRegexResult
from lib.core.common import firstNotNone from lib.core.common import firstNotNone
from lib.core.common import getConsoleWidth from lib.core.common import getConsoleWidth
from lib.core.common import getPartRun from lib.core.common import getPartRun
from lib.core.common import getTechnique
from lib.core.common import hashDBRetrieve from lib.core.common import hashDBRetrieve
from lib.core.common import hashDBWrite from lib.core.common import hashDBWrite
from lib.core.common import incrementCounter from lib.core.common import incrementCounter
@ -43,7 +44,6 @@ from lib.core.dicts import FROM_DUMMY_TABLE
from lib.core.enums import DBMS from lib.core.enums import DBMS
from lib.core.enums import HASHDB_KEYS from lib.core.enums import HASHDB_KEYS
from lib.core.enums import HTTP_HEADER from lib.core.enums import HTTP_HEADER
from lib.core.enums import PAYLOAD
from lib.core.exception import SqlmapDataException from lib.core.exception import SqlmapDataException
from lib.core.settings import CHECK_ZERO_COLUMNS_THRESHOLD from lib.core.settings import CHECK_ZERO_COLUMNS_THRESHOLD
from lib.core.settings import MAX_ERROR_CHUNK_LENGTH from lib.core.settings import MAX_ERROR_CHUNK_LENGTH
@ -124,7 +124,7 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False):
nulledCastedField = queries[Backend.getIdentifiedDbms()].substring.query % (nulledCastedField, offset, kb.errorChunkLength) nulledCastedField = queries[Backend.getIdentifiedDbms()].substring.query % (nulledCastedField, offset, kb.errorChunkLength)
# Forge the error-based SQL injection request # Forge the error-based SQL injection request
vector = kb.injection.data[PAYLOAD.TECHNIQUE.ERROR].vector vector = kb.injection.data[getTechnique()].vector
query = agent.prefixQuery(vector) query = agent.prefixQuery(vector)
query = agent.suffixQuery(query) query = agent.suffixQuery(query)
injExpression = expression.replace(field, nulledCastedField, 1) if field else expression injExpression = expression.replace(field, nulledCastedField, 1) if field else expression
@ -135,7 +135,7 @@ def _oneShotErrorUse(expression, field=None, chunkTest=False):
# Perform the request # Perform the request
page, headers, _ = Request.queryPage(payload, content=True, raise404=False) page, headers, _ = Request.queryPage(payload, content=True, raise404=False)
incrementCounter(PAYLOAD.TECHNIQUE.ERROR) incrementCounter(getTechnique())
if page and conf.noEscape: if page and conf.noEscape:
page = re.sub(r"('|\%%27)%s('|\%%27).*?('|\%%27)%s('|\%%27)" % (kb.chars.start, kb.chars.stop), "", page) page = re.sub(r"('|\%%27)%s('|\%%27).*?('|\%%27)%s('|\%%27)" % (kb.chars.start, kb.chars.stop), "", page)
@ -299,7 +299,7 @@ def errorUse(expression, dump=False):
SQL injection vulnerability on the affected parameter. SQL injection vulnerability on the affected parameter.
""" """
initTechnique(PAYLOAD.TECHNIQUE.ERROR) initTechnique(getTechnique())
abortedFlag = False abortedFlag = False
count = None count = None
@ -461,7 +461,7 @@ def errorUse(expression, dump=False):
duration = calculateDeltaSeconds(start) duration = calculateDeltaSeconds(start)
if not kb.bruteMode: if not kb.bruteMode:
debugMsg = "performed %d queries in %.2f seconds" % (kb.counters[PAYLOAD.TECHNIQUE.ERROR], duration) debugMsg = "performed %d queries in %.2f seconds" % (kb.counters[getTechnique()], duration)
logger.debug(debugMsg) logger.debug(debugMsg)
return value return value

View File

@ -20,6 +20,7 @@ from lib.core.common import randomInt
from lib.core.common import randomStr from lib.core.common import randomStr
from lib.core.common import readInput from lib.core.common import readInput
from lib.core.common import removeReflectiveValues from lib.core.common import removeReflectiveValues
from lib.core.common import setTechnique
from lib.core.common import singleTimeLogMessage from lib.core.common import singleTimeLogMessage
from lib.core.common import singleTimeWarnMessage from lib.core.common import singleTimeWarnMessage
from lib.core.common import stdev from lib.core.common import stdev
@ -323,7 +324,7 @@ def unionTest(comment, place, parameter, value, prefix, suffix):
return return
negativeLogic = kb.negativeLogic negativeLogic = kb.negativeLogic
kb.technique = PAYLOAD.TECHNIQUE.UNION setTechnique(PAYLOAD.TECHNIQUE.UNION)
try: try:
if negativeLogic: if negativeLogic: