2019-05-08 13:47:52 +03:00
#!/usr/bin/env python
2008-10-15 19:38:22 +04:00
"""
2020-12-31 13:46:27 +03:00
Copyright ( c ) 2006 - 2021 sqlmap developers ( http : / / sqlmap . org / )
2017-10-11 15:50:46 +03:00
See the file ' LICENSE ' for copying permission
2008-10-15 19:38:22 +04:00
"""
2012-08-22 15:58:52 +04:00
import copy
2017-11-24 14:20:57 +03:00
import logging
2016-04-15 14:47:19 +03:00
import random
2008-12-12 22:06:31 +03:00
import re
2010-05-21 17:36:49 +04:00
import socket
2016-12-20 01:47:39 +03:00
import subprocess
2018-08-10 15:01:55 +03:00
import sys
2008-10-15 19:38:22 +04:00
import time
2012-12-11 15:02:06 +04:00
from extra . beep . beep import beep
2008-10-15 19:38:22 +04:00
from lib . core . agent import agent
2011-01-28 19:36:09 +03:00
from lib . core . common import Backend
2010-12-06 18:50:19 +03:00
from lib . core . common import extractRegexResult
2012-04-11 01:48:34 +04:00
from lib . core . common import extractTextTagContent
2019-03-29 04:28:16 +03:00
from lib . core . common import filterNone
2010-12-29 22:39:32 +03:00
from lib . core . common import findDynamicContent
2011-01-28 19:36:09 +03:00
from lib . core . common import Format
2017-02-06 15:28:33 +03:00
from lib . core . common import getFilteredPageContent
2012-01-14 00:56:06 +04:00
from lib . core . common import getLastRequestHTTPError
2013-01-25 15:34:57 +04:00
from lib . core . common import getPublicTypeMembers
2015-09-10 16:51:33 +03:00
from lib . core . common import getSafeExString
2011-01-20 02:06:15 +03:00
from lib . core . common import getSortedInjectionTests
2016-01-09 01:23:41 +03:00
from lib . core . common import hashDBRetrieve
from lib . core . common import hashDBWrite
2011-02-14 00:20:21 +03:00
from lib . core . common import intersect
2020-11-27 01:41:35 +03:00
from lib . core . common import isDigit
2019-11-13 01:32:09 +03:00
from lib . core . common import joinValue
2011-01-31 15:21:17 +03:00
from lib . core . common import listToStrValue
2011-11-22 12:39:13 +04:00
from lib . core . common import parseFilePaths
2010-12-04 18:47:02 +03:00
from lib . core . common import popValue
from lib . core . common import pushValue
2008-10-15 19:38:22 +04:00
from lib . core . common import randomInt
from lib . core . common import randomStr
2010-10-11 15:47:07 +04:00
from lib . core . common import readInput
2010-10-12 19:49:04 +04:00
from lib . core . common import showStaticWords
2012-04-23 17:41:36 +04:00
from lib . core . common import singleTimeLogMessage
2011-06-08 18:35:23 +04:00
from lib . core . common import singleTimeWarnMessage
2017-11-29 17:59:00 +03:00
from lib . core . common import unArrayizeValue
2013-01-29 23:53:11 +04:00
from lib . core . common import wasLastResponseDBMSError
from lib . core . common import wasLastResponseHTTPError
2019-03-28 18:04:38 +03:00
from lib . core . compat import xrange
2019-12-01 01:10:20 +03:00
from lib . core . convert import getBytes
2019-05-06 01:54:21 +03:00
from lib . core . convert import getUnicode
2008-10-15 19:38:22 +04:00
from lib . core . data import conf
from lib . core . data import kb
from lib . core . data import logger
2011-07-08 10:02:31 +04:00
from lib . core . datatype import AttribDict
from lib . core . datatype import InjectionDict
2018-04-01 13:45:47 +03:00
from lib . core . decorators import stackedmethod
2013-01-25 15:34:57 +04:00
from lib . core . dicts import FROM_DUMMY_TABLE
2020-01-27 19:32:31 +03:00
from lib . core . dicts import HEURISTIC_NULL_EVAL
2013-01-25 15:34:57 +04:00
from lib . core . enums import DBMS
2016-01-09 01:23:41 +03:00
from lib . core . enums import HASHDB_KEYS
2012-08-22 13:56:30 +04:00
from lib . core . enums import HEURISTIC_TEST
2013-03-20 14:10:24 +04:00
from lib . core . enums import HTTP_HEADER
2010-11-08 12:49:57 +03:00
from lib . core . enums import HTTPMETHOD
2016-05-06 14:06:59 +03:00
from lib . core . enums import NOTE
2010-11-08 12:49:57 +03:00
from lib . core . enums import NULLCONNECTION
2010-11-28 21:10:54 +03:00
from lib . core . enums import PAYLOAD
2010-12-01 20:09:52 +03:00
from lib . core . enums import PLACE
2014-12-04 12:06:15 +03:00
from lib . core . enums import REDIRECTION
2018-12-21 13:29:57 +03:00
from lib . core . enums import WEB_PLATFORM
2012-12-06 17:14:19 +04:00
from lib . core . exception import SqlmapConnectionException
2018-12-04 01:18:52 +03:00
from lib . core . exception import SqlmapDataException
2012-12-06 17:14:19 +04:00
from lib . core . exception import SqlmapNoneDataException
from lib . core . exception import SqlmapSilentQuitException
2017-07-26 00:32:30 +03:00
from lib . core . exception import SqlmapSkipTargetException
2012-12-06 17:14:19 +04:00
from lib . core . exception import SqlmapUserQuitException
2018-11-02 00:24:36 +03:00
from lib . core . settings import BOUNDED_INJECTION_MARKER
2017-02-06 15:28:33 +03:00
from lib . core . settings import CANDIDATE_SENTENCE_MIN_LENGTH
2017-05-08 00:12:42 +03:00
from lib . core . settings import CHECK_INTERNET_ADDRESS
from lib . core . settings import CHECK_INTERNET_VALUE
2019-10-14 11:42:10 +03:00
from lib . core . settings import DEFAULT_COOKIE_DELIMITER
2015-01-06 16:01:47 +03:00
from lib . core . settings import DEFAULT_GET_POST_DELIMITER
2016-01-14 11:59:13 +03:00
from lib . core . settings import DUMMY_NON_SQLI_CHECK_APPENDIX
2016-05-30 17:06:39 +03:00
from lib . core . settings import FI_ERROR_REGEX
2012-08-22 17:51:47 +04:00
from lib . core . settings import FORMAT_EXCEPTION_STRINGS
2012-10-28 03:42:08 +04:00
from lib . core . settings import HEURISTIC_CHECK_ALPHABET
2019-06-04 15:44:06 +03:00
from lib . core . settings import INFERENCE_EQUALS_CHAR
2019-01-26 14:36:03 +03:00
from lib . core . settings import IPS_WAF_CHECK_PAYLOAD
2019-06-04 15:44:06 +03:00
from lib . core . settings import IPS_WAF_CHECK_RATIO
from lib . core . settings import IPS_WAF_CHECK_TIMEOUT
2016-06-30 15:57:56 +03:00
from lib . core . settings import MAX_DIFFLIB_SEQUENCE_LENGTH
2019-06-04 16:46:56 +03:00
from lib . core . settings import MAX_STABILITY_DELAY
2016-01-15 00:21:47 +03:00
from lib . core . settings import NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH
2018-09-05 00:01:17 +03:00
from lib . core . settings import PRECONNECT_INCOMPATIBLE_SERVERS
2018-10-16 13:23:07 +03:00
from lib . core . settings import SINGLE_QUOTE_MARKER
2016-09-27 11:32:22 +03:00
from lib . core . settings import SLEEP_TIME_MARKER
2013-01-16 05:31:03 +04:00
from lib . core . settings import SUHOSIN_MAX_VALUE_LENGTH
2015-02-21 05:23:42 +03:00
from lib . core . settings import SUPPORTED_DBMS
2018-08-10 15:01:55 +03:00
from lib . core . settings import UNICODE_ENCODING
2010-12-29 22:01:29 +03:00
from lib . core . settings import UPPER_RATIO_BOUND
2019-06-04 15:44:06 +03:00
from lib . core . settings import URI_HTTP_HEADER
2011-01-16 13:52:42 +03:00
from lib . core . threads import getCurrentThreadData
2020-01-23 12:53:06 +03:00
from lib . core . unescaper import unescaper
2008-10-15 19:38:22 +04:00
from lib . request . connect import Connect as Request
2016-05-30 17:46:23 +03:00
from lib . request . comparison import comparison
2011-04-22 16:24:16 +04:00
from lib . request . inject import checkBooleanExpression
2010-12-07 17:35:31 +03:00
from lib . request . templates import getPageTemplate
2011-06-18 16:34:41 +04:00
from lib . techniques . union . test import unionTest
from lib . techniques . union . use import configUnion
2019-03-28 15:53:54 +03:00
from thirdparty import six
2019-03-27 15:33:46 +03:00
from thirdparty . six . moves import http_client as _http_client
2010-11-28 21:10:54 +03:00
def checkSqlInjection ( place , parameter , value ) :
# Store here the details about boundaries and payload used to
# successfully inject
2011-07-08 10:02:31 +04:00
injection = InjectionDict ( )
2010-11-28 21:10:54 +03:00
2011-03-17 12:23:46 +03:00
# Localized thread data needed for some methods
threadData = getCurrentThreadData ( )
2016-09-20 10:56:08 +03:00
# Favoring non-string specific boundaries in case of digit-like parameter values
2020-11-27 01:41:35 +03:00
if isDigit ( value ) :
2016-09-20 11:03:00 +03:00
kb . cache . intBoundaries = kb . cache . intBoundaries or sorted ( copy . deepcopy ( conf . boundaries ) , key = lambda boundary : any ( _ in ( boundary . prefix or " " ) or _ in ( boundary . suffix or " " ) for _ in ( ' " ' , ' \' ' ) ) )
boundaries = kb . cache . intBoundaries
2017-12-29 15:04:52 +03:00
elif value . isalpha ( ) :
kb . cache . alphaBoundaries = kb . cache . alphaBoundaries or sorted ( copy . deepcopy ( conf . boundaries ) , key = lambda boundary : not any ( _ in ( boundary . prefix or " " ) or _ in ( boundary . suffix or " " ) for _ in ( ' " ' , ' \' ' ) ) )
boundaries = kb . cache . alphaBoundaries
2016-09-20 10:56:08 +03:00
else :
boundaries = conf . boundaries
2012-06-19 12:33:51 +04:00
# Set the flag for SQL injection test mode
2010-12-07 16:34:06 +03:00
kb . testMode = True
2010-12-04 18:47:02 +03:00
2014-11-21 13:20:54 +03:00
paramType = conf . method if conf . method not in ( None , HTTPMETHOD . GET , HTTPMETHOD . POST ) else place
2014-10-07 14:00:11 +04:00
tests = getSortedInjectionTests ( )
2015-07-10 01:54:02 +03:00
seenPayload = set ( )
2014-10-07 14:00:11 +04:00
2016-05-19 20:46:12 +03:00
kb . data . setdefault ( " randomInt " , str ( randomInt ( 10 ) ) )
kb . data . setdefault ( " randomStr " , str ( randomStr ( 10 ) ) )
2014-10-07 14:00:11 +04:00
while tests :
test = tests . pop ( 0 )
2011-01-12 01:18:47 +03:00
try :
2011-01-01 22:22:44 +03:00
if kb . endDetection :
break
2013-02-01 20:24:04 +04:00
if conf . dbms is None :
2015-02-21 05:23:42 +03:00
# 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
2013-02-01 20:24:04 +04:00
if not injection . dbms and PAYLOAD . TECHNIQUE . BOOLEAN in injection . data :
2017-05-26 15:14:35 +03:00
if not Backend . getIdentifiedDbms ( ) and kb . heuristicDbms is None and not kb . droppingRequests :
2015-02-21 05:23:42 +03:00
kb . heuristicDbms = heuristicCheckDbms ( injection )
# If the DBMS has already been fingerprinted (via DBMS-specific
# error message, simple heuristic check or via DBMS-specific
# payload), ask the user to limit the tests to the fingerprinted
# DBMS
2021-01-15 00:48:57 +03:00
2018-03-13 15:45:42 +03:00
if kb . reduceTests is None and not conf . testFilter and ( intersect ( Backend . getErrorParsedDBMSes ( ) , SUPPORTED_DBMS , True ) or kb . heuristicDbms or injection . dbms ) :
2019-11-13 01:32:09 +03:00
msg = " it looks like the back-end DBMS is ' %s ' . " % ( Format . getErrorParsedDBMSes ( ) or kb . heuristicDbms or joinValue ( injection . dbms , ' / ' ) )
2015-02-21 05:23:42 +03:00
msg + = " Do you want to skip test payloads specific for other DBMSes? [Y/n] "
2017-04-18 16:48:05 +03:00
kb . reduceTests = ( Backend . getErrorParsedDBMSes ( ) or [ kb . heuristicDbms ] ) if readInput ( msg , default = ' Y ' , boolean = True ) else [ ]
2015-02-21 05:23:42 +03:00
2015-02-27 16:57:28 +03:00
# If the DBMS has been fingerprinted (via DBMS-specific error
# message, via simple heuristic check or via DBMS-specific
2015-02-21 05:23:42 +03:00
# payload), ask the user to extend the tests to all DBMS-specific,
# regardless of --level and --risk values provided
2018-03-13 15:45:42 +03:00
if kb . extendTests is None and not conf . testFilter and ( conf . level < 5 or conf . risk < 3 ) and ( intersect ( Backend . getErrorParsedDBMSes ( ) , SUPPORTED_DBMS , True ) or kb . heuristicDbms or injection . dbms ) :
2015-02-21 15:59:44 +03:00
msg = " for the remaining tests, do you want to include all tests "
2019-11-13 01:32:09 +03:00
msg + = " for ' %s ' extending provided " % ( Format . getErrorParsedDBMSes ( ) or kb . heuristicDbms or joinValue ( injection . dbms , ' / ' ) )
2015-02-21 05:23:42 +03:00
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] "
2017-04-18 16:48:05 +03:00
kb . extendTests = ( Backend . getErrorParsedDBMSes ( ) or [ kb . heuristicDbms ] ) if readInput ( msg , default = ' Y ' , boolean = True ) else [ ]
2013-02-01 20:24:04 +04:00
2010-12-18 13:42:09 +03:00
title = test . title
2014-09-08 16:33:13 +04:00
kb . testType = stype = test . stype
2010-12-18 13:42:09 +03:00
clause = test . clause
2012-05-07 17:51:31 +04:00
unionExtended = False
2016-09-27 12:21:12 +03:00
trueCode , falseCode = None , None
2010-12-18 13:42:09 +03:00
2017-07-18 22:46:52 +03:00
if conf . httpCollector is not None :
conf . httpCollector . setExtendedArguments ( {
" _title " : title ,
" _place " : place ,
" _parameter " : parameter ,
} )
2011-05-10 19:34:54 +04:00
if stype == PAYLOAD . TECHNIQUE . UNION :
2011-01-19 02:03:50 +03:00
configUnion ( test . request . char )
2011-05-10 19:34:54 +04:00
if " [CHAR] " in title :
if conf . uChar is None :
continue
else :
title = title . replace ( " [CHAR] " , conf . uChar )
elif " [RANDNUM] " in title or " (NULL) " in title :
title = title . replace ( " [RANDNUM] " , " random number " )
2011-01-19 02:03:50 +03:00
if test . request . columns == " [COLSTART]-[COLSTOP] " :
if conf . uCols is None :
continue
else :
title = title . replace ( " [COLSTART] " , str ( conf . uColsStart ) )
title = title . replace ( " [COLSTOP] " , str ( conf . uColsStop ) )
2011-05-11 01:33:06 +04:00
2011-05-10 19:34:54 +04:00
elif conf . uCols is not None :
debugMsg = " skipping test ' %s ' because the user " % title
debugMsg + = " provided custom column range %s " % conf . uCols
logger . debug ( debugMsg )
continue
2011-04-07 15:10:35 +04:00
2012-04-23 17:41:36 +04:00
match = re . search ( r " ( \ d+)-( \ d+) " , test . request . columns )
2018-03-16 17:11:04 +03:00
if match and injection . data :
2012-04-23 17:41:36 +04:00
lower , upper = int ( match . group ( 1 ) ) , int ( match . group ( 2 ) )
for _ in ( lower , upper ) :
if _ > 1 :
2016-05-22 15:22:31 +03:00
__ = 2 * ( _ - 1 ) + 1 if _ == lower else 2 * _
2012-05-07 17:51:31 +04:00
unionExtended = True
2016-05-22 15:22:31 +03:00
test . request . columns = re . sub ( r " \ b %d \ b " % _ , str ( __ ) , test . request . columns )
title = re . sub ( r " \ b %d \ b " % _ , str ( __ ) , title )
test . title = re . sub ( r " \ b %d \ b " % _ , str ( __ ) , test . title )
2012-04-23 17:41:36 +04:00
2010-12-18 13:42:09 +03:00
# Skip test if the user's wants to test only for a specific
# technique
2019-06-07 01:21:43 +03:00
if conf . technique and isinstance ( conf . technique , list ) and stype not in conf . technique :
2020-11-27 01:41:35 +03:00
debugMsg = " skipping test ' %s ' because user " % title
debugMsg + = " specified testing of only "
2019-06-07 01:21:43 +03:00
debugMsg + = " %s techniques " % " & " . join ( PAYLOAD . SQLINJECTION [ _ ] for _ in conf . technique )
2010-11-29 17:48:07 +03:00
logger . debug ( debugMsg )
continue
2011-02-02 01:04:48 +03:00
# Skip test if it is the same SQL injection type already
# identified by another test
if injection . data and stype in injection . data :
debugMsg = " skipping test ' %s ' because " % title
debugMsg + = " the payload for %s has " % PAYLOAD . SQLINJECTION [ stype ]
debugMsg + = " already been identified "
logger . debug ( debugMsg )
continue
2015-02-27 16:57:28 +03:00
# Parse DBMS-specific payloads' details
2013-02-01 20:24:04 +04:00
if " details " in test and " dbms " in test . details :
2015-02-27 16:57:28 +03:00
payloadDbms = test . details . dbms
2013-02-01 20:24:04 +04:00
else :
2015-02-27 16:57:28 +03:00
payloadDbms = None
2013-02-01 20:24:04 +04:00
2015-02-15 19:28:37 +03:00
# Skip tests if title, vector or DBMS is not included by the
# given test filter
2018-03-13 15:45:42 +03:00
if conf . testFilter and not any ( conf . testFilter in str ( item ) or re . search ( conf . testFilter , str ( item ) , re . I ) for item in ( test . title , test . vector , payloadDbms ) ) :
2019-05-30 22:25:31 +03:00
debugMsg = " skipping test ' %s ' because its " % title
debugMsg + = " name/vector/DBMS is not included by the given filter "
logger . debug ( debugMsg )
continue
2010-11-28 21:10:54 +03:00
2015-10-01 12:57:33 +03:00
# Skip tests if title, vector or DBMS is included by the
# given skip filter
2018-03-13 15:45:42 +03:00
if conf . testSkip and any ( conf . testSkip in str ( item ) or re . search ( conf . testSkip , str ( item ) , re . I ) for item in ( test . title , test . vector , payloadDbms ) ) :
2019-05-30 22:25:31 +03:00
debugMsg = " skipping test ' %s ' because its " % title
debugMsg + = " name/vector/DBMS is included by the given skip filter "
logger . debug ( debugMsg )
continue
2015-10-01 12:57:33 +03:00
2015-02-27 16:57:28 +03:00
if payloadDbms is not None :
2015-02-21 05:23:42 +03:00
# Skip DBMS-specific test if it does not match the user's
# provided DBMS
2017-09-11 11:38:19 +03:00
if conf . dbms and not intersect ( payloadDbms , conf . dbms , True ) :
2010-12-18 13:42:09 +03:00
debugMsg = " skipping test ' %s ' because " % title
2017-09-11 11:41:50 +03:00
debugMsg + = " its declared DBMS is different than provided "
2017-08-28 14:02:08 +03:00
logger . debug ( debugMsg )
continue
2017-09-11 11:38:19 +03:00
if kb . dbmsFilter and not intersect ( payloadDbms , kb . dbmsFilter , True ) :
2017-08-28 14:02:08 +03:00
debugMsg = " skipping test ' %s ' because " % title
2017-09-11 11:41:50 +03:00
debugMsg + = " its declared DBMS is different than provided "
2010-12-18 13:42:09 +03:00
logger . debug ( debugMsg )
continue
2015-02-27 16:57:28 +03:00
# Skip DBMS-specific test if it does not match the
# previously identified DBMS (via DBMS-specific payload)
2017-09-11 11:38:19 +03:00
if injection . dbms and not intersect ( payloadDbms , injection . dbms , True ) :
2017-09-11 11:41:50 +03:00
debugMsg = " skipping test ' %s ' because " % title
debugMsg + = " its declared DBMS is different than identified "
2015-02-27 16:57:28 +03:00
logger . debug ( debugMsg )
continue
2015-02-21 05:23:42 +03:00
# Skip DBMS-specific test if it does not match the
# previously identified DBMS (via DBMS-specific error message)
2015-02-27 16:57:28 +03:00
if kb . reduceTests and not intersect ( payloadDbms , kb . reduceTests , True ) :
2017-11-29 17:59:00 +03:00
debugMsg = " skipping test ' %s ' because the heuristic " % title
debugMsg + = " tests showed that the back-end DBMS "
debugMsg + = " could be ' %s ' " % unArrayizeValue ( kb . reduceTests )
2011-01-02 02:38:11 +03:00
logger . debug ( debugMsg )
continue
2015-02-27 16:57:28 +03:00
# If the user did not decide to extend the tests to all
# DBMS-specific or the test payloads is not specific to the
# identified DBMS, then only test for it if both level and risk
# are below the corrisponding configuration's level and risk
# values
if not conf . testFilter and not ( kb . extendTests and intersect ( payloadDbms , kb . extendTests , True ) ) :
2015-02-13 12:59:03 +03:00
# Skip test if the risk is higher than the provided (or default)
# value
2015-02-27 16:57:28 +03:00
if test . risk > conf . risk :
2015-02-13 12:59:03 +03:00
debugMsg = " skipping test ' %s ' because the risk ( %d ) " % ( title , test . risk )
debugMsg + = " is higher than the provided ( %d ) " % conf . risk
logger . debug ( debugMsg )
continue
# Skip test if the level is higher than the provided (or default)
# value
2015-02-27 16:57:28 +03:00
if test . level > conf . level :
2015-02-13 12:59:03 +03:00
debugMsg = " skipping test ' %s ' because the level ( %d ) " % ( title , test . level )
debugMsg + = " is higher than the provided ( %d ) " % conf . level
logger . debug ( debugMsg )
continue
2010-12-18 13:42:09 +03:00
# Skip test if it does not match the same SQL injection clause
# already identified by another test
2010-11-28 21:10:54 +03:00
clauseMatch = False
2010-12-18 13:42:09 +03:00
for clauseTest in clause :
if injection . clause is not None and clauseTest in injection . clause :
2010-11-28 21:10:54 +03:00
clauseMatch = True
break
2012-02-22 19:53:36 +04:00
if clause != [ 0 ] and injection . clause and injection . clause != [ 0 ] and not clauseMatch :
2010-12-18 13:42:09 +03:00
debugMsg = " skipping test ' %s ' because the clauses " % title
2015-02-20 21:30:42 +03:00
debugMsg + = " differ from the clause already identified "
2010-12-18 13:42:09 +03:00
logger . debug ( debugMsg )
2010-11-28 21:10:54 +03:00
continue
2015-02-20 21:30:42 +03:00
# Skip test if the user provided custom character (for UNION-based payloads)
2011-05-10 19:34:54 +04:00
if conf . uChar is not None and ( " random number " in title or " (NULL) " in title ) :
debugMsg = " skipping test ' %s ' because the user " % title
debugMsg + = " provided a specific character, %s " % conf . uChar
2011-01-30 19:23:19 +03:00
logger . debug ( debugMsg )
continue
2018-03-16 17:21:19 +03:00
if stype == PAYLOAD . TECHNIQUE . UNION :
match = re . search ( r " ( \ d+)-( \ d+) " , test . request . columns )
if match and not injection . data :
_ = test . request . columns . split ( ' - ' ) [ - 1 ]
2019-05-20 16:13:52 +03:00
if conf . uCols is None and _ . isdigit ( ) :
2018-03-16 17:21:19 +03:00
if kb . futileUnion is None :
2019-05-20 16:13:52 +03:00
msg = " it is recommended to perform "
msg + = " only basic UNION tests if there is not "
2018-03-16 17:21:19 +03:00
msg + = " at least one other (potential) "
2019-05-20 16:13:52 +03:00
msg + = " technique found. Do you want to reduce "
2019-06-03 11:41:51 +03:00
msg + = " the number of requests? [Y/n] "
2019-05-20 16:13:52 +03:00
kb . futileUnion = readInput ( msg , default = ' Y ' , boolean = True )
2018-03-16 17:21:19 +03:00
2019-05-20 16:13:52 +03:00
if kb . futileUnion and int ( _ ) > 10 :
2018-03-16 17:21:19 +03:00
debugMsg = " skipping test ' %s ' " % title
logger . debug ( debugMsg )
continue
2018-03-16 17:11:04 +03:00
2010-12-18 13:42:09 +03:00
infoMsg = " testing ' %s ' " % title
logger . info ( infoMsg )
2010-11-28 21:10:54 +03:00
2015-02-21 16:12:30 +03:00
# Force back-end DBMS according to the current test DBMS value
# for proper payload unescaping
2015-02-27 16:57:28 +03:00
Backend . forceDbms ( payloadDbms [ 0 ] if isinstance ( payloadDbms , list ) else payloadDbms )
2011-02-07 02:27:56 +03:00
2010-12-18 13:42:09 +03:00
# Parse test's <request>
2011-08-02 22:20:21 +04:00
comment = agent . getComment ( test . request ) if len ( conf . boundaries ) > 1 else None
2018-11-02 00:24:36 +03:00
fstPayload = agent . cleanupPayload ( test . request . payload , origValue = value if place not in ( PLACE . URI , PLACE . CUSTOM_POST , PLACE . CUSTOM_HEADER ) and BOUNDED_INJECTION_MARKER not in ( value or " " ) else None )
2010-11-28 21:10:54 +03:00
2012-08-22 15:58:52 +04:00
for boundary in boundaries :
2010-12-18 13:42:09 +03:00
injectable = False
# Skip boundary if the level is higher than the provided (or
# default) value
# Parse boundary's <level>
2015-03-01 14:02:05 +03:00
if boundary . level > conf . level and not ( kb . extendTests and intersect ( payloadDbms , kb . extendTests , True ) ) :
2010-12-18 13:42:09 +03:00
continue
# Skip boundary if it does not match against test's <clause>
# Parse test's <clause> and boundary's <clause>
clauseMatch = False
for clauseTest in test . clause :
if clauseTest in boundary . clause :
clauseMatch = True
break
2012-02-22 19:53:36 +04:00
if test . clause != [ 0 ] and boundary . clause != [ 0 ] and not clauseMatch :
2010-12-18 13:42:09 +03:00
continue
# Skip boundary if it does not match against test's <where>
# Parse test's <where> and boundary's <where>
whereMatch = False
for where in test . where :
if where in boundary . where :
whereMatch = True
break
if not whereMatch :
continue
# Parse boundary's <prefix>, <suffix> and <ptype>
prefix = boundary . prefix if boundary . prefix else " "
suffix = boundary . suffix if boundary . suffix else " "
2015-02-20 21:30:42 +03:00
ptype = boundary . ptype
2012-09-25 11:25:35 +04:00
# Options --prefix/--suffix have a higher priority (if set by user)
prefix = conf . prefix if conf . prefix is not None else prefix
suffix = conf . suffix if conf . suffix is not None else suffix
comment = None if conf . suffix is not None else comment
2010-12-18 13:42:09 +03:00
# If the previous injections succeeded, we know which prefix,
# suffix and parameter type to use for further tests, no
# need to cycle through the boundaries for the following tests
condBound = ( injection . prefix is not None and injection . suffix is not None )
condBound & = ( injection . prefix != prefix or injection . suffix != suffix )
condType = injection . ptype is not None and injection . ptype != ptype
2015-02-20 21:30:42 +03:00
# If the payload is an inline query test for it regardless
# of previously identified injection types
if stype != PAYLOAD . TECHNIQUE . QUERY and ( condBound or condType ) :
2010-12-18 13:42:09 +03:00
continue
# For each test's <where>
for where in test . where :
templatePayload = None
2011-01-12 03:47:39 +03:00
vector = None
2010-12-18 13:42:09 +03:00
2019-01-22 13:08:57 +03:00
origValue = value
if kb . customInjectionMark in origValue :
origValue = origValue . split ( kb . customInjectionMark ) [ 0 ]
origValue = re . search ( r " ( \ w*) \ Z " , origValue ) . group ( 1 )
2010-12-18 13:42:09 +03:00
# Threat the parameter original value according to the
# test's <where> tag
2013-12-27 14:02:59 +04:00
if where == PAYLOAD . WHERE . ORIGINAL or conf . prefix :
2014-02-25 16:48:34 +04:00
if kb . tamperFunctions :
templatePayload = agent . payload ( place , parameter , value = " " , newValue = origValue , where = where )
2011-02-02 16:34:09 +03:00
elif where == PAYLOAD . WHERE . NEGATIVE :
2011-01-12 01:18:47 +03:00
# Use different page template than the original
# one as we are changing parameters value, which
# will likely result in a different content
2015-02-20 18:42:28 +03:00
2012-04-26 00:29:07 +04:00
if conf . invalidLogical :
2013-07-15 18:24:49 +04:00
_ = int ( kb . data . randomInt [ : 2 ] )
2019-01-22 13:08:57 +03:00
origValue = " %s AND %s LIKE %s " % ( origValue , _ , _ + 1 )
2012-04-26 00:29:07 +04:00
elif conf . invalidBignum :
2014-01-23 12:07:25 +04:00
origValue = kb . data . randomInt [ : 6 ]
2014-01-24 00:56:06 +04:00
elif conf . invalidString :
origValue = kb . data . randomStr [ : 6 ]
2012-04-26 00:29:07 +04:00
else :
2013-07-15 18:24:49 +04:00
origValue = " - %s " % kb . data . randomInt [ : 4 ]
2015-02-20 18:42:28 +03:00
2013-07-15 15:54:02 +04:00
templatePayload = agent . payload ( place , parameter , value = " " , newValue = origValue , where = where )
2011-02-02 16:34:09 +03:00
elif where == PAYLOAD . WHERE . REPLACE :
2010-12-18 13:42:09 +03:00
origValue = " "
2010-12-24 15:13:48 +03:00
kb . pageTemplate , kb . errorIsNone = getPageTemplate ( templatePayload , place )
2010-12-18 13:42:09 +03:00
# Forge request payload by prepending with boundary's
# prefix and appending the boundary's suffix to the
# test's ' <payload><comment> ' string
2015-07-05 02:47:01 +03:00
if fstPayload :
boundPayload = agent . prefixQuery ( fstPayload , prefix , where , clause )
boundPayload = agent . suffixQuery ( boundPayload , comment , suffix , where )
reqPayload = agent . payload ( place , parameter , newValue = boundPayload , where = where )
2018-04-12 15:38:32 +03:00
2015-07-10 01:54:02 +03:00
if reqPayload :
2018-04-12 15:38:32 +03:00
stripPayload = re . sub ( r " ( \ A| \ b|_)([A-Za-z] {4} ((?<!LIKE))| \ d+)(_| \ b| \ Z) " , r " \ g<1>. \ g<4> " , reqPayload )
if stripPayload in seenPayload :
2015-07-10 01:54:02 +03:00
continue
else :
2018-04-12 15:38:32 +03:00
seenPayload . add ( stripPayload )
2015-07-05 02:47:01 +03:00
else :
reqPayload = None
2010-12-18 13:42:09 +03:00
# Perform the test's request and check whether or not the
# payload was successful
# Parse test's <response>
for method , check in test . response . items ( ) :
2018-11-02 00:24:36 +03:00
check = agent . cleanupPayload ( check , origValue = value if place not in ( PLACE . URI , PLACE . CUSTOM_POST , PLACE . CUSTOM_HEADER ) and BOUNDED_INJECTION_MARKER not in ( value or " " ) else None )
2010-12-18 13:42:09 +03:00
# In case of boolean-based blind SQL injection
if method == PAYLOAD . METHOD . COMPARISON :
2011-02-08 00:53:05 +03:00
# Generate payload used for comparison
def genCmpPayload ( ) :
2018-11-02 00:24:36 +03:00
sndPayload = agent . cleanupPayload ( test . response . comparison , origValue = value if place not in ( PLACE . URI , PLACE . CUSTOM_POST , PLACE . CUSTOM_HEADER ) and BOUNDED_INJECTION_MARKER not in ( value or " " ) else None )
2011-02-08 00:53:05 +03:00
# Forge response payload by prepending with
# boundary's prefix and appending the boundary's
# suffix to the test's ' <payload><comment> '
# string
boundPayload = agent . prefixQuery ( sndPayload , prefix , where , clause )
boundPayload = agent . suffixQuery ( boundPayload , comment , suffix , where )
cmpPayload = agent . payload ( place , parameter , newValue = boundPayload , where = where )
2011-02-08 03:02:54 +03:00
2011-02-08 00:53:05 +03:00
return cmpPayload
2010-12-18 13:42:09 +03:00
2019-05-20 16:13:52 +03:00
# Useful to set kb.matchRatio at first based on False response content
2010-12-18 13:42:09 +03:00
kb . matchRatio = None
2012-03-29 18:33:27 +04:00
kb . negativeLogic = ( where == PAYLOAD . WHERE . NEGATIVE )
2020-07-20 13:43:17 +03:00
suggestion = None
2012-02-22 19:53:36 +04:00
Request . queryPage ( genCmpPayload ( ) , place , raise404 = False )
2016-06-03 16:51:52 +03:00
falsePage , falseHeaders , falseCode = threadData . lastComparisonPage or " " , threadData . lastComparisonHeaders , threadData . lastComparisonCode
2016-06-03 15:18:28 +03:00
falseRawResponse = " %s %s " % ( falseHeaders , falsePage )
2010-12-18 13:42:09 +03:00
2019-05-20 16:13:52 +03:00
# Checking if there is difference between current FALSE, original and heuristics page (i.e. not used parameter)
2020-05-04 01:06:03 +03:00
if not any ( ( kb . negativeLogic , conf . string , conf . notString ) ) :
2019-05-20 16:13:52 +03:00
try :
ratio = 1.0
seqMatcher = getCurrentThreadData ( ) . seqMatcher
for current in ( kb . originalPage , kb . heuristicPage ) :
2019-05-20 20:41:12 +03:00
seqMatcher . set_seq1 ( current or " " )
seqMatcher . set_seq2 ( falsePage or " " )
2019-05-20 16:13:52 +03:00
ratio * = seqMatcher . quick_ratio ( )
if ratio == 1.0 :
continue
2019-05-27 14:03:25 +03:00
except ( MemoryError , OverflowError ) :
2019-05-20 16:13:52 +03:00
pass
2010-12-18 13:42:09 +03:00
# Perform the test's True request
2010-12-24 15:36:00 +03:00
trueResult = Request . queryPage ( reqPayload , place , raise404 = False )
2016-06-03 16:51:52 +03:00
truePage , trueHeaders , trueCode = threadData . lastComparisonPage or " " , threadData . lastComparisonHeaders , threadData . lastComparisonCode
2016-06-03 15:18:28 +03:00
trueRawResponse = " %s %s " % ( trueHeaders , truePage )
2010-11-28 21:10:54 +03:00
2021-02-03 13:52:50 +03:00
if trueResult and not ( truePage == falsePage and not any ( ( kb . nullConnection , conf . code ) ) ) :
2016-01-14 15:40:50 +03:00
# Perform the test's False request
2011-02-08 00:53:05 +03:00
falseResult = Request . queryPage ( genCmpPayload ( ) , place , raise404 = False )
2010-11-28 21:10:54 +03:00
2010-12-18 13:42:09 +03:00
if not falseResult :
2016-01-14 15:40:50 +03:00
if kb . negativeLogic :
boundPayload = agent . prefixQuery ( kb . data . randomStr , prefix , where , clause )
boundPayload = agent . suffixQuery ( boundPayload , comment , suffix , where )
errorPayload = agent . payload ( place , parameter , newValue = boundPayload , where = where )
errorResult = Request . queryPage ( errorPayload , place , raise404 = False )
if errorResult :
continue
2018-03-31 12:02:48 +03:00
elif kb . heuristicPage and not any ( ( conf . string , conf . notString , conf . regexp , conf . code , kb . nullConnection ) ) :
2016-05-30 17:46:23 +03:00
_ = comparison ( kb . heuristicPage , None , getRatioValue = True )
2019-05-09 11:16:10 +03:00
if ( _ or 0 ) > ( kb . matchRatio or 0 ) :
2016-05-30 17:46:23 +03:00
kb . matchRatio = _
logger . debug ( " adjusting match ratio for current parameter to %.3f " % kb . matchRatio )
2016-01-14 15:40:50 +03:00
2018-03-29 15:47:30 +03:00
# Reducing false-positive "appears" messages in heavily dynamic environment
2018-03-31 12:02:48 +03:00
if kb . heavilyDynamic and not Request . queryPage ( reqPayload , place , raise404 = False ) :
2018-03-29 15:47:30 +03:00
continue
2016-06-03 16:51:52 +03:00
injectable = True
2019-05-10 10:30:21 +03:00
elif ( threadData . lastComparisonRatio or 0 ) > UPPER_RATIO_BOUND and not any ( ( conf . string , conf . notString , conf . regexp , conf . code , kb . nullConnection ) ) :
2017-02-06 15:28:33 +03:00
originalSet = set ( getFilteredPageContent ( kb . pageTemplate , True , " \n " ) . split ( " \n " ) )
trueSet = set ( getFilteredPageContent ( truePage , True , " \n " ) . split ( " \n " ) )
falseSet = set ( getFilteredPageContent ( falsePage , True , " \n " ) . split ( " \n " ) )
2017-12-12 13:18:17 +03:00
if threadData . lastErrorPage and threadData . lastErrorPage [ 1 ] :
errorSet = set ( getFilteredPageContent ( threadData . lastErrorPage [ 1 ] , True , " \n " ) . split ( " \n " ) )
else :
errorSet = set ( )
2017-02-06 15:28:33 +03:00
if originalSet == trueSet != falseSet :
2017-12-12 13:18:17 +03:00
candidates = trueSet - falseSet - errorSet
2017-02-06 15:28:33 +03:00
if candidates :
2019-05-30 23:40:51 +03:00
candidates = sorted ( candidates , key = len )
2017-02-06 15:28:33 +03:00
for candidate in candidates :
2017-05-26 15:08:08 +03:00
if re . match ( r " \ A[ \ w.,! ]+ \ Z " , candidate ) and ' ' in candidate and candidate . strip ( ) and len ( candidate ) > CANDIDATE_SENTENCE_MIN_LENGTH :
2020-07-20 13:43:17 +03:00
suggestion = conf . string = candidate
2017-02-06 15:28:33 +03:00
injectable = True
2019-05-21 13:07:19 +03:00
infoMsg = " %s parameter ' %s ' appears to be ' %s ' injectable (with --string= \" %s \" ) " % ( " %s " % paramType if paramType != parameter else " " , parameter , title , repr ( conf . string ) . lstrip ( ' u ' ) . strip ( " ' " ) )
2017-02-06 15:28:33 +03:00
logger . info ( infoMsg )
break
2016-06-23 18:52:37 +03:00
if injectable :
if kb . pageStable and not any ( ( conf . string , conf . notString , conf . regexp , conf . code , kb . nullConnection ) ) :
if all ( ( falseCode , trueCode ) ) and falseCode != trueCode :
2020-07-20 13:43:17 +03:00
suggestion = conf . code = trueCode
2016-06-03 16:51:52 +03:00
2019-05-21 13:07:19 +03:00
infoMsg = " %s parameter ' %s ' appears to be ' %s ' injectable (with --code= %d ) " % ( " %s " % paramType if paramType != parameter else " " , parameter , title , conf . code )
2016-06-03 16:51:52 +03:00
logger . info ( infoMsg )
2016-06-23 18:52:37 +03:00
else :
trueSet = set ( extractTextTagContent ( trueRawResponse ) )
2018-06-07 01:55:32 +03:00
trueSet | = set ( __ for _ in trueSet for __ in _ . split ( ) )
2015-02-21 15:59:44 +03:00
2016-06-23 18:52:37 +03:00
falseSet = set ( extractTextTagContent ( falseRawResponse ) )
2018-06-07 01:55:32 +03:00
falseSet | = set ( __ for _ in falseSet for __ in _ . split ( ) )
2016-06-23 18:52:37 +03:00
2017-12-12 13:18:17 +03:00
if threadData . lastErrorPage and threadData . lastErrorPage [ 1 ] :
errorSet = set ( extractTextTagContent ( threadData . lastErrorPage [ 1 ] ) )
2018-06-07 01:55:32 +03:00
errorSet | = set ( __ for _ in errorSet for __ in _ . split ( ) )
2017-12-12 13:18:17 +03:00
else :
errorSet = set ( )
2019-03-29 04:28:16 +03:00
candidates = filterNone ( _ . strip ( ) if _ . strip ( ) in trueRawResponse and _ . strip ( ) not in falseRawResponse else None for _ in ( trueSet - falseSet - errorSet ) )
2016-05-22 22:29:08 +03:00
2016-06-03 16:51:52 +03:00
if candidates :
2019-05-30 23:40:51 +03:00
candidates = sorted ( candidates , key = len )
2016-06-03 16:51:52 +03:00
for candidate in candidates :
2019-11-26 15:51:08 +03:00
if re . match ( r " \ A \ w { 2,} \ Z " , candidate ) : # Note: length of 1 (e.g. --string=5) could cause trouble, especially in error message pages with partially reflected payload content
2016-06-03 16:51:52 +03:00
break
2012-04-11 01:57:00 +04:00
2020-07-20 13:43:17 +03:00
suggestion = conf . string = candidate
2016-06-03 16:51:52 +03:00
2019-05-21 13:07:19 +03:00
infoMsg = " %s parameter ' %s ' appears to be ' %s ' injectable (with --string= \" %s \" ) " % ( " %s " % paramType if paramType != parameter else " " , parameter , title , repr ( conf . string ) . lstrip ( ' u ' ) . strip ( " ' " ) )
2016-06-03 16:51:52 +03:00
logger . info ( infoMsg )
2016-06-23 18:52:37 +03:00
if not any ( ( conf . string , conf . notString ) ) :
2019-03-29 04:28:16 +03:00
candidates = filterNone ( _ . strip ( ) if _ . strip ( ) in falseRawResponse and _ . strip ( ) not in trueRawResponse else None for _ in ( falseSet - trueSet ) )
2016-06-23 18:52:37 +03:00
if candidates :
2019-05-30 23:40:51 +03:00
candidates = sorted ( candidates , key = len )
2016-06-23 18:52:37 +03:00
for candidate in candidates :
if re . match ( r " \ A \ w+ \ Z " , candidate ) :
break
2020-07-20 13:43:17 +03:00
suggestion = conf . notString = candidate
2016-06-23 18:52:37 +03:00
2019-05-21 13:07:19 +03:00
infoMsg = " %s parameter ' %s ' appears to be ' %s ' injectable (with --not-string= \" %s \" ) " % ( " %s " % paramType if paramType != parameter else " " , parameter , title , repr ( conf . notString ) . lstrip ( ' u ' ) . strip ( " ' " ) )
2016-06-23 18:52:37 +03:00
logger . info ( infoMsg )
2020-07-20 13:43:17 +03:00
if not suggestion :
2019-05-21 13:07:19 +03:00
infoMsg = " %s parameter ' %s ' appears to be ' %s ' injectable " % ( " %s " % paramType if paramType != parameter else " " , parameter , title )
2016-09-26 18:02:40 +03:00
singleTimeLogMessage ( infoMsg )
2010-11-28 21:10:54 +03:00
2011-01-12 01:18:47 +03:00
# In case of error-based SQL injection
2010-12-18 13:42:09 +03:00
elif method == PAYLOAD . METHOD . GREP :
# Perform the test's request and grep the response
# body for the test's <grep> regular expression
2011-03-30 22:32:10 +04:00
try :
2017-06-05 17:28:19 +03:00
page , headers , _ = Request . queryPage ( reqPayload , place , content = True , raise404 = False )
2018-03-13 15:45:42 +03:00
output = extractRegexResult ( check , page , re . DOTALL | re . IGNORECASE )
output = output or extractRegexResult ( check , threadData . lastHTTPError [ 2 ] if wasLastResponseHTTPError ( ) else None , re . DOTALL | re . IGNORECASE )
2019-01-22 05:00:44 +03:00
output = output or extractRegexResult ( check , listToStrValue ( ( headers [ key ] for key in headers if key . lower ( ) != URI_HTTP_HEADER . lower ( ) ) if headers else None ) , re . DOTALL | re . IGNORECASE )
2018-03-13 15:45:42 +03:00
output = output or extractRegexResult ( check , threadData . lastRedirectMsg [ 1 ] if threadData . lastRedirectMsg and threadData . lastRedirectMsg [ 0 ] == threadData . lastRequestUID else None , re . DOTALL | re . IGNORECASE )
2011-03-30 22:32:10 +04:00
if output :
result = output == " 1 "
if result :
2019-05-21 13:07:19 +03:00
infoMsg = " %s parameter ' %s ' is ' %s ' injectable " % ( " %s " % paramType if paramType != parameter else " " , parameter , title )
2011-03-30 22:32:10 +04:00
logger . info ( infoMsg )
injectable = True
2019-01-22 03:20:27 +03:00
except SqlmapConnectionException as ex :
2013-07-31 11:22:45 +04:00
debugMsg = " problem occurred most likely because the "
2011-03-30 22:32:10 +04:00
debugMsg + = " server hasn ' t recovered as expected from the "
2020-11-27 01:41:35 +03:00
debugMsg + = " used error-based payload ( ' %s ' ) " % getSafeExString ( ex )
2011-03-30 22:32:10 +04:00
logger . debug ( debugMsg )
2010-11-28 21:10:54 +03:00
2010-12-18 13:42:09 +03:00
# In case of time-based blind or stacked queries
# SQL injections
elif method == PAYLOAD . METHOD . TIME :
# Perform the test's request
2010-12-24 15:36:00 +03:00
trueResult = Request . queryPage ( reqPayload , place , timeBasedCompare = True , raise404 = False )
2016-09-27 11:20:36 +03:00
trueCode = threadData . lastCode
2010-12-18 13:42:09 +03:00
if trueResult :
2016-09-27 12:21:12 +03:00
# Extra validation step (e.g. to check for DROP protection mechanisms)
2016-09-27 11:32:22 +03:00
if SLEEP_TIME_MARKER in reqPayload :
falseResult = Request . queryPage ( reqPayload . replace ( SLEEP_TIME_MARKER , " 0 " ) , place , timeBasedCompare = True , raise404 = False )
if falseResult :
continue
2010-12-18 13:42:09 +03:00
# Confirm test's results
2010-12-24 15:36:00 +03:00
trueResult = Request . queryPage ( reqPayload , place , timeBasedCompare = True , raise404 = False )
2010-12-18 13:42:09 +03:00
if trueResult :
2019-05-21 13:07:19 +03:00
infoMsg = " %s parameter ' %s ' appears to be ' %s ' injectable " % ( " %s " % paramType if paramType != parameter else " " , parameter , title )
2010-12-18 13:42:09 +03:00
logger . info ( infoMsg )
injectable = True
2011-01-12 01:18:47 +03:00
# In case of UNION query SQL injection
elif method == PAYLOAD . METHOD . UNION :
2011-01-12 15:01:32 +03:00
# Test for UNION injection and set the sample
# payload as well as the vector.
# NOTE: vector is set to a tuple with 6 elements,
2012-10-28 02:36:09 +04:00
# used afterwards by Agent.forgeUnionQuery()
2011-01-12 15:01:32 +03:00
# method to forge the UNION query payload
2011-01-15 19:59:53 +03:00
2011-01-18 01:57:33 +03:00
configUnion ( test . request . char , test . request . columns )
2017-08-28 14:02:08 +03:00
if len ( kb . dbmsFilter or [ ] ) == 1 :
Backend . forceDbms ( kb . dbmsFilter [ 0 ] )
elif not Backend . getIdentifiedDbms ( ) :
2015-02-21 05:23:42 +03:00
if kb . heuristicDbms is None :
2017-11-24 14:20:57 +03:00
if kb . heuristicTest == HEURISTIC_TEST . POSITIVE or injection . data :
warnMsg = " using unescaped version of the test "
warnMsg + = " because of zero knowledge of the "
warnMsg + = " back-end DBMS. You can try to "
warnMsg + = " explicitly set it with option ' --dbms ' "
singleTimeWarnMessage ( warnMsg )
2013-01-25 15:34:57 +04:00
else :
Backend . forceDbms ( kb . heuristicDbms )
2011-02-08 00:18:01 +03:00
2012-05-07 17:51:31 +04:00
if unionExtended :
2015-02-21 15:59:44 +03:00
infoMsg = " automatically extending ranges for UNION "
infoMsg + = " query injection technique tests as "
2013-08-22 13:11:30 +04:00
infoMsg + = " there is at least one other (potential) "
infoMsg + = " technique found "
2012-05-07 17:51:31 +04:00
singleTimeLogMessage ( infoMsg )
2011-01-19 02:03:50 +03:00
# Test for UNION query SQL injection
2011-01-16 04:17:09 +03:00
reqPayload , vector = unionTest ( comment , place , parameter , value , prefix , suffix )
2011-01-12 01:18:47 +03:00
2019-03-28 15:53:54 +03:00
if isinstance ( reqPayload , six . string_types ) :
2019-05-21 13:07:19 +03:00
infoMsg = " %s parameter ' %s ' is ' %s ' injectable " % ( " %s " % paramType if paramType != parameter else " " , parameter , title )
2011-01-12 01:18:47 +03:00
logger . info ( infoMsg )
injectable = True
2011-01-16 03:15:30 +03:00
# Overwrite 'where' because it can be set
# by unionTest() directly
2011-01-13 12:41:55 +03:00
where = vector [ 6 ]
2011-01-12 15:01:32 +03:00
2011-05-27 01:54:19 +04:00
kb . previousMethod = method
2018-03-21 16:22:59 +03:00
if conf . offline :
2013-10-11 01:08:20 +04:00
injectable = False
2010-12-18 13:42:09 +03:00
# If the injection test was successful feed the injection
# object with the test's details
if injectable is True :
# Feed with the boundaries details only the first time a
# test has been successful
if injection . place is None or injection . parameter is None :
2012-07-26 14:26:57 +04:00
if place in ( PLACE . USER_AGENT , PLACE . REFERER , PLACE . HOST ) :
2011-02-12 02:36:23 +03:00
injection . parameter = place
2010-12-18 13:42:09 +03:00
else :
injection . parameter = parameter
injection . place = place
injection . ptype = ptype
injection . prefix = prefix
injection . suffix = suffix
injection . clause = clause
2011-02-06 18:20:44 +03:00
# Feed with test details every time a test is successful
if hasattr ( test , " details " ) :
2016-12-20 01:47:39 +03:00
for key , value in test . details . items ( ) :
if key == " dbms " :
injection . dbms = value
2015-02-21 15:59:44 +03:00
2016-12-20 01:47:39 +03:00
if not isinstance ( value , list ) :
Backend . setDbms ( value )
2011-06-02 02:47:54 +04:00
else :
2016-12-20 01:47:39 +03:00
Backend . forceDbms ( value [ 0 ] , True )
2015-02-21 15:59:44 +03:00
2016-12-20 01:47:39 +03:00
elif key == " dbms_version " and injection . dbms_version is None and not conf . testFilter :
injection . dbms_version = Backend . setVersion ( value )
2015-02-21 15:59:44 +03:00
2016-12-20 01:47:39 +03:00
elif key == " os " and injection . os is None :
injection . os = Backend . setOs ( value )
2011-02-06 18:20:44 +03:00
2011-01-12 03:47:39 +03:00
if vector is None and " vector " in test and test . vector is not None :
2012-09-26 13:27:43 +04:00
vector = test . vector
2010-12-18 13:42:09 +03:00
2011-07-08 10:02:31 +04:00
injection . data [ stype ] = AttribDict ( )
2010-12-18 13:42:09 +03:00
injection . data [ stype ] . title = title
2011-01-27 22:44:24 +03:00
injection . data [ stype ] . payload = agent . removePayloadDelimiters ( reqPayload )
2010-12-18 13:42:09 +03:00
injection . data [ stype ] . where = where
2011-01-12 03:47:39 +03:00
injection . data [ stype ] . vector = vector
2010-12-18 13:42:09 +03:00
injection . data [ stype ] . comment = comment
injection . data [ stype ] . templatePayload = templatePayload
2011-01-14 17:55:59 +03:00
injection . data [ stype ] . matchRatio = kb . matchRatio
2016-09-27 11:20:36 +03:00
injection . data [ stype ] . trueCode = trueCode
2016-09-27 12:21:12 +03:00
injection . data [ stype ] . falseCode = falseCode
2010-12-18 13:42:09 +03:00
2011-01-14 17:55:59 +03:00
injection . conf . textOnly = conf . textOnly
2011-06-11 12:33:36 +04:00
injection . conf . titles = conf . titles
2016-06-03 16:51:52 +03:00
injection . conf . code = conf . code
2011-01-16 02:11:36 +03:00
injection . conf . string = conf . string
2012-07-26 14:06:02 +04:00
injection . conf . notString = conf . notString
2011-01-16 02:11:36 +03:00
injection . conf . regexp = conf . regexp
2011-07-25 15:05:49 +04:00
injection . conf . optimize = conf . optimize
2011-01-14 17:37:03 +03:00
2012-12-11 17:44:43 +04:00
if not kb . alerted :
if conf . beep :
beep ( )
2010-12-18 13:42:09 +03:00
2012-12-11 17:44:43 +04:00
if conf . alert :
infoMsg = " executing alerting shell command(s) ( ' %s ' ) " % conf . alert
logger . info ( infoMsg )
2019-11-11 16:03:43 +03:00
try :
2019-12-01 01:10:20 +03:00
process = subprocess . Popen ( getBytes ( conf . alert , sys . getfilesystemencoding ( ) or UNICODE_ENCODING ) , shell = True )
2019-11-11 16:03:43 +03:00
process . wait ( )
except Exception as ex :
errMsg = " error occurred while executing ' %s ' ( ' %s ' ) " % ( conf . alert , getSafeExString ( ex ) )
logger . error ( errMsg )
2012-12-11 15:48:58 +04:00
2012-12-11 17:44:43 +04:00
kb . alerted = True
2012-12-11 15:48:58 +04:00
2010-12-18 13:42:09 +03:00
# There is no need to perform this test for other
# <where> tags
break
if injectable is True :
2012-08-22 18:50:01 +04:00
kb . vulnHosts . add ( conf . hostname )
2010-12-01 01:40:25 +03:00
break
2008-10-15 19:38:22 +04:00
2011-02-06 23:23:23 +03:00
# Reset forced back-end DBMS value
Backend . flushForcedDbms ( )
2010-12-18 13:42:09 +03:00
except KeyboardInterrupt :
2011-04-08 14:39:07 +04:00
warnMsg = " user aborted during detection phase "
2010-12-18 13:42:09 +03:00
logger . warn ( warnMsg )
2017-07-26 00:32:30 +03:00
if conf . multipleTargets :
msg = " how do you want to proceed? [ne(X)t target/(s)kip current test/(e)nd detection phase/(n)ext parameter/(c)hange verbosity/(q)uit] "
2018-05-28 12:07:06 +03:00
choice = readInput ( msg , default = ' X ' , checkBatch = False ) . upper ( )
2017-07-26 00:32:30 +03:00
else :
msg = " how do you want to proceed? [(S)kip current test/(e)nd detection phase/(n)ext parameter/(c)hange verbosity/(q)uit] "
choice = readInput ( msg , default = ' S ' , checkBatch = False ) . upper ( )
2011-06-27 18:14:49 +04:00
2017-07-26 00:32:30 +03:00
if choice == ' X ' :
if conf . multipleTargets :
raise SqlmapSkipTargetException
elif choice == ' C ' :
2013-10-17 18:54:53 +04:00
choice = None
while not ( ( choice or " " ) . isdigit ( ) and 0 < = int ( choice ) < = 6 ) :
if choice :
logger . warn ( " invalid value " )
msg = " enter new verbosity level: [0-6] "
2017-04-19 15:46:27 +03:00
choice = readInput ( msg , default = str ( conf . verbose ) , checkBatch = False )
2013-10-17 18:54:53 +04:00
conf . verbose = int ( choice )
setVerbosity ( )
2014-10-07 14:00:11 +04:00
tests . insert ( 0 , test )
2017-04-18 16:48:05 +03:00
elif choice == ' N ' :
2011-06-27 18:14:49 +04:00
return None
2017-04-18 16:48:05 +03:00
elif choice == ' E ' :
2011-06-08 18:44:11 +04:00
kb . endDetection = True
2017-04-18 16:48:05 +03:00
elif choice == ' Q ' :
2012-12-06 17:14:19 +04:00
raise SqlmapUserQuitException
2010-12-04 18:47:02 +03:00
2011-02-06 23:23:23 +03:00
finally :
# Reset forced back-end DBMS value
Backend . flushForcedDbms ( )
2011-06-02 03:00:18 +04:00
Backend . flushForcedDbms ( True )
2010-12-01 01:40:25 +03:00
# Return the injection object
2010-11-29 00:27:47 +03:00
if injection . place is not None and injection . parameter is not None :
2011-06-03 19:43:50 +04:00
if not conf . dropSetCookie and PAYLOAD . TECHNIQUE . BOOLEAN in injection . data and injection . data [ PAYLOAD . TECHNIQUE . BOOLEAN ] . vector . startswith ( ' OR ' ) :
2016-05-22 15:30:32 +03:00
warnMsg = " in OR boolean-based injection cases, please consider usage "
2012-02-01 18:49:42 +04:00
warnMsg + = " of switch ' --drop-set-cookie ' if you experience any "
2011-06-03 19:43:50 +04:00
warnMsg + = " problems during data retrieval "
logger . warn ( warnMsg )
2016-05-06 14:06:59 +03:00
if not checkFalsePositives ( injection ) :
2020-12-01 00:25:56 +03:00
if conf . hostname in kb . vulnHosts :
kb . vulnHosts . remove ( conf . hostname )
2016-05-24 15:55:19 +03:00
if NOTE . FALSE_POSITIVE_OR_UNEXPLOITABLE not in injection . notes :
injection . notes . append ( NOTE . FALSE_POSITIVE_OR_UNEXPLOITABLE )
2016-05-06 14:06:59 +03:00
2010-11-29 00:27:47 +03:00
else :
2012-10-25 15:21:32 +04:00
injection = None
2016-05-30 16:20:21 +03:00
if injection and NOTE . FALSE_POSITIVE_OR_UNEXPLOITABLE not in injection . notes :
2013-01-16 05:31:03 +04:00
checkSuhosinPatch ( injection )
2014-08-20 03:11:26 +04:00
checkFilteredChars ( injection )
2012-10-25 15:21:32 +04:00
return injection
2008-10-15 19:38:22 +04:00
2018-04-01 13:45:47 +03:00
@stackedmethod
2013-01-25 15:34:57 +04:00
def heuristicCheckDbms ( injection ) :
2015-02-21 05:23:42 +03:00
"""
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
"""
2020-11-10 00:11:11 +03:00
2015-02-21 05:23:42 +03:00
retVal = False
2013-01-25 15:34:57 +04:00
2020-11-10 00:11:11 +03:00
if conf . skipHeuristics :
return retVal
2013-02-01 14:24:17 +04:00
pushValue ( kb . injection )
kb . injection = injection
2013-01-25 15:34:57 +04:00
2013-02-01 14:24:17 +04:00
for dbms in getPublicTypeMembers ( DBMS , True ) :
2020-01-23 01:41:06 +03:00
randStr1 , randStr2 = randomStr ( ) , randomStr ( )
2020-01-23 12:53:06 +03:00
2020-01-23 01:41:06 +03:00
Backend . forceDbms ( dbms )
2020-02-02 16:51:24 +03:00
if dbms in HEURISTIC_NULL_EVAL :
result = checkBooleanExpression ( " (SELECT %s %s ) IS NULL " % ( HEURISTIC_NULL_EVAL [ dbms ] , FROM_DUMMY_TABLE . get ( dbms , " " ) ) )
elif not ( ( randStr1 in unescaper . escape ( " ' %s ' " % randStr1 ) ) and list ( FROM_DUMMY_TABLE . values ( ) ) . count ( FROM_DUMMY_TABLE . get ( dbms , " " ) ) != 1 ) :
result = checkBooleanExpression ( " (SELECT ' %s ' %s )= %s %s %s " % ( randStr1 , FROM_DUMMY_TABLE . get ( dbms , " " ) , SINGLE_QUOTE_MARKER , randStr1 , SINGLE_QUOTE_MARKER ) )
else :
result = False
if result :
if not checkBooleanExpression ( " (SELECT ' %s ' %s )= %s %s %s " % ( randStr1 , FROM_DUMMY_TABLE . get ( dbms , " " ) , SINGLE_QUOTE_MARKER , randStr2 , SINGLE_QUOTE_MARKER ) ) :
2013-02-01 14:24:17 +04:00
retVal = dbms
break
2013-01-25 15:34:57 +04:00
2013-02-01 14:24:17 +04:00
Backend . flushForcedDbms ( )
kb . injection = popValue ( )
2013-01-25 15:34:57 +04:00
2013-01-25 15:52:31 +04:00
if retVal :
2015-02-21 05:23:42 +03:00
infoMsg = " heuristic (extended) test shows that the back-end DBMS " # Not as important as "parsing" counter-part (because of false-positives)
2013-01-25 15:52:31 +04:00
infoMsg + = " could be ' %s ' " % retVal
logger . info ( infoMsg )
2017-06-05 17:48:14 +03:00
kb . heuristicExtendedDbms = retVal
2013-01-25 15:34:57 +04:00
return retVal
2018-04-01 13:45:47 +03:00
@stackedmethod
2011-04-22 16:24:16 +04:00
def checkFalsePositives ( injection ) :
"""
2011-05-27 00:48:18 +04:00
Checks for false positives ( only in single special cases )
2011-04-22 16:24:16 +04:00
"""
2016-05-06 14:06:59 +03:00
retVal = True
2011-04-22 16:24:16 +04:00
2018-03-13 15:45:42 +03:00
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 ) :
2011-04-22 16:24:16 +04:00
pushValue ( kb . injection )
2011-04-25 04:36:09 +04:00
infoMsg = " checking if the injection point on %s " % injection . place
infoMsg + = " parameter ' %s ' is a false positive " % injection . parameter
2011-04-22 16:24:16 +04:00
logger . info ( infoMsg )
2012-03-09 14:28:19 +04:00
def _ ( ) :
return int ( randomInt ( 2 ) ) + 1
2011-04-22 16:24:16 +04:00
kb . injection = injection
2018-09-14 11:01:31 +03:00
for level in xrange ( conf . level ) :
2015-03-10 11:23:26 +03:00
while True :
randInt1 , randInt2 , randInt3 = ( _ ( ) for j in xrange ( 3 ) )
2012-10-16 12:24:05 +04:00
2015-03-10 11:23:26 +03:00
randInt1 = min ( randInt1 , randInt2 , randInt3 )
randInt3 = max ( randInt1 , randInt2 , randInt3 )
2013-06-26 12:55:34 +04:00
2019-11-26 16:03:22 +03:00
if conf . string and any ( conf . string in getUnicode ( _ ) for _ in ( randInt1 , randInt2 , randInt3 ) ) :
continue
2020-05-05 14:31:44 +03:00
if conf . notString and any ( conf . notString in getUnicode ( _ ) for _ in ( randInt1 , randInt2 , randInt3 ) ) :
continue
2015-03-10 11:23:26 +03:00
if randInt3 > randInt2 > randInt1 :
break
2013-06-26 12:55:34 +04:00
2019-04-29 12:01:40 +03:00
if not checkBooleanExpression ( " %d %s %d " % ( randInt1 , INFERENCE_EQUALS_CHAR , randInt1 ) ) :
2016-05-06 14:06:59 +03:00
retVal = False
2012-10-16 12:24:05 +04:00
break
2013-03-01 13:59:04 +04:00
if PAYLOAD . TECHNIQUE . BOOLEAN not in injection . data :
2019-04-29 12:01:40 +03:00
checkBooleanExpression ( " %d %s %d " % ( randInt1 , INFERENCE_EQUALS_CHAR , randInt2 ) ) # just in case if DBMS hasn't properly recovered from previous delayed request
2013-03-01 13:59:04 +04:00
2019-04-29 11:58:12 +03:00
if checkBooleanExpression ( " %d %s %d " % ( randInt1 , INFERENCE_EQUALS_CHAR , randInt3 ) ) : # this must not be evaluated to True
2016-05-06 14:06:59 +03:00
retVal = False
2012-10-16 12:24:05 +04:00
break
2013-06-26 12:55:34 +04:00
2019-04-29 11:58:12 +03:00
elif checkBooleanExpression ( " %d %s %d " % ( randInt3 , INFERENCE_EQUALS_CHAR , randInt2 ) ) : # this must not be evaluated to True
2016-05-06 14:06:59 +03:00
retVal = False
2012-10-16 12:24:05 +04:00
break
2013-06-26 12:55:34 +04:00
2019-04-29 11:58:12 +03:00
elif not checkBooleanExpression ( " %d %s %d " % ( randInt2 , INFERENCE_EQUALS_CHAR , randInt2 ) ) : # this must be evaluated to True
2016-05-06 14:06:59 +03:00
retVal = False
2012-10-16 12:24:05 +04:00
break
2011-04-22 16:24:16 +04:00
2019-04-29 12:01:40 +03:00
elif checkBooleanExpression ( " %d %d " % ( randInt3 , randInt2 ) ) : # this must not be evaluated to True (invalid statement)
2016-05-06 14:06:59 +03:00
retVal = False
2016-01-14 15:16:44 +03:00
break
2016-05-06 14:06:59 +03:00
if not retVal :
2014-08-20 03:45:42 +04:00
warnMsg = " false positive or unexploitable injection point detected "
2011-04-22 16:24:16 +04:00
logger . warn ( warnMsg )
kb . injection = popValue ( )
return retVal
2018-04-01 13:45:47 +03:00
@stackedmethod
2013-01-16 05:31:03 +04:00
def checkSuhosinPatch ( injection ) :
2012-10-25 15:21:32 +04:00
"""
2013-01-16 05:31:03 +04:00
Checks for existence of Suhosin - patch ( and alike ) protection mechanism ( s )
2012-10-25 15:21:32 +04:00
"""
if injection . place == PLACE . GET :
2014-08-20 03:45:42 +04:00
debugMsg = " checking for parameter length "
2017-12-13 15:49:55 +03:00
debugMsg + = " constraining mechanisms "
2014-08-20 03:45:42 +04:00
logger . debug ( debugMsg )
2012-10-25 15:21:32 +04:00
pushValue ( kb . injection )
kb . injection = injection
randInt = randomInt ( )
2013-05-15 15:38:26 +04:00
if not checkBooleanExpression ( " %d = %s %d " % ( randInt , ' ' * SUHOSIN_MAX_VALUE_LENGTH , randInt ) ) :
2017-12-13 15:49:55 +03:00
warnMsg = " parameter length constraining "
2013-01-16 05:31:03 +04:00
warnMsg + = " mechanism detected (e.g. Suhosin patch). "
2012-10-25 15:21:32 +04:00
warnMsg + = " Potential problems in enumeration phase can be expected "
logger . warn ( warnMsg )
kb . injection = popValue ( )
2018-04-01 13:45:47 +03:00
@stackedmethod
2014-08-20 03:11:26 +04:00
def checkFilteredChars ( injection ) :
2014-08-20 03:45:42 +04:00
debugMsg = " checking for filtered characters "
logger . debug ( debugMsg )
2014-08-20 03:11:26 +04:00
pushValue ( kb . injection )
kb . injection = injection
randInt = randomInt ( )
2014-08-20 03:59:30 +04:00
# all other techniques are already using parentheses in tests
if len ( injection . data ) == 1 and PAYLOAD . TECHNIQUE . BOOLEAN in injection . data :
if not checkBooleanExpression ( " ( %d )= %d " % ( randInt , randInt ) ) :
warnMsg = " it appears that some non-alphanumeric characters (i.e. ()) are "
warnMsg + = " filtered by the back-end server. There is a strong "
warnMsg + = " possibility that sqlmap won ' t be able to properly "
warnMsg + = " exploit this vulnerability "
2014-08-20 15:35:41 +04:00
logger . warn ( warnMsg )
2014-08-20 03:59:30 +04:00
# inference techniques depend on character '>'
if not any ( _ in injection . data for _ in ( PAYLOAD . TECHNIQUE . ERROR , PAYLOAD . TECHNIQUE . UNION , PAYLOAD . TECHNIQUE . QUERY ) ) :
2018-03-13 15:45:42 +03:00
if not checkBooleanExpression ( " %d > %d " % ( randInt + 1 , randInt ) ) :
2014-08-20 03:59:30 +04:00
warnMsg = " it appears that the character ' > ' is "
warnMsg + = " filtered by the back-end server. You are strongly "
warnMsg + = " advised to rerun with the ' --tamper=between ' "
logger . warn ( warnMsg )
2014-08-20 03:11:26 +04:00
kb . injection = popValue ( )
2011-01-15 16:15:10 +03:00
def heuristicCheckSqlInjection ( place , parameter ) :
2020-11-10 00:11:11 +03:00
if conf . skipHeuristics :
return None
2012-08-22 17:51:47 +04:00
origValue = conf . paramDict [ place ] [ parameter ]
2014-11-21 13:20:54 +03:00
paramType = conf . method if conf . method not in ( None , HTTPMETHOD . GET , HTTPMETHOD . POST ) else place
2016-12-20 01:47:39 +03:00
2010-10-11 16:26:35 +04:00
prefix = " "
2010-11-18 01:00:09 +03:00
suffix = " "
2016-12-20 01:47:39 +03:00
randStr = " "
2010-10-11 16:26:35 +04:00
2010-11-18 01:00:09 +03:00
if conf . prefix or conf . suffix :
2010-10-11 16:26:35 +04:00
if conf . prefix :
prefix = conf . prefix
2010-11-18 01:00:09 +03:00
if conf . suffix :
suffix = conf . suffix
2010-10-11 16:26:35 +04:00
2016-10-04 12:32:06 +03:00
while randStr . count ( ' \' ' ) != 1 or randStr . count ( ' \" ' ) != 1 :
2012-10-28 03:42:08 +04:00
randStr = randomStr ( length = 10 , alphabet = HEURISTIC_CHECK_ALPHABET )
2013-07-08 13:48:33 +04:00
kb . heuristicMode = True
2012-10-28 03:42:08 +04:00
payload = " %s %s %s " % ( prefix , randStr , suffix )
2011-01-12 01:18:47 +03:00
payload = agent . payload ( place , parameter , newValue = payload )
2017-06-05 17:28:19 +03:00
page , _ , _ = Request . queryPage ( payload , place , content = True , raise404 = False )
2011-11-22 12:39:13 +04:00
2016-05-30 17:46:23 +03:00
kb . heuristicPage = page
2013-07-08 13:48:33 +04:00
kb . heuristicMode = False
2011-11-22 12:39:13 +04:00
parseFilePaths ( page )
2013-01-29 23:53:11 +04:00
result = wasLastResponseDBMSError ( )
2010-10-16 19:10:48 +04:00
2019-05-21 13:07:19 +03:00
infoMsg = " heuristic (basic) test shows that %s parameter ' %s ' might " % ( " %s " % paramType if paramType != parameter else " " , parameter )
2010-10-16 19:10:48 +04:00
2012-08-22 17:51:47 +04:00
def _ ( page ) :
2016-06-26 02:42:21 +03:00
return any ( _ in ( page or " " ) for _ in FORMAT_EXCEPTION_STRINGS )
2012-08-20 14:14:01 +04:00
2012-08-22 17:51:47 +04:00
casting = _ ( page ) and not _ ( kb . originalPage )
2012-08-20 14:14:01 +04:00
2021-01-15 00:48:57 +03:00
if not casting and not result and kb . dynamicParameter and origValue . isdigit ( ) and not kb . heavilyDynamic :
2012-08-22 17:51:47 +04:00
randInt = int ( randomInt ( ) )
payload = " %s %s %s " % ( prefix , " %d - %d " % ( int ( origValue ) + randInt , randInt ) , suffix )
payload = agent . payload ( place , parameter , newValue = payload , where = PAYLOAD . WHERE . REPLACE )
result = Request . queryPage ( payload , place , raise404 = False )
2012-08-22 13:27:58 +04:00
2012-08-22 17:51:47 +04:00
if not result :
randStr = randomStr ( )
2016-04-15 14:47:19 +03:00
payload = " %s %s %s " % ( prefix , " %s . %d %s " % ( origValue , random . randint ( 1 , 9 ) , randStr ) , suffix )
2012-08-22 17:51:47 +04:00
payload = agent . payload ( place , parameter , newValue = payload , where = PAYLOAD . WHERE . REPLACE )
casting = Request . queryPage ( payload , place , raise404 = False )
2010-10-11 16:26:35 +04:00
2012-08-29 22:21:45 +04:00
kb . heuristicTest = HEURISTIC_TEST . CASTED if casting else HEURISTIC_TEST . NEGATIVE if not result else HEURISTIC_TEST . POSITIVE
2021-01-15 00:48:57 +03:00
if kb . heavilyDynamic :
debugMsg = " heuristic check stopped because of heavy dynamicity "
logger . debug ( debugMsg )
return kb . heuristicTest
2012-08-22 13:27:58 +04:00
if casting :
2018-12-21 13:29:57 +03:00
errMsg = " possible %s casting detected (e.g. ' " % ( " integer " if origValue . isdigit ( ) else " type " )
platform = conf . url . split ( ' . ' ) [ - 1 ] . lower ( )
if platform == WEB_PLATFORM . ASP :
errMsg + = " %s =CInt(request.querystring( \" %s \" )) " % ( parameter , parameter )
elif platform == WEB_PLATFORM . ASPX :
errMsg + = " int.TryParse(Request.QueryString[ \" %s \" ], out %s ) " % ( parameter , parameter )
elif platform == WEB_PLATFORM . JSP :
errMsg + = " %s =Integer.parseInt(request.getParameter( \" %s \" )) " % ( parameter , parameter )
else :
errMsg + = " $ %s =intval($_REQUEST[ \" %s \" ]) " % ( parameter , parameter )
errMsg + = " ' ) at the back-end web application "
2012-08-22 13:27:58 +04:00
logger . error ( errMsg )
2012-08-22 18:06:09 +04:00
if kb . ignoreCasted is None :
2012-08-22 18:10:56 +04:00
message = " do you want to skip those kind of cases (and save scanning time)? %s " % ( " [Y/n] " if conf . multipleTargets else " [y/N] " )
2017-04-19 15:46:27 +03:00
kb . ignoreCasted = readInput ( message , default = ' Y ' if conf . multipleTargets else ' N ' , boolean = True )
2012-08-22 13:27:58 +04:00
2012-08-22 17:51:47 +04:00
elif result :
2013-02-05 13:02:11 +04:00
infoMsg + = " be injectable "
if Backend . getErrorParsedDBMSes ( ) :
infoMsg + = " (possible DBMS: ' %s ' ) " % Format . getErrorParsedDBMSes ( )
2012-08-22 17:51:47 +04:00
logger . info ( infoMsg )
else :
infoMsg + = " not be injectable "
logger . warn ( infoMsg )
2014-10-01 15:31:48 +04:00
kb . heuristicMode = True
2019-11-18 13:40:07 +03:00
kb . disableHtmlDecoding = True
2014-10-01 15:31:48 +04:00
2016-01-15 00:21:47 +03:00
randStr1 , randStr2 = randomStr ( NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH ) , randomStr ( NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH )
2016-01-14 11:59:13 +03:00
value = " %s %s %s " % ( randStr1 , DUMMY_NON_SQLI_CHECK_APPENDIX , randStr2 )
2014-10-01 15:42:10 +04:00
payload = " %s %s %s " % ( prefix , " ' %s " % value , suffix )
2014-10-01 15:31:48 +04:00
payload = agent . payload ( place , parameter , newValue = payload )
2017-06-05 17:28:19 +03:00
page , _ , _ = Request . queryPage ( payload , place , content = True , raise404 = False )
2014-10-01 15:31:48 +04:00
2014-11-21 13:20:54 +03:00
paramType = conf . method if conf . method not in ( None , HTTPMETHOD . GET , HTTPMETHOD . POST ) else place
2020-12-31 14:09:15 +03:00
# Reference: https://bugs.python.org/issue18183
if value . upper ( ) in ( page or " " ) . upper ( ) :
2019-05-21 13:07:19 +03:00
infoMsg = " heuristic (XSS) test shows that %s parameter ' %s ' might be vulnerable to cross-site scripting (XSS) attacks " % ( " %s " % paramType if paramType != parameter else " " , parameter )
2016-01-14 11:59:13 +03:00
logger . info ( infoMsg )
2020-12-02 01:10:53 +03:00
if conf . beep :
beep ( )
2016-05-30 17:06:39 +03:00
for match in re . finditer ( FI_ERROR_REGEX , page or " " ) :
2016-01-15 00:21:47 +03:00
if randStr1 . lower ( ) in match . group ( 0 ) . lower ( ) :
2019-05-21 13:07:19 +03:00
infoMsg = " heuristic (FI) test shows that %s parameter ' %s ' might be vulnerable to file inclusion (FI) attacks " % ( " %s " % paramType if paramType != parameter else " " , parameter )
2016-01-15 00:21:47 +03:00
logger . info ( infoMsg )
2020-12-02 01:10:53 +03:00
if conf . beep :
beep ( )
2016-01-15 00:21:47 +03:00
break
2014-10-01 15:31:48 +04:00
2019-11-18 13:40:07 +03:00
kb . disableHtmlDecoding = False
2014-10-01 15:31:48 +04:00
kb . heuristicMode = False
2012-08-22 13:56:30 +04:00
return kb . heuristicTest
2010-12-20 13:13:14 +03:00
2008-10-15 19:38:22 +04:00
def checkDynParam ( place , parameter , value ) :
"""
2013-04-09 13:48:42 +04:00
This function checks if the URL parameter is dynamic . If it is
2008-10-15 19:38:22 +04:00
dynamic , the content of the page differs , otherwise the
dynamicity might depend on another parameter .
"""
2021-01-12 15:21:51 +03:00
if kb . choices . redirect :
2012-03-15 23:47:59 +04:00
return None
2010-12-18 12:51:34 +03:00
kb . matchRatio = None
2012-01-14 00:56:06 +04:00
dynResult = None
randInt = randomInt ( )
2010-11-10 01:44:23 +03:00
2014-11-21 13:20:54 +03:00
paramType = conf . method if conf . method not in ( None , HTTPMETHOD . GET , HTTPMETHOD . POST ) else place
2019-05-21 13:07:19 +03:00
infoMsg = " testing if %s parameter ' %s ' is dynamic " % ( " %s " % paramType if paramType != parameter else " " , parameter )
2008-12-09 00:24:24 +03:00
logger . info ( infoMsg )
2008-10-15 19:38:22 +04:00
2012-01-14 00:56:06 +04:00
try :
payload = agent . payload ( place , parameter , value , getUnicode ( randInt ) )
dynResult = Request . queryPage ( payload , place , raise404 = False )
2012-12-06 17:14:19 +04:00
except SqlmapConnectionException :
2012-01-14 00:56:06 +04:00
pass
2008-10-15 19:38:22 +04:00
2012-08-20 14:14:01 +04:00
result = None if dynResult is None else not dynResult
kb . dynamicParameter = result
return result
2008-10-15 19:38:22 +04:00
2010-10-25 14:41:37 +04:00
def checkDynamicContent ( firstPage , secondPage ) :
2010-09-14 01:01:46 +04:00
"""
2010-12-29 22:39:32 +03:00
This function checks for the dynamic content in the provided pages
2010-09-14 01:01:46 +04:00
"""
2010-11-04 12:18:32 +03:00
2010-11-04 00:51:36 +03:00
if kb . nullConnection :
2011-01-19 02:03:50 +03:00
debugMsg = " dynamic content checking skipped "
2010-11-04 12:18:32 +03:00
debugMsg + = " because NULL connection used "
logger . debug ( debugMsg )
2010-11-04 00:51:36 +03:00
return
2011-01-26 01:26:28 +03:00
if any ( page is None for page in ( firstPage , secondPage ) ) :
warnMsg = " can ' t check dynamic content "
warnMsg + = " because of lack of page content "
logger . critical ( warnMsg )
return
2016-06-30 15:57:56 +03:00
if firstPage and secondPage and any ( len ( _ ) > MAX_DIFFLIB_SEQUENCE_LENGTH for _ in ( firstPage , secondPage ) ) :
ratio = None
else :
try :
seqMatcher = getCurrentThreadData ( ) . seqMatcher
seqMatcher . set_seq1 ( firstPage )
seqMatcher . set_seq2 ( secondPage )
ratio = seqMatcher . quick_ratio ( )
except MemoryError :
ratio = None
if ratio is None :
kb . skipSeqMatcher = True
2010-10-07 02:29:52 +04:00
2010-12-29 22:39:32 +03:00
# In case of an intolerable difference turn on dynamicity removal engine
2016-06-30 15:57:56 +03:00
elif ratio < = UPPER_RATIO_BOUND :
2010-12-29 22:39:32 +03:00
findDynamicContent ( firstPage , secondPage )
2010-10-25 23:45:53 +04:00
2010-12-29 22:39:32 +03:00
count = 0
while not Request . queryPage ( ) :
count + = 1
2010-10-25 14:41:37 +04:00
2010-12-29 22:39:32 +03:00
if count > conf . retries :
2017-11-24 14:20:57 +03:00
warnMsg = " target URL content appears to be too dynamic. "
2012-03-18 21:27:08 +04:00
warnMsg + = " Switching to ' --text-only ' "
2011-01-03 14:06:49 +03:00
logger . warn ( warnMsg )
conf . textOnly = True
return
2010-10-25 23:45:53 +04:00
2017-11-24 14:20:57 +03:00
warnMsg = " target URL content appears to be heavily dynamic. "
warnMsg + = " sqlmap is going to retry the request(s) "
singleTimeLogMessage ( warnMsg , logging . CRITICAL )
2010-10-25 23:45:53 +04:00
2018-03-31 12:02:48 +03:00
kb . heavilyDynamic = True
2018-03-29 15:37:33 +03:00
2017-06-05 17:28:19 +03:00
secondPage , _ , _ = Request . queryPage ( content = True )
2010-12-29 22:39:32 +03:00
findDynamicContent ( firstPage , secondPage )
2010-09-13 17:31:01 +04:00
2008-10-15 19:38:22 +04:00
def checkStability ( ) :
"""
This function checks if the URL content is stable requesting the
2010-09-13 19:19:47 +04:00
same page two times with a small delay within each request to
2008-10-15 19:38:22 +04:00
assume that it is stable .
In case the content of the page differs when requesting
the same page , the dynamicity might depend on other parameters ,
like for instance string matching ( - - string ) .
"""
2017-11-24 14:20:57 +03:00
infoMsg = " testing if the target URL content is stable "
2008-12-09 00:24:24 +03:00
logger . info ( infoMsg )
2008-10-15 19:38:22 +04:00
2012-02-22 19:53:36 +04:00
firstPage = kb . originalPage # set inside checkConnection()
2015-07-10 10:24:14 +03:00
2019-06-04 16:46:56 +03:00
delay = MAX_STABILITY_DELAY - ( time . time ( ) - ( kb . originalPageTime or 0 ) )
delay = max ( 0 , min ( MAX_STABILITY_DELAY , delay ) )
2015-07-10 10:24:14 +03:00
time . sleep ( delay )
2017-06-05 17:28:19 +03:00
secondPage , _ , _ = Request . queryPage ( content = True , noteResponseTime = False , raise404 = False )
2008-10-15 19:38:22 +04:00
2021-01-12 15:21:51 +03:00
if kb . choices . redirect :
2012-03-18 21:27:08 +04:00
return None
2010-10-25 17:52:21 +04:00
kb . pageStable = ( firstPage == secondPage )
2008-12-18 23:48:23 +03:00
2010-10-25 17:52:21 +04:00
if kb . pageStable :
2010-02-10 12:27:34 +03:00
if firstPage :
2017-11-24 14:20:57 +03:00
infoMsg = " target URL content is stable "
2011-04-30 19:29:59 +04:00
logger . info ( infoMsg )
2010-02-10 12:27:34 +03:00
else :
2011-01-19 02:03:50 +03:00
errMsg = " there was an error checking the stability of page "
2012-05-28 18:04:17 +04:00
errMsg + = " because of lack of content. Please check the "
2010-03-16 15:14:02 +03:00
errMsg + = " page request results (and probable errors) by "
errMsg + = " using higher verbosity levels "
2011-08-05 14:55:21 +04:00
logger . error ( errMsg )
2009-02-09 13:28:03 +03:00
2010-10-25 17:52:21 +04:00
else :
2018-09-18 17:52:17 +03:00
warnMsg = " target URL content is not stable (i.e. content differs). sqlmap will base the page "
2010-10-16 19:10:48 +04:00
warnMsg + = " comparison on a sequence matcher. If no dynamic nor "
warnMsg + = " injectable parameters are detected, or in case of "
warnMsg + = " junk results, refer to user ' s manual paragraph "
2017-11-24 14:20:57 +03:00
warnMsg + = " ' Page comparison ' "
2008-12-20 04:54:08 +03:00
logger . warn ( warnMsg )
2008-10-15 19:38:22 +04:00
2011-01-16 22:29:06 +03:00
message = " how do you want to proceed? [(C)ontinue/(s)tring/(r)egex/(q)uit] "
2017-04-19 15:46:27 +03:00
choice = readInput ( message , default = ' C ' ) . upper ( )
2010-10-16 19:10:48 +04:00
2017-04-18 16:48:05 +03:00
if choice == ' Q ' :
2012-12-06 17:14:19 +04:00
raise SqlmapUserQuitException
2010-10-16 19:10:48 +04:00
2017-04-18 16:48:05 +03:00
elif choice == ' S ' :
2010-10-12 19:49:04 +04:00
showStaticWords ( firstPage , secondPage )
2010-10-16 19:10:48 +04:00
2010-10-12 19:49:04 +04:00
message = " please enter value for parameter ' string ' : "
2017-04-18 16:48:05 +03:00
string = readInput ( message )
2010-10-16 19:10:48 +04:00
2017-04-18 16:48:05 +03:00
if string :
conf . string = string
2010-11-04 12:18:32 +03:00
if kb . nullConnection :
2011-01-19 02:03:50 +03:00
debugMsg = " turning off NULL connection "
2010-11-04 12:18:32 +03:00
debugMsg + = " support because of string checking "
logger . debug ( debugMsg )
kb . nullConnection = None
2010-10-12 19:49:04 +04:00
else :
2010-11-10 22:44:51 +03:00
errMsg = " Empty value supplied "
2013-01-04 02:20:55 +04:00
raise SqlmapNoneDataException ( errMsg )
2010-10-16 19:10:48 +04:00
2017-04-18 16:48:05 +03:00
elif choice == ' R ' :
2010-10-12 19:49:04 +04:00
message = " please enter value for parameter ' regex ' : "
2017-04-18 16:48:05 +03:00
regex = readInput ( message )
2010-10-16 19:10:48 +04:00
2017-04-18 16:48:05 +03:00
if regex :
conf . regex = regex
2010-11-04 12:18:32 +03:00
if kb . nullConnection :
2011-01-19 02:03:50 +03:00
debugMsg = " turning off NULL connection "
2010-11-04 12:18:32 +03:00
debugMsg + = " support because of regex checking "
logger . debug ( debugMsg )
kb . nullConnection = None
2010-10-12 19:49:04 +04:00
else :
2010-11-10 22:44:51 +03:00
errMsg = " Empty value supplied "
2013-01-04 02:20:55 +04:00
raise SqlmapNoneDataException ( errMsg )
2011-01-06 11:54:50 +03:00
2010-10-12 19:49:04 +04:00
else :
2010-12-29 22:39:32 +03:00
checkDynamicContent ( firstPage , secondPage )
2010-11-29 18:25:45 +03:00
2010-10-25 17:52:21 +04:00
return kb . pageStable
2010-03-12 15:23:05 +03:00
2008-10-15 19:38:22 +04:00
def checkString ( ) :
if not conf . string :
return True
2011-01-19 02:03:50 +03:00
infoMsg = " testing if the provided string is within the "
2008-12-09 00:24:24 +03:00
infoMsg + = " target URL page content "
logger . info ( infoMsg )
2008-10-15 19:38:22 +04:00
2017-06-05 17:28:19 +03:00
page , headers , _ = Request . queryPage ( content = True )
2011-08-12 19:33:37 +04:00
rawResponse = " %s %s " % ( listToStrValue ( headers . headers if headers else " " ) , page )
2008-10-15 19:38:22 +04:00
2011-08-12 19:33:37 +04:00
if conf . string not in rawResponse :
2011-01-19 02:03:50 +03:00
warnMsg = " you provided ' %s ' as the string to " % conf . string
2010-11-18 01:00:09 +03:00
warnMsg + = " match, but such a string is not within the target "
2011-08-12 19:33:37 +04:00
warnMsg + = " URL raw response, sqlmap will carry on anyway "
2010-11-18 01:00:09 +03:00
logger . warn ( warnMsg )
2008-10-15 19:38:22 +04:00
2010-11-18 01:00:09 +03:00
return True
2008-10-15 19:38:22 +04:00
2008-12-12 22:06:31 +03:00
def checkRegexp ( ) :
if not conf . regexp :
return True
2011-01-19 02:03:50 +03:00
infoMsg = " testing if the provided regular expression matches within "
2008-12-12 22:06:31 +03:00
infoMsg + = " the target URL page content "
logger . info ( infoMsg )
2017-06-05 17:28:19 +03:00
page , headers , _ = Request . queryPage ( content = True )
2011-08-12 19:33:37 +04:00
rawResponse = " %s %s " % ( listToStrValue ( headers . headers if headers else " " ) , page )
2008-12-12 22:06:31 +03:00
2011-08-12 19:33:37 +04:00
if not re . search ( conf . regexp , rawResponse , re . I | re . M ) :
2018-09-18 17:52:17 +03:00
warnMsg = " you provided ' %s ' as the regular expression " % conf . regexp
warnMsg + = " which does not have any match within the target URL raw response. sqlmap "
2011-08-12 19:33:37 +04:00
warnMsg + = " will carry on anyway "
2010-11-18 01:00:09 +03:00
logger . warn ( warnMsg )
2008-12-12 22:06:31 +03:00
2010-11-18 01:00:09 +03:00
return True
2008-12-12 22:06:31 +03:00
2018-04-01 13:45:47 +03:00
@stackedmethod
2011-07-06 09:44:47 +04:00
def checkWaf ( ) :
"""
Reference : http : / / seclists . org / nmap - dev / 2011 / q2 / att - 1005 / http - waf - detect . nse
"""
2015-09-21 15:57:44 +03:00
if any ( ( conf . string , conf . notString , conf . regexp , conf . dummy , conf . offline , conf . skipWaf ) ) :
2015-05-29 17:01:41 +03:00
return None
2019-03-27 15:33:46 +03:00
if kb . originalCode == _http_client . NOT_FOUND :
2019-03-20 13:33:10 +03:00
return None
2016-01-09 01:23:41 +03:00
_ = hashDBRetrieve ( HASHDB_KEYS . CHECK_WAF_RESULT , True )
if _ is not None :
if _ :
warnMsg = " previous heuristics detected that the target "
2018-09-14 11:01:31 +03:00
warnMsg + = " is protected by some kind of WAF/IPS "
2016-01-09 01:23:41 +03:00
logger . critical ( warnMsg )
return _
2017-07-29 04:35:05 +03:00
if not kb . originalPage :
return None
2015-09-21 15:57:44 +03:00
infoMsg = " checking if the target is protected by "
2018-09-14 11:01:31 +03:00
infoMsg + = " some kind of WAF/IPS "
2015-09-21 15:57:44 +03:00
logger . info ( infoMsg )
2011-07-06 09:44:47 +04:00
retVal = False
2019-01-26 14:36:03 +03:00
payload = " %d %s " % ( randomInt ( ) , IPS_WAF_CHECK_PAYLOAD )
2013-07-08 14:44:14 +04:00
2018-03-11 05:20:33 +03:00
if PLACE . URI in conf . parameters :
place = PLACE . POST
value = " %s = %s " % ( randomStr ( ) , agent . addPayloadDelimiters ( payload ) )
else :
place = PLACE . GET
value = " " if not conf . parameters . get ( PLACE . GET ) else conf . parameters [ PLACE . GET ] + DEFAULT_GET_POST_DELIMITER
value + = " %s = %s " % ( randomStr ( ) , agent . addPayloadDelimiters ( payload ) )
2011-07-06 09:44:47 +04:00
2021-01-12 15:21:51 +03:00
pushValue ( kb . choices . redirect )
2018-10-12 01:29:43 +03:00
pushValue ( kb . resendPostOnRedirect )
2015-09-21 14:23:56 +03:00
pushValue ( conf . timeout )
2018-08-29 12:06:45 +03:00
2021-01-12 15:21:51 +03:00
kb . choices . redirect = REDIRECTION . YES
2018-10-12 01:29:43 +03:00
kb . resendPostOnRedirect = False
2019-06-04 15:44:06 +03:00
conf . timeout = IPS_WAF_CHECK_TIMEOUT
2015-09-21 14:23:56 +03:00
2015-01-06 16:01:47 +03:00
try :
2019-06-04 15:44:06 +03:00
retVal = ( Request . queryPage ( place = place , value = value , getRatioValue = True , noteResponseTime = False , silent = True , raise404 = False , disableTampering = True ) [ 1 ] or 0 ) < IPS_WAF_CHECK_RATIO
2015-01-06 16:01:47 +03:00
except SqlmapConnectionException :
retVal = True
finally :
kb . matchRatio = None
2018-08-29 12:06:45 +03:00
2015-09-21 14:23:56 +03:00
conf . timeout = popValue ( )
2018-10-12 01:29:43 +03:00
kb . resendPostOnRedirect = popValue ( )
2021-01-12 15:21:51 +03:00
kb . choices . redirect = popValue ( )
2011-07-06 09:44:47 +04:00
2019-05-24 15:18:18 +03:00
hashDBWrite ( HASHDB_KEYS . CHECK_WAF_RESULT , retVal , True )
2011-07-06 09:44:47 +04:00
if retVal :
2019-05-24 14:54:10 +03:00
if not kb . identifiedWafs :
warnMsg = " heuristics detected that the target "
warnMsg + = " is protected by some kind of WAF/IPS "
logger . critical ( warnMsg )
message = " are you sure that you want to "
2019-05-24 15:18:18 +03:00
message + = " continue with further target testing? [Y/n] "
choice = readInput ( message , default = ' Y ' , boolean = True )
2019-05-24 14:54:10 +03:00
if not choice :
raise SqlmapUserQuitException
2019-05-24 15:18:18 +03:00
else :
if not conf . tamper :
warnMsg = " please consider usage of tamper scripts (option ' --tamper ' ) "
singleTimeWarnMessage ( warnMsg )
2013-02-26 14:08:06 +04:00
2013-02-21 14:14:57 +04:00
return retVal
2018-04-01 13:45:47 +03:00
@stackedmethod
2010-09-16 12:43:10 +04:00
def checkNullConnection ( ) :
2010-10-15 15:17:17 +04:00
"""
Reference : http : / / www . wisec . it / sectou . php ? id = 472 f952d79293
"""
2012-08-20 12:41:43 +04:00
if conf . data :
return False
2019-03-25 13:42:16 +03:00
_ = hashDBRetrieve ( HASHDB_KEYS . CHECK_NULL_CONNECTION_RESULT , True )
if _ is not None :
kb . nullConnection = _
2010-09-16 12:43:10 +04:00
2019-03-25 13:42:16 +03:00
if _ :
dbgMsg = " resuming NULL connection method ' %s ' " % _
logger . debug ( dbgMsg )
2015-07-18 18:01:34 +03:00
2019-03-25 13:42:16 +03:00
else :
infoMsg = " testing NULL connection to the target URL "
logger . info ( infoMsg )
2010-12-06 18:50:19 +03:00
2019-03-25 13:42:16 +03:00
pushValue ( kb . pageCompress )
kb . pageCompress = False
2010-10-15 14:24:54 +04:00
2019-03-25 13:42:16 +03:00
try :
page , headers , _ = Request . getPage ( method = HTTPMETHOD . HEAD , raise404 = False )
2010-12-06 18:50:19 +03:00
2019-03-25 13:42:16 +03:00
if not page and HTTP_HEADER . CONTENT_LENGTH in ( headers or { } ) :
kb . nullConnection = NULLCONNECTION . HEAD
2010-09-16 12:43:10 +04:00
2019-03-25 13:42:16 +03:00
infoMsg = " NULL connection is supported with HEAD method ( ' Content-Length ' ) "
2010-10-15 14:24:54 +04:00
logger . info ( infoMsg )
2013-05-17 17:04:25 +04:00
else :
2019-03-25 13:42:16 +03:00
page , headers , _ = Request . getPage ( auxHeaders = { HTTP_HEADER . RANGE : " bytes=-1 " } )
2013-05-17 17:04:25 +04:00
2019-03-25 13:42:16 +03:00
if page and len ( page ) == 1 and HTTP_HEADER . CONTENT_RANGE in ( headers or { } ) :
kb . nullConnection = NULLCONNECTION . RANGE
2013-05-17 17:04:25 +04:00
2019-03-25 13:42:16 +03:00
infoMsg = " NULL connection is supported with GET method ( ' Range ' ) "
2013-05-17 17:04:25 +04:00
logger . info ( infoMsg )
2019-03-25 13:42:16 +03:00
else :
_ , headers , _ = Request . getPage ( skipRead = True )
2010-12-06 18:50:19 +03:00
2019-03-25 13:42:16 +03:00
if HTTP_HEADER . CONTENT_LENGTH in ( headers or { } ) :
kb . nullConnection = NULLCONNECTION . SKIP_READ
2010-09-16 12:43:10 +04:00
2019-03-25 13:42:16 +03:00
infoMsg = " NULL connection is supported with ' skip-read ' method "
logger . info ( infoMsg )
except SqlmapConnectionException :
pass
finally :
kb . pageCompress = popValue ( )
kb . nullConnection = False if kb . nullConnection is None else kb . nullConnection
hashDBWrite ( HASHDB_KEYS . CHECK_NULL_CONNECTION_RESULT , kb . nullConnection , True )
2013-05-17 18:04:05 +04:00
2019-03-25 13:42:16 +03:00
return kb . nullConnection in getPublicTypeMembers ( NULLCONNECTION , True )
2010-09-16 12:43:10 +04:00
2010-11-15 15:19:22 +03:00
def checkConnection ( suppressOutput = False ) :
2019-03-20 13:33:10 +03:00
threadData = getCurrentThreadData ( )
2018-05-03 14:31:27 +03:00
if not re . search ( r " \ A \ d { 1,3} \ . \ d { 1,3} \ . \ d { 1,3} \ . \ d { 1,3} \ Z " , conf . hostname ) :
if not any ( ( conf . proxy , conf . tor , conf . dummy , conf . offline ) ) :
try :
debugMsg = " resolving hostname ' %s ' " % conf . hostname
logger . debug ( debugMsg )
socket . getaddrinfo ( conf . hostname , None )
except socket . gaierror :
errMsg = " host ' %s ' does not exist " % conf . hostname
raise SqlmapConnectionException ( errMsg )
2019-01-22 02:40:48 +03:00
except socket . error as ex :
2018-05-03 14:31:27 +03:00
errMsg = " problem occurred while "
errMsg + = " resolving a host name ' %s ' ( ' %s ' ) " % ( conf . hostname , getSafeExString ( ex ) )
raise SqlmapConnectionException ( errMsg )
2019-01-22 02:40:48 +03:00
except UnicodeError as ex :
2018-12-04 01:18:52 +03:00
errMsg = " problem occurred while "
errMsg + = " handling a host name ' %s ' ( ' %s ' ) " % ( conf . hostname , getSafeExString ( ex ) )
raise SqlmapDataException ( errMsg )
2010-05-21 17:36:49 +04:00
2015-07-10 17:10:24 +03:00
if not suppressOutput and not conf . dummy and not conf . offline :
2013-04-09 13:48:42 +04:00
infoMsg = " testing connection to the target URL "
2010-11-15 15:19:22 +03:00
logger . info ( infoMsg )
2008-10-15 19:38:22 +04:00
try :
2015-07-10 10:51:11 +03:00
kb . originalPageTime = time . time ( )
2019-03-20 13:33:10 +03:00
Request . queryPage ( content = True , noteResponseTime = False )
2011-01-01 23:19:55 +03:00
kb . errorIsNone = False
2011-01-12 01:18:47 +03:00
2018-09-05 00:01:17 +03:00
if any ( _ in ( kb . serverHeader or " " ) for _ in PRECONNECT_INCOMPATIBLE_SERVERS ) :
singleTimeWarnMessage ( " turning off pre-connect mechanism because of incompatible server ( ' %s ' ) " % kb . serverHeader )
conf . disablePrecon = True
2013-01-29 23:53:11 +04:00
if not kb . originalPage and wasLastResponseHTTPError ( ) :
2019-11-18 18:17:17 +03:00
if getLastRequestHTTPError ( ) not in ( conf . ignoreCode or [ ] ) :
errMsg = " unable to retrieve page content "
raise SqlmapConnectionException ( errMsg )
2013-01-29 23:53:11 +04:00
elif wasLastResponseDBMSError ( ) :
2012-07-17 03:25:02 +04:00
warnMsg = " there is a DBMS error found in the HTTP response body "
2011-01-12 01:18:47 +03:00
warnMsg + = " which could interfere with the results of the tests "
2011-01-01 23:19:55 +03:00
logger . warn ( warnMsg )
2013-01-29 23:53:11 +04:00
elif wasLastResponseHTTPError ( ) :
2019-07-17 14:20:24 +03:00
if getLastRequestHTTPError ( ) not in ( conf . ignoreCode or [ ] ) :
2017-08-23 14:17:37 +03:00
warnMsg = " the web server responded with an HTTP error code ( %d ) " % getLastRequestHTTPError ( )
warnMsg + = " which could interfere with the results of the tests "
logger . warn ( warnMsg )
2011-01-01 23:19:55 +03:00
else :
kb . errorIsNone = True
2012-05-25 12:30:24 +04:00
2021-01-12 15:21:51 +03:00
if kb . choices . redirect == REDIRECTION . YES and threadData . lastRedirectURL and threadData . lastRedirectURL [ 0 ] == threadData . lastRequestUID :
2019-04-18 17:06:19 +03:00
if ( threadData . lastRedirectURL [ 1 ] or " " ) . startswith ( " https:// " ) and conf . hostname in getUnicode ( threadData . lastRedirectURL [ 1 ] ) :
2018-03-28 16:13:33 +03:00
conf . url = re . sub ( r " https?:// " , " https:// " , conf . url )
match = re . search ( r " :( \ d+) " , threadData . lastRedirectURL [ 1 ] )
port = match . group ( 1 ) if match else 443
2019-05-08 13:28:50 +03:00
conf . url = re . sub ( r " : \ d+(/| \ Z) " , r " : %s \ g<1> " % port , conf . url )
2018-03-28 16:13:33 +03:00
2019-01-22 02:40:48 +03:00
except SqlmapConnectionException as ex :
2012-05-25 12:30:24 +04:00
if conf . ipv6 :
warnMsg = " check connection to a provided "
warnMsg + = " IPv6 address with a tool like ping6 "
2013-05-20 00:17:53 +04:00
warnMsg + = " (e.g. ' ping6 -I eth0 %s ' ) " % conf . hostname
2012-05-25 12:30:24 +04:00
warnMsg + = " prior to running sqlmap to avoid "
warnMsg + = " any addressing issues "
singleTimeWarnMessage ( warnMsg )
2019-03-27 15:33:46 +03:00
if any ( code in kb . httpErrorCodes for code in ( _http_client . NOT_FOUND , ) ) :
2015-09-10 16:51:33 +03:00
errMsg = getSafeExString ( ex )
2014-06-16 11:51:24 +04:00
logger . critical ( errMsg )
2012-02-07 15:16:03 +04:00
if conf . multipleTargets :
return False
2011-12-16 03:29:11 +04:00
msg = " it is not recommended to continue in this kind of cases. Do you want to quit and make sure that everything is set up properly? [Y/n] "
2017-04-18 16:48:05 +03:00
if readInput ( msg , default = ' Y ' , boolean = True ) :
2012-12-06 17:14:19 +04:00
raise SqlmapSilentQuitException
2011-12-16 03:29:11 +04:00
else :
kb . ignoreNotFound = True
2011-12-05 13:25:56 +04:00
else :
2011-12-16 03:29:11 +04:00
raise
2019-03-20 13:33:10 +03:00
finally :
kb . originalPage = kb . pageTemplate = threadData . lastPage
kb . originalCode = threadData . lastCode
2008-10-15 19:38:22 +04:00
2020-08-20 14:54:52 +03:00
if conf . cj and not conf . cookie and not any ( _ [ 0 ] == HTTP_HEADER . COOKIE for _ in conf . httpHeaders ) and not conf . dropSetCookie :
2019-10-14 11:42:10 +03:00
candidate = DEFAULT_COOKIE_DELIMITER . join ( " %s = %s " % ( _ . name , _ . value ) for _ in conf . cj )
message = " you have not declared cookie(s), while "
message + = " server wants to set its own ( ' %s ' ). " % re . sub ( r " (=[^=;] {10} [^=;])[^=;]+([^=;] {10} ) " , r " \ g<1>... \ g<2> " , candidate )
message + = " Do you want to use those [Y/n] "
if readInput ( message , default = ' Y ' , boolean = True ) :
2019-10-21 11:11:38 +03:00
kb . mergeCookies = True
2019-10-14 11:42:10 +03:00
conf . httpHeaders . append ( ( HTTP_HEADER . COOKIE , candidate ) )
2008-10-15 19:38:22 +04:00
return True
2013-10-17 18:54:53 +04:00
2017-05-08 00:12:42 +03:00
def checkInternet ( ) :
content = Request . getPage ( url = CHECK_INTERNET_ADDRESS , checking = True ) [ 0 ]
2020-05-27 19:39:48 +03:00
return CHECK_INTERNET_VALUE in ( content or " " )
2017-05-08 00:12:42 +03:00
2018-03-21 16:29:54 +03:00
def setVerbosity ( ) : # Cross-referenced function
2013-10-17 18:54:53 +04:00
raise NotImplementedError