This commit is contained in:
Miroslav Stampar 2016-05-06 13:06:59 +02:00
parent 5d09f7b85f
commit be9381abc5
7 changed files with 36 additions and 23 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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)