mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-01-23 15:54:24 +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 HTTP_HEADER
|
||||
from lib.core.enums import HTTPMETHOD
|
||||
from lib.core.enums import NOTE
|
||||
from lib.core.enums import NULLCONNECTION
|
||||
from lib.core.enums import PAYLOAD
|
||||
from lib.core.enums import PLACE
|
||||
|
@ -696,10 +697,10 @@ def checkSqlInjection(place, parameter, value):
|
|||
warnMsg += "problems during data retrieval"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
injection = checkFalsePositives(injection)
|
||||
|
||||
if not injection:
|
||||
if not checkFalsePositives(injection):
|
||||
kb.vulnHosts.remove(conf.hostname)
|
||||
injection.notes.add(NOTE.FALSE_POSITIVE_OR_UNEXPLOITABLE)
|
||||
|
||||
else:
|
||||
injection = None
|
||||
|
||||
|
@ -748,7 +749,7 @@ def checkFalsePositives(injection):
|
|||
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\
|
||||
(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
|
||||
|
||||
if not checkBooleanExpression("%d=%d" % (randInt1, randInt1)):
|
||||
retVal = None
|
||||
retVal = False
|
||||
break
|
||||
|
||||
# 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))
|
||||
|
||||
if checkBooleanExpression("%d=%d" % (randInt1, randInt3)): # this must not be evaluated to True
|
||||
retVal = None
|
||||
retVal = False
|
||||
break
|
||||
|
||||
elif checkBooleanExpression("%d=%d" % (randInt3, randInt2)): # this must not be evaluated to True
|
||||
retVal = None
|
||||
retVal = False
|
||||
break
|
||||
|
||||
elif not checkBooleanExpression("%d=%d" % (randInt2, randInt2)): # this must be evaluated to True
|
||||
retVal = None
|
||||
retVal = False
|
||||
break
|
||||
|
||||
elif checkBooleanExpression("%d %d" % (randInt3, randInt2)): # this must not be evaluated to True (invalid statement)
|
||||
retVal = None
|
||||
retVal = False
|
||||
break
|
||||
|
||||
if retVal is None:
|
||||
if not retVal:
|
||||
warnMsg = "false positive or unexploitable injection point detected"
|
||||
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 HEURISTIC_TEST
|
||||
from lib.core.enums import HTTPMETHOD
|
||||
from lib.core.enums import NOTE
|
||||
from lib.core.enums import PAYLOAD
|
||||
from lib.core.enums import PLACE
|
||||
from lib.core.exception import SqlmapBaseException
|
||||
|
@ -225,23 +226,23 @@ def _saveToResultsFile():
|
|||
results = {}
|
||||
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:
|
||||
continue
|
||||
|
||||
key = (inj.place, inj.parameter)
|
||||
key = (inj.place, inj.parameter, ';'.join(inj.notes))
|
||||
if key not in results:
|
||||
results[key] = []
|
||||
|
||||
results[key].extend(inj.data.keys())
|
||||
|
||||
for key, value in results.items():
|
||||
place, parameter = 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)
|
||||
place, parameter, notes = key
|
||||
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)
|
||||
|
||||
if not results:
|
||||
line = "%s,,,%s" % (conf.url, os.linesep)
|
||||
line = "%s,,,,%s" % (conf.url, os.linesep)
|
||||
conf.resultsFP.writelines(line)
|
||||
|
||||
def start():
|
||||
|
@ -522,7 +523,10 @@ def start():
|
|||
proceed = not kb.endDetection
|
||||
|
||||
if getattr(injection, "place", None) is not None:
|
||||
kb.injections.append(injection)
|
||||
if NOTE.FALSE_POSITIVE_OR_UNEXPLOITABLE in injection.notes:
|
||||
kb.falsePositives.append(injection)
|
||||
else:
|
||||
kb.injections.append(injection)
|
||||
|
||||
# In case when user wants to end detection phase (Ctrl+C)
|
||||
if not proceed:
|
||||
|
@ -651,6 +655,8 @@ def start():
|
|||
errMsg = getSafeExString(ex)
|
||||
|
||||
if conf.multipleTargets:
|
||||
_saveToResultsFile()
|
||||
|
||||
errMsg += ", skipping to the next %s" % ("form" if conf.forms else "URL")
|
||||
logger.error(errMsg)
|
||||
else:
|
||||
|
@ -669,9 +675,10 @@ def start():
|
|||
if kb.dataOutputFlag and not conf.multipleTargets:
|
||||
logger.info("fetched data logged to text files under '%s'" % conf.outputPath)
|
||||
|
||||
if conf.multipleTargets and conf.resultsFilename:
|
||||
infoMsg = "you can find results of scanning in multiple targets "
|
||||
infoMsg += "mode inside the CSV file '%s'" % conf.resultsFilename
|
||||
logger.info(infoMsg)
|
||||
if conf.multipleTargets:
|
||||
if conf.resultsFilename:
|
||||
infoMsg = "you can find results of scanning in multiple targets "
|
||||
infoMsg += "mode inside the CSV file '%s'" % conf.resultsFilename
|
||||
logger.info(infoMsg)
|
||||
|
||||
return True
|
||||
|
|
|
@ -93,6 +93,7 @@ class InjectionDict(AttribDict):
|
|||
self.prefix = None
|
||||
self.suffix = None
|
||||
self.clause = None
|
||||
self.notes = set()
|
||||
|
||||
# data is a dict with various stype, each which is a dict with
|
||||
# all the information specific for that stype
|
||||
|
|
|
@ -351,3 +351,6 @@ class AUTOCOMPLETE_TYPE:
|
|||
SQL = 0
|
||||
OS = 1
|
||||
SQLMAP = 2
|
||||
|
||||
class NOTE:
|
||||
FALSE_POSITIVE_OR_UNEXPLOITABLE = "false positive or unexploitable"
|
||||
|
|
|
@ -1838,6 +1838,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
|
|||
kb.extendTests = None
|
||||
kb.errorChunkLength = None
|
||||
kb.errorIsNone = True
|
||||
kb.falsePositives = []
|
||||
kb.fileReadMode = False
|
||||
kb.followSitemapRecursion = None
|
||||
kb.forcedDbms = None
|
||||
|
|
|
@ -19,7 +19,7 @@ from lib.core.enums import OS
|
|||
from lib.core.revision import getRevisionNumber
|
||||
|
||||
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
||||
VERSION = "1.0.5.14"
|
||||
VERSION = "1.0.5.15"
|
||||
REVISION = getRevisionNumber()
|
||||
STABLE = VERSION.count('.') <= 2
|
||||
VERSION_STRING = "sqlmap/%s#%s" % (VERSION, "stable" if STABLE else "dev")
|
||||
|
@ -530,7 +530,7 @@ HASHDB_FLUSH_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)
|
||||
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
|
||||
LARGE_OUTPUT_THRESHOLD = 1024 ** 2
|
||||
|
|
|
@ -542,7 +542,7 @@ def _setResultsFile():
|
|||
errMsg += "create temporary files and/or directories"
|
||||
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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user