Implementation for an Issue #363

This commit is contained in:
Miroslav Stampar 2013-02-01 17:24:04 +01:00
parent 231ea51fe6
commit e7b93b5b66
3 changed files with 46 additions and 44 deletions

View File

@ -85,6 +85,24 @@ def checkSqlInjection(place, parameter, value):
if kb.endDetection: if kb.endDetection:
break break
if conf.dbms is None:
if not injection.dbms and PAYLOAD.TECHNIQUE.BOOLEAN in injection.data:
if not Backend.getIdentifiedDbms() and not kb.heuristicDbms:
kb.heuristicDbms = heuristicCheckDbms(injection) or UNKNOWN_DBMS
if not conf.testFilter and (Backend.getErrorParsedDBMSes() or kb.heuristicDbms) not in ([], None, UNKNOWN_DBMS):
if kb.reduceTests is None and Backend.getErrorParsedDBMSes():
msg = "heuristic (parsing) test showed that the "
msg += "back-end DBMS could be '%s'. " % (Format.getErrorParsedDBMSes() if Backend.getErrorParsedDBMSes() else kb.heuristicDbms)
msg += "Do you want to skip test payloads specific for other DBMSes? [Y/n]"
kb.reduceTests = [] if readInput(msg, default='Y').upper() != 'Y' else (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms])
if kb.extendTests is None:
_ = (Format.getErrorParsedDBMSes() if Backend.getErrorParsedDBMSes() else kb.heuristicDbms)
msg = "do you want to include all tests for '%s' " % _
msg += "ignoring provided level (%d) and risk (%s)? [Y/n]" % (conf.level, conf.risk)
kb.extendTests = [] if readInput(msg, default='Y').upper() != 'Y' else (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms])
title = test.title title = test.title
stype = test.stype stype = test.stype
clause = test.clause clause = test.clause
@ -143,15 +161,24 @@ def checkSqlInjection(place, parameter, value):
logger.debug(debugMsg) logger.debug(debugMsg)
continue continue
# Skip DBMS-specific test if it does not match either the
# previously identified or the user's provided DBMS (either
# from program switch or from parsed error message(s))
if "details" in test and "dbms" in test.details:
dbms = test.details.dbms
else:
dbms = None
# Skip tests if title is not included by the given filter # Skip tests if title is not included by the given filter
if conf.testFilter: if conf.testFilter:
if not any(re.search(conf.testFilter, str(item), re.I) for item in (test.title, test.vector,\ if not any(re.search(conf.testFilter, str(item), re.I) for item in (test.title, test.vector, dbms)):
test.details.dbms if "details" in test and "dbms" in test.details else "")):
debugMsg = "skipping test '%s' because " % title debugMsg = "skipping test '%s' because " % title
debugMsg += "its name/vector/dbms is not included by the given filter" debugMsg += "its name/vector/dbms is not included by the given filter"
logger.debug(debugMsg) logger.debug(debugMsg)
continue continue
else:
if not (kb.extendTests and intersect(dbms, kb.extendTests)):
# Skip test if the risk is higher than the provided (or default) # Skip test if the risk is higher than the provided (or default)
# value # value
# Parse test's <risk> # Parse test's <risk>
@ -170,14 +197,6 @@ def checkSqlInjection(place, parameter, value):
logger.debug(debugMsg) logger.debug(debugMsg)
continue continue
# Skip DBMS-specific test if it does not match either the
# previously identified or the user's provided DBMS (either
# from program switch or from parsed error message(s))
if "details" in test and "dbms" in test.details:
dbms = test.details.dbms
else:
dbms = None
if dbms is not None: if dbms is not None:
if injection.dbms is not None and not intersect(injection.dbms, dbms): if injection.dbms is not None and not intersect(injection.dbms, dbms):
debugMsg = "skipping test '%s' because " % title debugMsg = "skipping test '%s' because " % title
@ -192,17 +211,7 @@ def checkSqlInjection(place, parameter, value):
logger.debug(debugMsg) logger.debug(debugMsg)
continue continue
if conf.dbms is None and len(Backend.getErrorParsedDBMSes()) > 0 and not intersect(dbms, Backend.getErrorParsedDBMSes()) and kb.skipOthersDbms is None: if kb.reduceTests and not intersect(dbms, kb.reduceTests):
msg = "parsed error message(s) showed that the "
msg += "back-end DBMS could be %s. " % Format.getErrorParsedDBMSes()
msg += "Do you want to skip test payloads specific for other DBMSes? [Y/n]"
if readInput(msg, default="Y") in ("y", "Y"):
kb.skipOthersDbms = Backend.getErrorParsedDBMSes()
else:
kb.skipOthersDbms = []
if kb.skipOthersDbms and not intersect(dbms, kb.skipOthersDbms):
debugMsg = "skipping test '%s' because " % title debugMsg = "skipping test '%s' because " % title
debugMsg += "the parsed error message(s) showed " debugMsg += "the parsed error message(s) showed "
debugMsg += "that the back-end DBMS could be " debugMsg += "that the back-end DBMS could be "
@ -549,20 +558,12 @@ def checkSqlInjection(place, parameter, value):
# Reset forced back-end DBMS value # Reset forced back-end DBMS value
Backend.flushForcedDbms() Backend.flushForcedDbms()
if len(injection.data) == 1 and PAYLOAD.TECHNIQUE.BOOLEAN in injection.data:
if not Backend.getIdentifiedDbms() and kb.heuristicDbms in (None, UNKNOWN_DBMS):
kb.heuristicDbms = heuristicCheckDbms(injection) or UNKNOWN_DBMS
if Backend.getIdentifiedDbms() or kb.heuristicDbms not in (None, UNKNOWN_DBMS):
#do you want to extend <- one time question!!!!!!!!!! (mirek)
pass
except KeyboardInterrupt: except KeyboardInterrupt:
warnMsg = "user aborted during detection phase" warnMsg = "user aborted during detection phase"
logger.warn(warnMsg) logger.warn(warnMsg)
message = "How do you want to proceed? [(S)kip current test/(e)nd detection phase/(n)ext parameter/(q)uit]" msg = "How do you want to proceed? [(S)kip current test/(e)nd detection phase/(n)ext parameter/(q)uit]"
choice = readInput(message, default="S", checkBatch=False) choice = readInput(msg, default="S", checkBatch=False)
if choice[0] in ("s", "S"): if choice[0] in ("s", "S"):
pass pass
@ -615,7 +616,7 @@ def heuristicCheckDbms(injection):
kb.injection = popValue() kb.injection = popValue()
if retVal: if retVal:
infoMsg = "heuristic test showed that the back-end DBMS " infoMsg = "heuristic (extended) test shows that the back-end DBMS " # not as important as "parsing" counter-part (because of false-positives)
infoMsg += "could be '%s' " % retVal infoMsg += "could be '%s' " % retVal
logger.info(infoMsg) logger.info(infoMsg)
@ -729,7 +730,7 @@ def heuristicCheckSqlInjection(place, parameter):
parseFilePaths(page) parseFilePaths(page)
result = wasLastResponseDBMSError() result = wasLastResponseDBMSError()
infoMsg = "heuristic test shows that %s " % place infoMsg = "heuristic (parsing) test shows that %s " % place
infoMsg += "parameter '%s' might " % parameter infoMsg += "parameter '%s' might " % parameter
def _(page): def _(page):
@ -762,7 +763,7 @@ def heuristicCheckSqlInjection(place, parameter):
kb.ignoreCasted = readInput(message, default='Y' if conf.multipleTargets else 'N').upper() != 'N' kb.ignoreCasted = readInput(message, default='Y' if conf.multipleTargets else 'N').upper() != 'N'
elif result: elif result:
infoMsg += "be injectable (possible DBMS: %s)" % (Format.getErrorParsedDBMSes() or UNKNOWN_DBMS) infoMsg += "be injectable (possible DBMS: '%s')" % (Format.getErrorParsedDBMSes() or UNKNOWN_DBMS)
logger.info(infoMsg) logger.info(infoMsg)
else: else:

View File

@ -1525,6 +1525,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.dynamicParameter = False kb.dynamicParameter = False
kb.endDetection = False kb.endDetection = False
kb.explicitSettings = set() kb.explicitSettings = set()
kb.extendTests = None
kb.errorIsNone = True kb.errorIsNone = True
kb.fileReadMode = False kb.fileReadMode = False
kb.forcedDbms = None kb.forcedDbms = None
@ -1552,12 +1553,6 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.multiThreadMode = False kb.multiThreadMode = False
kb.negativeLogic = False kb.negativeLogic = False
kb.nullConnection = None kb.nullConnection = None
kb.pageCompress = True
kb.pageTemplate = None
kb.pageTemplates = dict()
kb.postHint = None
kb.previousMethod = None
kb.processUserMarks = None
kb.orderByColumns = None kb.orderByColumns = None
kb.originalCode = None kb.originalCode = None
kb.originalPage = None kb.originalPage = None
@ -1570,12 +1565,19 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.osVersion = None kb.osVersion = None
kb.osSP = None kb.osSP = None
kb.pageCompress = True
kb.pageTemplate = None
kb.pageTemplates = dict()
kb.pageEncoding = DEFAULT_PAGE_ENCODING kb.pageEncoding = DEFAULT_PAGE_ENCODING
kb.pageStable = None kb.pageStable = None
kb.partRun = None kb.partRun = None
kb.permissionFlag = False kb.permissionFlag = False
kb.postHint = None
kb.postSpaceToPlus = False
kb.prependFlag = False kb.prependFlag = False
kb.processResponseCounter = 0 kb.processResponseCounter = 0
kb.previousMethod = None
kb.processUserMarks = None
kb.proxyAuthHeader = None kb.proxyAuthHeader = None
kb.queryCounter = 0 kb.queryCounter = 0
kb.redirectChoice = None kb.redirectChoice = None
@ -1588,8 +1590,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.resumeValues = True kb.resumeValues = True
kb.safeCharEncode = False kb.safeCharEncode = False
kb.singleLogFlags = set() kb.singleLogFlags = set()
kb.skipOthersDbms = None kb.reduceTests = None
kb.postSpaceToPlus = False
kb.stickyDBMS = False kb.stickyDBMS = False
kb.stickyLevel = None kb.stickyLevel = None
kb.suppressResumeInfo = False kb.suppressResumeInfo = False

View File

@ -466,7 +466,7 @@ VALID_TIME_CHARS_RUN_THRESHOLD = 100
CHECK_ZERO_COLUMNS_THRESHOLD = 10 CHECK_ZERO_COLUMNS_THRESHOLD = 10
# Boldify all logger messages containing these "patterns" # Boldify all logger messages containing these "patterns"
BOLD_PATTERNS = ("' injectable", "might be injectable", "' is vulnerable", "is not injectable", "test failed", "test passed", "live test final result", "heuristic test showed") BOLD_PATTERNS = ("' injectable", "might be injectable", "' is vulnerable", "is not injectable", "test failed", "test passed", "live test final result", "test shows that")
# Generic www root directory names # Generic www root directory names
GENERIC_DOC_ROOT_DIRECTORY_NAMES = ("htdocs", "wwwroot", "www") GENERIC_DOC_ROOT_DIRECTORY_NAMES = ("htdocs", "wwwroot", "www")