mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-01-24 00:04:23 +03:00
Implements #1845
This commit is contained in:
parent
5d09f7b85f
commit
be9381abc5
|
@ -55,6 +55,7 @@ from lib.core.enums import HASHDB_KEYS
|
||||||
from lib.core.enums import HEURISTIC_TEST
|
from lib.core.enums import HEURISTIC_TEST
|
||||||
from lib.core.enums import HTTP_HEADER
|
from lib.core.enums import HTTP_HEADER
|
||||||
from lib.core.enums import HTTPMETHOD
|
from lib.core.enums import HTTPMETHOD
|
||||||
|
from lib.core.enums import NOTE
|
||||||
from lib.core.enums import NULLCONNECTION
|
from lib.core.enums import NULLCONNECTION
|
||||||
from lib.core.enums import PAYLOAD
|
from lib.core.enums import PAYLOAD
|
||||||
from lib.core.enums import PLACE
|
from lib.core.enums import PLACE
|
||||||
|
@ -696,10 +697,10 @@ def checkSqlInjection(place, parameter, value):
|
||||||
warnMsg += "problems during data retrieval"
|
warnMsg += "problems during data retrieval"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
injection = checkFalsePositives(injection)
|
if not checkFalsePositives(injection):
|
||||||
|
|
||||||
if not injection:
|
|
||||||
kb.vulnHosts.remove(conf.hostname)
|
kb.vulnHosts.remove(conf.hostname)
|
||||||
|
injection.notes.add(NOTE.FALSE_POSITIVE_OR_UNEXPLOITABLE)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
injection = None
|
injection = None
|
||||||
|
|
||||||
|
@ -748,7 +749,7 @@ def checkFalsePositives(injection):
|
||||||
Checks for false positives (only in single special cases)
|
Checks for false positives (only in single special cases)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
retVal = injection
|
retVal = True
|
||||||
|
|
||||||
if all(_ in (PAYLOAD.TECHNIQUE.BOOLEAN, PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED) for _ in injection.data) or\
|
if all(_ in (PAYLOAD.TECHNIQUE.BOOLEAN, PAYLOAD.TECHNIQUE.TIME, PAYLOAD.TECHNIQUE.STACKED) for _ in injection.data) or\
|
||||||
(len(injection.data) == 1 and PAYLOAD.TECHNIQUE.UNION in injection.data and "Generic" in injection.data[PAYLOAD.TECHNIQUE.UNION].title):
|
(len(injection.data) == 1 and PAYLOAD.TECHNIQUE.UNION in injection.data and "Generic" in injection.data[PAYLOAD.TECHNIQUE.UNION].title):
|
||||||
|
@ -774,7 +775,7 @@ def checkFalsePositives(injection):
|
||||||
break
|
break
|
||||||
|
|
||||||
if not checkBooleanExpression("%d=%d" % (randInt1, randInt1)):
|
if not checkBooleanExpression("%d=%d" % (randInt1, randInt1)):
|
||||||
retVal = None
|
retVal = False
|
||||||
break
|
break
|
||||||
|
|
||||||
# Just in case if DBMS hasn't properly recovered from previous delayed request
|
# Just in case if DBMS hasn't properly recovered from previous delayed request
|
||||||
|
@ -782,22 +783,22 @@ def checkFalsePositives(injection):
|
||||||
checkBooleanExpression("%d=%d" % (randInt1, randInt2))
|
checkBooleanExpression("%d=%d" % (randInt1, randInt2))
|
||||||
|
|
||||||
if checkBooleanExpression("%d=%d" % (randInt1, randInt3)): # this must not be evaluated to True
|
if checkBooleanExpression("%d=%d" % (randInt1, randInt3)): # this must not be evaluated to True
|
||||||
retVal = None
|
retVal = False
|
||||||
break
|
break
|
||||||
|
|
||||||
elif checkBooleanExpression("%d=%d" % (randInt3, randInt2)): # this must not be evaluated to True
|
elif checkBooleanExpression("%d=%d" % (randInt3, randInt2)): # this must not be evaluated to True
|
||||||
retVal = None
|
retVal = False
|
||||||
break
|
break
|
||||||
|
|
||||||
elif not checkBooleanExpression("%d=%d" % (randInt2, randInt2)): # this must be evaluated to True
|
elif not checkBooleanExpression("%d=%d" % (randInt2, randInt2)): # this must be evaluated to True
|
||||||
retVal = None
|
retVal = False
|
||||||
break
|
break
|
||||||
|
|
||||||
elif checkBooleanExpression("%d %d" % (randInt3, randInt2)): # this must not be evaluated to True (invalid statement)
|
elif checkBooleanExpression("%d %d" % (randInt3, randInt2)): # this must not be evaluated to True (invalid statement)
|
||||||
retVal = None
|
retVal = False
|
||||||
break
|
break
|
||||||
|
|
||||||
if retVal is None:
|
if not retVal:
|
||||||
warnMsg = "false positive or unexploitable injection point detected"
|
warnMsg = "false positive or unexploitable injection point detected"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ from lib.core.enums import CONTENT_TYPE
|
||||||
from lib.core.enums import HASHDB_KEYS
|
from lib.core.enums import HASHDB_KEYS
|
||||||
from lib.core.enums import HEURISTIC_TEST
|
from lib.core.enums import HEURISTIC_TEST
|
||||||
from lib.core.enums import HTTPMETHOD
|
from lib.core.enums import HTTPMETHOD
|
||||||
|
from lib.core.enums import NOTE
|
||||||
from lib.core.enums import PAYLOAD
|
from lib.core.enums import PAYLOAD
|
||||||
from lib.core.enums import PLACE
|
from lib.core.enums import PLACE
|
||||||
from lib.core.exception import SqlmapBaseException
|
from lib.core.exception import SqlmapBaseException
|
||||||
|
@ -225,23 +226,23 @@ def _saveToResultsFile():
|
||||||
results = {}
|
results = {}
|
||||||
techniques = dict(map(lambda x: (x[1], x[0]), getPublicTypeMembers(PAYLOAD.TECHNIQUE)))
|
techniques = dict(map(lambda x: (x[1], x[0]), getPublicTypeMembers(PAYLOAD.TECHNIQUE)))
|
||||||
|
|
||||||
for inj in kb.injections:
|
for inj in kb.injections + kb.falsePositives:
|
||||||
if inj.place is None or inj.parameter is None:
|
if inj.place is None or inj.parameter is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
key = (inj.place, inj.parameter)
|
key = (inj.place, inj.parameter, ';'.join(inj.notes))
|
||||||
if key not in results:
|
if key not in results:
|
||||||
results[key] = []
|
results[key] = []
|
||||||
|
|
||||||
results[key].extend(inj.data.keys())
|
results[key].extend(inj.data.keys())
|
||||||
|
|
||||||
for key, value in results.items():
|
for key, value in results.items():
|
||||||
place, parameter = key
|
place, parameter, notes = key
|
||||||
line = "%s,%s,%s,%s%s" % (safeCSValue(kb.originalUrls.get(conf.url) or conf.url), place, parameter, "".join(map(lambda x: techniques[x][0].upper(), sorted(value))), os.linesep)
|
line = "%s,%s,%s,%s,%s%s" % (safeCSValue(kb.originalUrls.get(conf.url) or conf.url), place, parameter, "".join(map(lambda x: techniques[x][0].upper(), sorted(value))), notes, os.linesep)
|
||||||
conf.resultsFP.writelines(line)
|
conf.resultsFP.writelines(line)
|
||||||
|
|
||||||
if not results:
|
if not results:
|
||||||
line = "%s,,,%s" % (conf.url, os.linesep)
|
line = "%s,,,,%s" % (conf.url, os.linesep)
|
||||||
conf.resultsFP.writelines(line)
|
conf.resultsFP.writelines(line)
|
||||||
|
|
||||||
def start():
|
def start():
|
||||||
|
@ -522,6 +523,9 @@ def start():
|
||||||
proceed = not kb.endDetection
|
proceed = not kb.endDetection
|
||||||
|
|
||||||
if getattr(injection, "place", None) is not None:
|
if getattr(injection, "place", None) is not None:
|
||||||
|
if NOTE.FALSE_POSITIVE_OR_UNEXPLOITABLE in injection.notes:
|
||||||
|
kb.falsePositives.append(injection)
|
||||||
|
else:
|
||||||
kb.injections.append(injection)
|
kb.injections.append(injection)
|
||||||
|
|
||||||
# In case when user wants to end detection phase (Ctrl+C)
|
# In case when user wants to end detection phase (Ctrl+C)
|
||||||
|
@ -651,6 +655,8 @@ def start():
|
||||||
errMsg = getSafeExString(ex)
|
errMsg = getSafeExString(ex)
|
||||||
|
|
||||||
if conf.multipleTargets:
|
if conf.multipleTargets:
|
||||||
|
_saveToResultsFile()
|
||||||
|
|
||||||
errMsg += ", skipping to the next %s" % ("form" if conf.forms else "URL")
|
errMsg += ", skipping to the next %s" % ("form" if conf.forms else "URL")
|
||||||
logger.error(errMsg)
|
logger.error(errMsg)
|
||||||
else:
|
else:
|
||||||
|
@ -669,7 +675,8 @@ def start():
|
||||||
if kb.dataOutputFlag and not conf.multipleTargets:
|
if kb.dataOutputFlag and not conf.multipleTargets:
|
||||||
logger.info("fetched data logged to text files under '%s'" % conf.outputPath)
|
logger.info("fetched data logged to text files under '%s'" % conf.outputPath)
|
||||||
|
|
||||||
if conf.multipleTargets and conf.resultsFilename:
|
if conf.multipleTargets:
|
||||||
|
if conf.resultsFilename:
|
||||||
infoMsg = "you can find results of scanning in multiple targets "
|
infoMsg = "you can find results of scanning in multiple targets "
|
||||||
infoMsg += "mode inside the CSV file '%s'" % conf.resultsFilename
|
infoMsg += "mode inside the CSV file '%s'" % conf.resultsFilename
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
|
@ -93,6 +93,7 @@ class InjectionDict(AttribDict):
|
||||||
self.prefix = None
|
self.prefix = None
|
||||||
self.suffix = None
|
self.suffix = None
|
||||||
self.clause = None
|
self.clause = None
|
||||||
|
self.notes = set()
|
||||||
|
|
||||||
# data is a dict with various stype, each which is a dict with
|
# data is a dict with various stype, each which is a dict with
|
||||||
# all the information specific for that stype
|
# all the information specific for that stype
|
||||||
|
|
|
@ -351,3 +351,6 @@ class AUTOCOMPLETE_TYPE:
|
||||||
SQL = 0
|
SQL = 0
|
||||||
OS = 1
|
OS = 1
|
||||||
SQLMAP = 2
|
SQLMAP = 2
|
||||||
|
|
||||||
|
class NOTE:
|
||||||
|
FALSE_POSITIVE_OR_UNEXPLOITABLE = "false positive or unexploitable"
|
||||||
|
|
|
@ -1838,6 +1838,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
||||||
kb.extendTests = None
|
kb.extendTests = None
|
||||||
kb.errorChunkLength = None
|
kb.errorChunkLength = None
|
||||||
kb.errorIsNone = True
|
kb.errorIsNone = True
|
||||||
|
kb.falsePositives = []
|
||||||
kb.fileReadMode = False
|
kb.fileReadMode = False
|
||||||
kb.followSitemapRecursion = None
|
kb.followSitemapRecursion = None
|
||||||
kb.forcedDbms = None
|
kb.forcedDbms = None
|
||||||
|
|
|
@ -19,7 +19,7 @@ from lib.core.enums import OS
|
||||||
from lib.core.revision import getRevisionNumber
|
from lib.core.revision import getRevisionNumber
|
||||||
|
|
||||||
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
||||||
VERSION = "1.0.5.14"
|
VERSION = "1.0.5.15"
|
||||||
REVISION = getRevisionNumber()
|
REVISION = getRevisionNumber()
|
||||||
STABLE = VERSION.count('.') <= 2
|
STABLE = VERSION.count('.') <= 2
|
||||||
VERSION_STRING = "sqlmap/%s#%s" % (VERSION, "stable" if STABLE else "dev")
|
VERSION_STRING = "sqlmap/%s#%s" % (VERSION, "stable" if STABLE else "dev")
|
||||||
|
@ -530,7 +530,7 @@ HASHDB_FLUSH_RETRIES = 3
|
||||||
HASHDB_END_TRANSACTION_RETRIES = 3
|
HASHDB_END_TRANSACTION_RETRIES = 3
|
||||||
|
|
||||||
# Unique milestone value used for forced deprecation of old HashDB values (e.g. when changing hash/pickle mechanism)
|
# Unique milestone value used for forced deprecation of old HashDB values (e.g. when changing hash/pickle mechanism)
|
||||||
HASHDB_MILESTONE_VALUE = "WVMqopmuzX" # "".join(random.sample(string.ascii_letters, 10))
|
HASHDB_MILESTONE_VALUE = "zYwqRDymvj" # "".join(random.sample(string.ascii_letters, 10))
|
||||||
|
|
||||||
# Warn user of possible delay due to large page dump in full UNION query injections
|
# Warn user of possible delay due to large page dump in full UNION query injections
|
||||||
LARGE_OUTPUT_THRESHOLD = 1024 ** 2
|
LARGE_OUTPUT_THRESHOLD = 1024 ** 2
|
||||||
|
|
|
@ -542,7 +542,7 @@ def _setResultsFile():
|
||||||
errMsg += "create temporary files and/or directories"
|
errMsg += "create temporary files and/or directories"
|
||||||
raise SqlmapSystemException(errMsg)
|
raise SqlmapSystemException(errMsg)
|
||||||
|
|
||||||
conf.resultsFP.writelines("Target URL,Place,Parameter,Techniques%s" % os.linesep)
|
conf.resultsFP.writelines("Target URL,Place,Parameter,Technique(s),Note(s)%s" % os.linesep)
|
||||||
|
|
||||||
logger.info("using '%s' as the CSV results file in multiple targets mode" % conf.resultsFilename)
|
logger.info("using '%s' as the CSV results file in multiple targets mode" % conf.resultsFilename)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user