6464from lib .core .settings import FORMAT_EXCEPTION_STRINGS
6565from lib .core .settings import HEURISTIC_CHECK_ALPHABET
6666from lib .core .settings import SUHOSIN_MAX_VALUE_LENGTH
67+ from lib .core .settings import SUPPORTED_DBMS
6768from lib .core .settings import UNKNOWN_DBMS
6869from lib .core .settings import URI_HTTP_HEADER
6970from 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
648663def 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