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 filterNone
from lib.core.common import getSQLSnippet
from lib.core.common import getTechnique
from lib.core.common import isDBMSVersionAtLeast
from lib.core.common import isNumber
from lib.core.common import isTechniqueAvailable
@@ -89,8 +90,8 @@ class Agent(object):
if kb.forceWhere:
where = kb.forceWhere
elif where is None and isTechniqueAvailable(kb.technique):
where = kb.injection.data[kb.technique].where
elif where is None and isTechniqueAvailable(getTechnique()):
where = kb.injection.data[getTechnique()].where
if kb.injection.place is not None:
place = kb.injection.place
@@ -234,8 +235,8 @@ class Agent(object):
expression = unescaper.escape(expression)
query = None
if where is None and kb.technique and kb.technique in kb.injection.data:
where = kb.injection.data[kb.technique].where
if where is None and getTechnique() is not None and getTechnique() in kb.injection.data:
where = kb.injection.data[getTechnique()].where
# If we are replacing (<where>) the parameter original value with
# 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
# 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
elif kb.injection.clause == [2, 3] or kb.injection.clause == [2] or kb.injection.clause == [3]:
query = kb.injection.prefix
@@ -282,9 +283,9 @@ class Agent(object):
# Take default values if None
suffix = kb.injection.suffix if kb.injection and suffix is None else suffix
if kb.technique and kb.technique in kb.injection.data:
where = kb.injection.data[kb.technique].where if where is None else where
comment = kb.injection.data[kb.technique].comment if comment is None else comment
if getTechnique() is not None and getTechnique() in kb.injection.data:
where = kb.injection.data[getTechnique()].where if where is None else where
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]")):
comment = queries[DBMS.ACCESS].comment.query

View File

@@ -1125,6 +1125,20 @@ def readInput(message, default=None, checkBatch=True, boolean=False):
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):
"""
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
>>> pushValue(kb.injection.data)
>>> pushValue(kb.technique)
>>> kb.technique = PAYLOAD.TECHNIQUE.STACKED
>>> kb.injection.data[kb.technique] = [test for test in getSortedInjectionTests() if "heavy" in test["title"].lower()][0]
>>> setTechnique(PAYLOAD.TECHNIQUE.STACKED)
>>> kb.injection.data[getTechnique()] = [test for test in getSortedInjectionTests() if "heavy" in test["title"].lower()][0]
>>> isHeavyQueryBased()
True
>>> kb.technique = popValue()
>>> kb.injection.data = popValue()
"""
retVal = False
technique = technique or kb.technique
technique = technique or getTechnique()
if isTechniqueAvailable(technique):
data = getTechniqueData(technique)
@@ -3630,7 +3642,7 @@ def unhandledExceptionMessage():
errMsg += "Python version: %s\n" % PYVERSION
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 += "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:"
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
# 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_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)

View File

@@ -63,6 +63,7 @@ class _ThreadData(threading.local):
self.retriesCount = 0
self.seqMatcher = difflib.SequenceMatcher(None)
self.shared = shared
self.technique = None
self.validationRun = 0
self.valueStack = []
@@ -113,6 +114,7 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio
kb.threadContinue = True
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)):
while True:
@@ -206,6 +208,7 @@ def runThreads(numThreads, threadFunction, cleanupFunction=None, forwardExceptio
finally:
kb.threadContinue = True
kb.threadException = False
kb.technique = None
for lock in kb.locks.values():
if lock.locked():