Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 52dd927

Browse files
committed
rework some of the logic of the detection phase based on identified DBMS along the way
1 parent 4f939b5 commit 52dd927

1 file changed

Lines changed: 52 additions & 33 deletions

File tree

lib/controller/checks.py

Lines changed: 52 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
from lib.core.settings import FORMAT_EXCEPTION_STRINGS
6565
from lib.core.settings import HEURISTIC_CHECK_ALPHABET
6666
from lib.core.settings import SUHOSIN_MAX_VALUE_LENGTH
67+
from lib.core.settings import SUPPORTED_DBMS
6768
from lib.core.settings import UNKNOWN_DBMS
6869
from lib.core.settings import URI_HTTP_HEADER
6970
from lib.core.settings import LOWER_RATIO_BOUND
@@ -89,7 +90,6 @@ def checkSqlInjection(place, parameter, value):
8990
kb.testMode = True
9091

9192
paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place
92-
9393
tests = getSortedInjectionTests()
9494

9595
while tests:
@@ -100,26 +100,38 @@ def checkSqlInjection(place, parameter, value):
100100
break
101101

102102
if conf.dbms is None:
103+
# If the DBMS has not yet been fingerprinted (via simple heuristic check
104+
# or via DBMS-specific payload) and boolean-based blind has been identified
105+
# then attempt to identify with a simple DBMS specific boolean-based
106+
# test what the DBMS may be
103107
if not injection.dbms and PAYLOAD.TECHNIQUE.BOOLEAN in injection.data:
104-
if not Backend.getIdentifiedDbms() and not kb.heuristicDbms:
105-
kb.heuristicDbms = heuristicCheckDbms(injection) or UNKNOWN_DBMS
106-
107-
if not conf.testFilter and (Backend.getErrorParsedDBMSes() or kb.heuristicDbms) not in ([], None, UNKNOWN_DBMS):
108-
if kb.reduceTests is None and Backend.getErrorParsedDBMSes():
109-
msg = "heuristic (parsing) test showed that the "
110-
msg += "back-end DBMS could be '%s'. " % (Format.getErrorParsedDBMSes() if Backend.getErrorParsedDBMSes() else kb.heuristicDbms)
111-
msg += "Do you want to skip test payloads specific for other DBMSes? [Y/n]"
112-
kb.reduceTests = [] if readInput(msg, default='Y').upper() != 'Y' else (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms])
113-
114-
if kb.extendTests is None and (conf.level < 5 or conf.risk < 3):
115-
_ = (Format.getErrorParsedDBMSes() if Backend.getErrorParsedDBMSes() else kb.heuristicDbms)
116-
msg = "do you want to include all tests for '%s' " % _
117-
msg += "extending provided level (%d) and risk (%s) values? [Y/n]" % (conf.level, conf.risk)
118-
kb.extendTests = [] if readInput(msg, default='Y').upper() != 'Y' else (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms])
119-
elif kb.extendTests is None and (conf.level < 5 or conf.risk < 3):
120-
msg = "do you want to include all tests for '%s' " % conf.dbms
121-
msg += "extending provided level (%d) and risk (%s)? [Y/n]" % (conf.level, conf.risk)
122-
kb.extendTests = [] if readInput(msg, default='Y').upper() != 'Y' else ([conf.dbms])
108+
if not Backend.getIdentifiedDbms() and kb.heuristicDbms is False:
109+
kb.heuristicDbms = heuristicCheckDbms(injection)
110+
111+
# If the DBMS has already been fingerprinted (via DBMS-specific
112+
# error message, simple heuristic check or via DBMS-specific
113+
# payload), ask the user to limit the tests to the fingerprinted
114+
# DBMS
115+
if kb.reduceTests is None and not conf.testFilter and (intersect(Backend.getErrorParsedDBMSes(), \
116+
SUPPORTED_DBMS, True) or kb.heuristicDbms or injection.dbms):
117+
msg = "it looks like the back-end DBMS is '%s'. " % (Format.getErrorParsedDBMSes() or kb.heuristicDbms or injection.dbms)
118+
msg += "Do you want to skip test payloads specific for other DBMSes? [Y/n]"
119+
kb.reduceTests = (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms]) if readInput(msg, default='Y').upper() == 'Y' else []
120+
121+
# If the DBMS has already been fingerprinted (via DBMS-specific
122+
# error message, via simple heuristic check or via DBMS-specific
123+
# payload), ask the user to extend the tests to all DBMS-specific,
124+
# regardless of --level and --risk values provided
125+
if kb.extendTests is None and not conf.testFilter and (conf.level < 5 or conf.risk < 3) \
126+
and (intersect(Backend.getErrorParsedDBMSes(), SUPPORTED_DBMS, True) or \
127+
kb.heuristicDbms or injection.dbms):
128+
msg = "do you want to include all tests for '%s' " % (Format.getErrorParsedDBMSes() or kb.heuristicDbms or injection.dbms)
129+
msg += "extending provided "
130+
msg += "level (%d)" % conf.level if conf.level < 5 else ""
131+
msg += " and " if conf.level < 5 and conf.risk < 3 else ""
132+
msg += "risk (%d)" % conf.risk if conf.risk < 3 else ""
133+
msg += " values? [Y/n]" if conf.level < 5 and conf.risk < 3 else " value? [Y/n]"
134+
kb.extendTests = (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms]) if readInput(msg, default='Y').upper() == 'Y' else []
123135

124136
title = test.title
125137
kb.testType = stype = test.stype
@@ -179,9 +191,6 @@ def checkSqlInjection(place, parameter, value):
179191
logger.debug(debugMsg)
180192
continue
181193

182-
# Skip DBMS-specific test if it does not match either the
183-
# previously identified or the user's provided DBMS (either
184-
# from program switch or from parsed error message(s))
185194
if "details" in test and "dbms" in test.details:
186195
dbms = test.details.dbms
187196
else:
@@ -198,20 +207,26 @@ def checkSqlInjection(place, parameter, value):
198207
continue
199208

200209
if dbms is not None:
201-
if injection.dbms is not None and not intersect(injection.dbms, dbms):
210+
# Skip DBMS-specific test if it does not match the
211+
# previously identified DBMS (via DBMS-specific payload)
212+
if injection.dbms is not None and not intersect(dbms, injection.dbms, True):
202213
debugMsg = "skipping test '%s' because " % title
203214
debugMsg += "the back-end DBMS identified is "
204215
debugMsg += "%s" % injection.dbms
205216
logger.debug(debugMsg)
206217
continue
207218

208-
if conf.dbms is not None and not intersect(conf.dbms.lower(), [_.lower() for _ in arrayizeValue(dbms)]):
219+
# Skip DBMS-specific test if it does not match the user's
220+
# provided DBMS
221+
if conf.dbms is not None and not intersect(dbms, conf.dbms, True):
209222
debugMsg = "skipping test '%s' because " % title
210223
debugMsg += "the provided DBMS is %s" % conf.dbms
211224
logger.debug(debugMsg)
212225
continue
213226

214-
if kb.reduceTests and not intersect(dbms, kb.reduceTests):
227+
# Skip DBMS-specific test if it does not match the
228+
# previously identified DBMS (via DBMS-specific error message)
229+
if kb.reduceTests and not intersect(dbms, kb.reduceTests, True):
215230
debugMsg = "skipping test '%s' because " % title
216231
debugMsg += "the parsed error message(s) showed "
217232
debugMsg += "that the back-end DBMS could be "
@@ -484,7 +499,7 @@ def genCmpPayload():
484499
configUnion(test.request.char, test.request.columns)
485500

486501
if not Backend.getIdentifiedDbms():
487-
if kb.heuristicDbms in (None, UNKNOWN_DBMS):
502+
if kb.heuristicDbms is None:
488503
warnMsg = "using unescaped version of the test "
489504
warnMsg += "because of zero knowledge of the "
490505
warnMsg += "back-end DBMS. You can try to "
@@ -646,7 +661,13 @@ def genCmpPayload():
646661
return injection
647662

648663
def heuristicCheckDbms(injection):
649-
retVal = None
664+
"""
665+
This functions is called when boolean-based blind is identified with a
666+
generic payload and the DBMS has not yet been fingerprinted to attempt
667+
to identify with a simple DBMS specific boolean-based test what the DBMS
668+
may be
669+
"""
670+
retVal = False
650671

651672
pushValue(kb.injection)
652673
kb.injection = injection
@@ -667,7 +688,7 @@ def heuristicCheckDbms(injection):
667688
kb.injection = popValue()
668689

669690
if retVal:
670-
infoMsg = "heuristic (extended) test shows that the back-end DBMS " # not as important as "parsing" counter-part (because of false-positives)
691+
infoMsg = "heuristic (extended) test shows that the back-end DBMS " # Not as important as "parsing" counter-part (because of false-positives)
671692
infoMsg += "could be '%s' " % retVal
672693
logger.info(infoMsg)
673694

@@ -798,9 +819,7 @@ def heuristicCheckSqlInjection(place, parameter):
798819
return None
799820

800821
origValue = conf.paramDict[place][parameter]
801-
802822
paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place
803-
804823
prefix = ""
805824
suffix = ""
806825

@@ -812,6 +831,7 @@ def heuristicCheckSqlInjection(place, parameter):
812831
suffix = conf.suffix
813832

814833
randStr = ""
834+
815835
while '\'' not in randStr:
816836
randStr = randomStr(length=10, alphabet=HEURISTIC_CHECK_ALPHABET)
817837

@@ -879,8 +899,7 @@ def _(page):
879899

880900
if value in (page or ""):
881901
infoMsg = "heuristic (XSS) test shows that %s parameter " % paramType
882-
infoMsg += "'%s' might " % parameter
883-
infoMsg += "be vulnerable to XSS attacks"
902+
infoMsg += "'%s' might be vulnerable to XSS attacks" % parameter
884903
logger.info(infoMsg)
885904

886905
kb.heuristicMode = False

0 commit comments

Comments
 (0)