mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2024-11-29 21:13:51 +03:00
rework some of the logic of the detection phase based on identified DBMS along the way
This commit is contained in:
parent
4f939b5719
commit
52dd92748a
|
@ -64,6 +64,7 @@ from lib.core.settings import DUMMY_XSS_CHECK_APPENDIX
|
||||||
from lib.core.settings import FORMAT_EXCEPTION_STRINGS
|
from lib.core.settings import FORMAT_EXCEPTION_STRINGS
|
||||||
from lib.core.settings import HEURISTIC_CHECK_ALPHABET
|
from lib.core.settings import HEURISTIC_CHECK_ALPHABET
|
||||||
from lib.core.settings import SUHOSIN_MAX_VALUE_LENGTH
|
from lib.core.settings import SUHOSIN_MAX_VALUE_LENGTH
|
||||||
|
from lib.core.settings import SUPPORTED_DBMS
|
||||||
from lib.core.settings import UNKNOWN_DBMS
|
from lib.core.settings import UNKNOWN_DBMS
|
||||||
from lib.core.settings import URI_HTTP_HEADER
|
from lib.core.settings import URI_HTTP_HEADER
|
||||||
from lib.core.settings import LOWER_RATIO_BOUND
|
from lib.core.settings import LOWER_RATIO_BOUND
|
||||||
|
@ -89,7 +90,6 @@ def checkSqlInjection(place, parameter, value):
|
||||||
kb.testMode = True
|
kb.testMode = True
|
||||||
|
|
||||||
paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place
|
paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place
|
||||||
|
|
||||||
tests = getSortedInjectionTests()
|
tests = getSortedInjectionTests()
|
||||||
|
|
||||||
while tests:
|
while tests:
|
||||||
|
@ -100,26 +100,38 @@ def checkSqlInjection(place, parameter, value):
|
||||||
break
|
break
|
||||||
|
|
||||||
if conf.dbms is None:
|
if conf.dbms is None:
|
||||||
|
# If the DBMS has not yet been fingerprinted (via simple heuristic check
|
||||||
|
# or via DBMS-specific payload) and boolean-based blind has been identified
|
||||||
|
# then attempt to identify with a simple DBMS specific boolean-based
|
||||||
|
# test what the DBMS may be
|
||||||
if not injection.dbms and PAYLOAD.TECHNIQUE.BOOLEAN in injection.data:
|
if not injection.dbms and PAYLOAD.TECHNIQUE.BOOLEAN in injection.data:
|
||||||
if not Backend.getIdentifiedDbms() and not kb.heuristicDbms:
|
if not Backend.getIdentifiedDbms() and kb.heuristicDbms is False:
|
||||||
kb.heuristicDbms = heuristicCheckDbms(injection) or UNKNOWN_DBMS
|
kb.heuristicDbms = heuristicCheckDbms(injection)
|
||||||
|
|
||||||
if not conf.testFilter and (Backend.getErrorParsedDBMSes() or kb.heuristicDbms) not in ([], None, UNKNOWN_DBMS):
|
# If the DBMS has already been fingerprinted (via DBMS-specific
|
||||||
if kb.reduceTests is None and Backend.getErrorParsedDBMSes():
|
# error message, simple heuristic check or via DBMS-specific
|
||||||
msg = "heuristic (parsing) test showed that the "
|
# payload), ask the user to limit the tests to the fingerprinted
|
||||||
msg += "back-end DBMS could be '%s'. " % (Format.getErrorParsedDBMSes() if Backend.getErrorParsedDBMSes() else kb.heuristicDbms)
|
# DBMS
|
||||||
|
if kb.reduceTests is None and not conf.testFilter and (intersect(Backend.getErrorParsedDBMSes(), \
|
||||||
|
SUPPORTED_DBMS, True) or kb.heuristicDbms or injection.dbms):
|
||||||
|
msg = "it looks like the back-end DBMS is '%s'. " % (Format.getErrorParsedDBMSes() or kb.heuristicDbms or injection.dbms)
|
||||||
msg += "Do you want to skip test payloads specific for other DBMSes? [Y/n]"
|
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])
|
kb.reduceTests = (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms]) if readInput(msg, default='Y').upper() == 'Y' else []
|
||||||
|
|
||||||
if kb.extendTests is None and (conf.level < 5 or conf.risk < 3):
|
# If the DBMS has already been fingerprinted (via DBMS-specific
|
||||||
_ = (Format.getErrorParsedDBMSes() if Backend.getErrorParsedDBMSes() else kb.heuristicDbms)
|
# error message, via simple heuristic check or via DBMS-specific
|
||||||
msg = "do you want to include all tests for '%s' " % _
|
# payload), ask the user to extend the tests to all DBMS-specific,
|
||||||
msg += "extending provided level (%d) and risk (%s) values? [Y/n]" % (conf.level, conf.risk)
|
# regardless of --level and --risk values provided
|
||||||
kb.extendTests = [] if readInput(msg, default='Y').upper() != 'Y' else (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms])
|
if kb.extendTests is None and not conf.testFilter and (conf.level < 5 or conf.risk < 3) \
|
||||||
elif kb.extendTests is None and (conf.level < 5 or conf.risk < 3):
|
and (intersect(Backend.getErrorParsedDBMSes(), SUPPORTED_DBMS, True) or \
|
||||||
msg = "do you want to include all tests for '%s' " % conf.dbms
|
kb.heuristicDbms or injection.dbms):
|
||||||
msg += "extending provided level (%d) and risk (%s)? [Y/n]" % (conf.level, conf.risk)
|
msg = "do you want to include all tests for '%s' " % (Format.getErrorParsedDBMSes() or kb.heuristicDbms or injection.dbms)
|
||||||
kb.extendTests = [] if readInput(msg, default='Y').upper() != 'Y' else ([conf.dbms])
|
msg += "extending provided "
|
||||||
|
msg += "level (%d)" % conf.level if conf.level < 5 else ""
|
||||||
|
msg += " and " if conf.level < 5 and conf.risk < 3 else ""
|
||||||
|
msg += "risk (%d)" % conf.risk if conf.risk < 3 else ""
|
||||||
|
msg += " values? [Y/n]" if conf.level < 5 and conf.risk < 3 else " value? [Y/n]"
|
||||||
|
kb.extendTests = (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms]) if readInput(msg, default='Y').upper() == 'Y' else []
|
||||||
|
|
||||||
title = test.title
|
title = test.title
|
||||||
kb.testType = stype = test.stype
|
kb.testType = stype = test.stype
|
||||||
|
@ -179,9 +191,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:
|
if "details" in test and "dbms" in test.details:
|
||||||
dbms = test.details.dbms
|
dbms = test.details.dbms
|
||||||
else:
|
else:
|
||||||
|
@ -198,20 +207,26 @@ def checkSqlInjection(place, parameter, value):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if dbms is not None:
|
if dbms is not None:
|
||||||
if injection.dbms is not None and not intersect(injection.dbms, dbms):
|
# Skip DBMS-specific test if it does not match the
|
||||||
|
# previously identified DBMS (via DBMS-specific payload)
|
||||||
|
if injection.dbms is not None and not intersect(dbms, injection.dbms, True):
|
||||||
debugMsg = "skipping test '%s' because " % title
|
debugMsg = "skipping test '%s' because " % title
|
||||||
debugMsg += "the back-end DBMS identified is "
|
debugMsg += "the back-end DBMS identified is "
|
||||||
debugMsg += "%s" % injection.dbms
|
debugMsg += "%s" % injection.dbms
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if conf.dbms is not None and not intersect(conf.dbms.lower(), [_.lower() for _ in arrayizeValue(dbms)]):
|
# Skip DBMS-specific test if it does not match the user's
|
||||||
|
# provided DBMS
|
||||||
|
if conf.dbms is not None and not intersect(dbms, conf.dbms, True):
|
||||||
debugMsg = "skipping test '%s' because " % title
|
debugMsg = "skipping test '%s' because " % title
|
||||||
debugMsg += "the provided DBMS is %s" % conf.dbms
|
debugMsg += "the provided DBMS is %s" % conf.dbms
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if kb.reduceTests and not intersect(dbms, kb.reduceTests):
|
# Skip DBMS-specific test if it does not match the
|
||||||
|
# previously identified DBMS (via DBMS-specific error message)
|
||||||
|
if kb.reduceTests and not intersect(dbms, kb.reduceTests, True):
|
||||||
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 "
|
||||||
|
@ -484,7 +499,7 @@ def checkSqlInjection(place, parameter, value):
|
||||||
configUnion(test.request.char, test.request.columns)
|
configUnion(test.request.char, test.request.columns)
|
||||||
|
|
||||||
if not Backend.getIdentifiedDbms():
|
if not Backend.getIdentifiedDbms():
|
||||||
if kb.heuristicDbms in (None, UNKNOWN_DBMS):
|
if kb.heuristicDbms is None:
|
||||||
warnMsg = "using unescaped version of the test "
|
warnMsg = "using unescaped version of the test "
|
||||||
warnMsg += "because of zero knowledge of the "
|
warnMsg += "because of zero knowledge of the "
|
||||||
warnMsg += "back-end DBMS. You can try to "
|
warnMsg += "back-end DBMS. You can try to "
|
||||||
|
@ -646,7 +661,13 @@ def checkSqlInjection(place, parameter, value):
|
||||||
return injection
|
return injection
|
||||||
|
|
||||||
def heuristicCheckDbms(injection):
|
def heuristicCheckDbms(injection):
|
||||||
retVal = None
|
"""
|
||||||
|
This functions is called when boolean-based blind is identified with a
|
||||||
|
generic payload and the DBMS has not yet been fingerprinted to attempt
|
||||||
|
to identify with a simple DBMS specific boolean-based test what the DBMS
|
||||||
|
may be
|
||||||
|
"""
|
||||||
|
retVal = False
|
||||||
|
|
||||||
pushValue(kb.injection)
|
pushValue(kb.injection)
|
||||||
kb.injection = injection
|
kb.injection = injection
|
||||||
|
@ -667,7 +688,7 @@ def heuristicCheckDbms(injection):
|
||||||
kb.injection = popValue()
|
kb.injection = popValue()
|
||||||
|
|
||||||
if retVal:
|
if retVal:
|
||||||
infoMsg = "heuristic (extended) test shows that the back-end DBMS " # not as important as "parsing" counter-part (because of false-positives)
|
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)
|
||||||
|
|
||||||
|
@ -798,9 +819,7 @@ def heuristicCheckSqlInjection(place, parameter):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
origValue = conf.paramDict[place][parameter]
|
origValue = conf.paramDict[place][parameter]
|
||||||
|
|
||||||
paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place
|
paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place
|
||||||
|
|
||||||
prefix = ""
|
prefix = ""
|
||||||
suffix = ""
|
suffix = ""
|
||||||
|
|
||||||
|
@ -812,6 +831,7 @@ def heuristicCheckSqlInjection(place, parameter):
|
||||||
suffix = conf.suffix
|
suffix = conf.suffix
|
||||||
|
|
||||||
randStr = ""
|
randStr = ""
|
||||||
|
|
||||||
while '\'' not in randStr:
|
while '\'' not in randStr:
|
||||||
randStr = randomStr(length=10, alphabet=HEURISTIC_CHECK_ALPHABET)
|
randStr = randomStr(length=10, alphabet=HEURISTIC_CHECK_ALPHABET)
|
||||||
|
|
||||||
|
@ -879,8 +899,7 @@ def heuristicCheckSqlInjection(place, parameter):
|
||||||
|
|
||||||
if value in (page or ""):
|
if value in (page or ""):
|
||||||
infoMsg = "heuristic (XSS) test shows that %s parameter " % paramType
|
infoMsg = "heuristic (XSS) test shows that %s parameter " % paramType
|
||||||
infoMsg += "'%s' might " % parameter
|
infoMsg += "'%s' might be vulnerable to XSS attacks" % parameter
|
||||||
infoMsg += "be vulnerable to XSS attacks"
|
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
kb.heuristicMode = False
|
kb.heuristicMode = False
|
||||||
|
|
Loading…
Reference in New Issue
Block a user