2013-02-14 15:32:17 +04:00
#!/usr/bin/env python
2008-10-15 19:38:22 +04:00
"""
2017-01-02 16:19:18 +03:00
Copyright ( c ) 2006 - 2017 sqlmap developers ( http : / / sqlmap . org / )
2010-10-15 03:18:29 +04:00
See the file ' doc/COPYING ' for copying permission
2008-10-15 19:38:22 +04:00
"""
2012-08-22 15:58:52 +04:00
import copy
2011-12-16 03:33:44 +04:00
import httplib
2017-07-26 01:24:13 +03:00
import os
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
2017-07-26 01:24:13 +03:00
import tempfile
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
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
2010-06-02 16:45:40 +04:00
from lib . core . common import getUnicode
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
2011-01-31 15:21:17 +03:00
from lib . core . common import listToStrValue
2017-07-26 01:24:13 +03:00
from lib . core . common import openFile
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
2013-02-21 17:33:12 +04:00
from lib . core . common import urlencode
2013-01-29 23:53:11 +04:00
from lib . core . common import wasLastResponseDBMSError
from lib . core . common import wasLastResponseHTTPError
2015-09-21 14:23:56 +03:00
from lib . core . defaults import defaults
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
2013-02-21 17:33:12 +04:00
from lib . core . decorators import cachedmethod
2013-01-25 15:34:57 +04:00
from lib . core . dicts import FROM_DUMMY_TABLE
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
2017-07-26 01:24:13 +03:00
from lib . core . enums import MKSTEMP_PREFIX
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
2012-12-06 17:14:19 +04:00
from lib . core . exception import SqlmapConnectionException
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
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
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
2016-01-15 00:21:47 +03:00
from lib . core . settings import IDS_WAF_CHECK_PAYLOAD
from lib . core . settings import IDS_WAF_CHECK_RATIO
from lib . core . settings import IDS_WAF_CHECK_TIMEOUT
2016-06-30 15:57:56 +03:00
from lib . core . settings import MAX_DIFFLIB_SEQUENCE_LENGTH
2016-01-15 00:21:47 +03:00
from lib . core . settings import NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH
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
2014-07-20 01:01:59 +04:00
from lib . core . settings import URI_HTTP_HEADER
2010-12-29 22:01:29 +03:00
from lib . core . settings import UPPER_RATIO_BOUND
2011-01-16 13:52:42 +03:00
from lib . core . threads import getCurrentThreadData
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
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
if value . isdigit ( ) :
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
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
if kb . reduceTests is None and not conf . testFilter and ( intersect ( Backend . getErrorParsedDBMSes ( ) , \
SUPPORTED_DBMS , True ) or kb . heuristicDbms or injection . dbms ) :
msg = " it looks like the back-end DBMS is ' %s ' . " % ( Format . getErrorParsedDBMSes ( ) or kb . heuristicDbms or injection . dbms )
msg + = " Do you want to skip test payloads specific for other DBMSes? [Y/n] "
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
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 "
msg + = " for ' %s ' extending provided " % ( Format . getErrorParsedDBMSes ( ) or kb . heuristicDbms or 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 )
if injection . data and match :
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
2011-04-06 18:41:44 +04:00
if conf . tech and isinstance ( conf . tech , list ) and stype not in conf . tech :
2010-12-18 13:42:09 +03:00
debugMsg = " skipping test ' %s ' because the user " % title
debugMsg + = " specified to test only for "
2016-12-20 01:47:39 +03:00
debugMsg + = " %s techniques " % " & " . join ( PAYLOAD . SQLINJECTION [ _ ] for _ in conf . tech )
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
if conf . testFilter and not any ( conf . testFilter in str ( item ) or \
re . search ( conf . testFilter , str ( item ) , re . I ) for item in \
2015-02-27 16:57:28 +03:00
( test . title , test . vector , payloadDbms ) ) :
debugMsg = " skipping test ' %s ' because its " % title
debugMsg + = " name/vector/DBMS is not included by the given filter "
2010-12-18 13:42:09 +03:00
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
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 ) ) :
debugMsg = " skipping test ' %s ' because its " % title
debugMsg + = " name/vector/DBMS is included by the given skip filter "
logger . debug ( debugMsg )
continue
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
2015-02-27 16:57:28 +03:00
if conf . dbms is not None and not intersect ( payloadDbms , conf . dbms , True ) :
2010-12-18 13:42:09 +03:00
debugMsg = " skipping test ' %s ' because " % title
2017-08-28 14:02:08 +03:00
debugMsg + = " it is different than provided "
logger . debug ( debugMsg )
continue
if kb . dbmsFilter is not None and not intersect ( payloadDbms , kb . dbmsFilter , True ) :
debugMsg = " skipping test ' %s ' because " % title
debugMsg + = " it 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)
if injection . dbms is not None and not intersect ( payloadDbms , injection . dbms , True ) :
debugMsg = " skipping test ' %s ' because the identified " % title
debugMsg + = " back-end DBMS is %s " % injection . dbms
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 ) :
debugMsg = " skipping test ' %s ' because the parsed " % title
debugMsg + = " error message(s) showed that the back-end DBMS "
debugMsg + = " could be %s " % Format . getErrorParsedDBMSes ( )
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
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
2014-02-26 14:41:48 +04:00
fstPayload = agent . cleanupPayload ( test . request . payload , origValue = value if place not in ( PLACE . URI , PLACE . CUSTOM_POST , PLACE . CUSTOM_HEADER ) 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
# 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 :
2010-12-18 13:42:09 +03:00
origValue = value
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 ] )
2013-03-01 15:09:03 +04:00
origValue = " %s AND %s = %s " % ( value , _ , _ + 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 )
2015-07-10 01:54:02 +03:00
if reqPayload :
if reqPayload in seenPayload :
continue
else :
seenPayload . add ( reqPayload )
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 ( ) :
2014-02-26 14:41:48 +04:00
check = agent . cleanupPayload ( check , origValue = value if place not in ( PLACE . URI , PLACE . CUSTOM_POST , PLACE . CUSTOM_HEADER ) 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 ( ) :
2014-02-26 14:41:48 +04:00
sndPayload = agent . cleanupPayload ( test . response . comparison , origValue = value if place not in ( PLACE . URI , PLACE . CUSTOM_POST , PLACE . CUSTOM_HEADER ) 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
# Useful to set kb.matchRatio at first based on
# the False response content
kb . matchRatio = None
2012-03-29 18:33:27 +04:00
kb . negativeLogic = ( where == PAYLOAD . WHERE . NEGATIVE )
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
# 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
2015-07-10 02:33:53 +03:00
if trueResult and not ( truePage == falsePage and not kb . nullConnection ) :
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
2016-05-30 17:46:23 +03:00
elif not any ( ( conf . string , conf . notString , conf . regexp , conf . code , kb . nullConnection ) ) :
_ = comparison ( kb . heuristicPage , None , getRatioValue = True )
if _ > kb . matchRatio :
kb . matchRatio = _
logger . debug ( " adjusting match ratio for current parameter to %.3f " % kb . matchRatio )
2016-01-14 15:40:50 +03:00
2016-06-03 16:51:52 +03:00
injectable = True
2017-02-06 15:28:33 +03:00
elif threadData . lastComparisonRatio > UPPER_RATIO_BOUND and not any ( ( conf . string , conf . notString , conf . regexp , conf . code , kb . nullConnection ) ) :
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 " ) )
if originalSet == trueSet != falseSet :
candidates = trueSet - falseSet
if candidates :
candidates = sorted ( candidates , key = lambda _ : len ( _ ) )
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 :
2017-02-06 15:28:33 +03:00
conf . string = candidate
injectable = True
infoMsg = " %s parameter ' %s ' appears to be ' %s ' injectable (with --string= \" %s \" ) " % ( paramType , parameter , title , repr ( conf . string ) . lstrip ( ' u ' ) . strip ( " ' " ) )
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 :
conf . code = trueCode
2016-06-03 16:51:52 +03:00
2016-06-23 18:52:37 +03:00
infoMsg = " %s parameter ' %s ' appears to be ' %s ' injectable (with --code= %d ) " % ( paramType , 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 ) )
trueSet = trueSet . union ( __ 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 ) )
falseSet = falseSet . union ( __ for _ in falseSet for __ in _ . split ( ) )
candidates = filter ( None , ( _ . strip ( ) if _ . strip ( ) in trueRawResponse and _ . strip ( ) not in falseRawResponse else None for _ in ( trueSet - falseSet ) ) )
2016-05-22 22:29:08 +03:00
2016-06-03 16:51:52 +03:00
if candidates :
candidates = sorted ( candidates , key = lambda _ : len ( _ ) )
for candidate in candidates :
if re . match ( r " \ A \ w+ \ Z " , candidate ) :
break
2012-04-11 01:57:00 +04:00
2016-06-23 18:52:37 +03:00
conf . string = candidate
2016-06-03 16:51:52 +03:00
2016-06-23 18:52:37 +03:00
infoMsg = " %s parameter ' %s ' appears to be ' %s ' injectable (with --string= \" %s \" ) " % ( paramType , 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 ) ) :
candidates = filter ( None , ( _ . strip ( ) if _ . strip ( ) in falseRawResponse and _ . strip ( ) not in trueRawResponse else None for _ in ( falseSet - trueSet ) ) )
if candidates :
candidates = sorted ( candidates , key = lambda _ : len ( _ ) )
for candidate in candidates :
if re . match ( r " \ A \ w+ \ Z " , candidate ) :
break
conf . notString = candidate
infoMsg = " %s parameter ' %s ' appears to be ' %s ' injectable (with --not-string= \" %s \" ) " % ( paramType , parameter , title , repr ( conf . notString ) . lstrip ( ' u ' ) . strip ( " ' " ) )
logger . info ( infoMsg )
2016-06-03 16:51:52 +03:00
if not any ( ( conf . string , conf . notString , conf . code ) ) :
infoMsg = " %s parameter ' %s ' appears to be ' %s ' injectable " % ( paramType , 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 )
2011-03-30 22:32:10 +04:00
output = extractRegexResult ( check , page , re . DOTALL | re . IGNORECASE ) \
2017-05-17 01:22:18 +03:00
or extractRegexResult ( check , threadData . lastHTTPError [ 2 ] if wasLastResponseHTTPError ( ) else None , re . DOTALL | re . IGNORECASE ) \
or extractRegexResult ( check , listToStrValue ( [ headers [ key ] for key in headers . keys ( ) if key . lower ( ) != URI_HTTP_HEADER . lower ( ) ] if headers else None ) , re . DOTALL | re . IGNORECASE ) \
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 :
2014-11-21 13:20:54 +03:00
infoMsg = " %s parameter ' %s ' is ' %s ' injectable " % ( paramType , parameter , title )
2011-03-30 22:32:10 +04:00
logger . info ( infoMsg )
injectable = True
2012-12-06 17:14:19 +04:00
except SqlmapConnectionException , msg :
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 "
debugMsg + = " error-based payload used ( ' %s ' ) " % msg
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 :
2016-05-22 22:44:17 +03:00
infoMsg = " %s parameter ' %s ' appears to be ' %s ' injectable " % ( paramType , 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 :
2013-01-25 15:34:57 +04:00
warnMsg = " using unescaped version of the test "
warnMsg + = " because of zero knowledge of the "
warnMsg + = " back-end DBMS. You can try to "
2016-05-30 15:40:22 +03:00
warnMsg + = " explicitly set it with option ' --dbms ' "
2013-01-25 15:34:57 +04:00
singleTimeWarnMessage ( warnMsg )
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 )
2015-07-10 02:19:46 +03:00
elif not injection . data :
_ = test . request . columns . split ( ' - ' ) [ - 1 ]
if _ . isdigit ( ) and int ( _ ) > 10 :
if kb . futileUnion is None :
msg = " it is not recommended to perform "
msg + = " extended UNION tests if there is not "
msg + = " at least one other (potential) "
msg + = " technique found. Do you want to skip? [Y/n] "
2017-04-18 16:48:05 +03:00
kb . futileUnion = not readInput ( msg , default = ' Y ' , boolean = True )
2015-07-10 02:19:46 +03:00
if kb . futileUnion is False :
continue
2012-05-07 17:51:31 +04:00
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
if isinstance ( reqPayload , basestring ) :
2014-11-21 13:20:54 +03:00
infoMsg = " %s parameter ' %s ' is ' %s ' injectable " % ( paramType , 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
2015-07-10 17:10:24 +03:00
if conf . dummy or 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 )
2016-12-20 01:47:39 +03:00
process = subprocess . Popen ( conf . alert , shell = True )
2012-12-11 17:44:43 +04:00
process . wait ( )
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] "
choice = readInput ( msg , default = ' T ' , checkBatch = False ) . upper ( )
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 ) :
2014-08-28 02:31:49 +04:00
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
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
"""
retVal = False
2013-01-25 15:34:57 +04:00
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 ) :
2015-02-20 21:36:34 +03:00
randStr1 , randStr2 = randomStr ( ) , randomStr ( )
2013-02-01 14:24:17 +04:00
Backend . forceDbms ( dbms )
2013-01-25 15:34:57 +04:00
2016-01-14 01:47:34 +03:00
if conf . noEscape and dbms not in FROM_DUMMY_TABLE :
continue
2013-02-01 14:24:17 +04:00
if checkBooleanExpression ( " (SELECT ' %s ' %s )= ' %s ' " % ( randStr1 , FROM_DUMMY_TABLE . get ( dbms , " " ) , randStr1 ) ) :
if not checkBooleanExpression ( " (SELECT ' %s ' %s )= ' %s ' " % ( randStr1 , FROM_DUMMY_TABLE . get ( dbms , " " ) , randStr2 ) ) :
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
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
2015-07-03 09:55:33 +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
2014-02-23 22:40:01 +04:00
for i 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
2015-03-10 11:23:26 +03:00
if randInt3 > randInt2 > randInt1 :
break
2013-06-26 12:55:34 +04:00
if not checkBooleanExpression ( " %d = %d " % ( randInt1 , 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
# Just in case if DBMS hasn't properly recovered from previous delayed request
if PAYLOAD . TECHNIQUE . BOOLEAN not in injection . data :
2013-03-02 01:51:34 +04:00
checkBooleanExpression ( " %d = %d " % ( randInt1 , randInt2 ) )
2013-03-01 13:59:04 +04:00
2016-01-26 09:52:25 +03:00
if checkBooleanExpression ( " %d = %d " % ( randInt1 , 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
2016-01-26 09:52:25 +03:00
elif checkBooleanExpression ( " %d = %d " % ( randInt3 , 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
2016-01-26 09:52:25 +03:00
elif not checkBooleanExpression ( " %d = %d " % ( randInt2 , 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
2016-01-26 09:52:25 +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
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 "
debugMsg + = " constrainting mechanisms "
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 ) ) :
2014-08-20 03:45:42 +04:00
warnMsg = " parameter length constrainting "
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 ( )
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 ) ) :
if not checkBooleanExpression ( " %d > %d " % ( randInt + 1 , randInt ) ) :
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 ) :
2010-11-05 16:14:12 +03:00
if kb . nullConnection :
2015-02-21 15:59:44 +03:00
debugMsg = " heuristic check skipped because NULL connection used "
2010-11-05 16:14:12 +03:00
logger . debug ( debugMsg )
2012-03-05 13:42:52 +04:00
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
2014-11-21 13:20:54 +03:00
infoMsg = " heuristic (basic) test shows that %s parameter " % paramType
infoMsg + = " ' %s ' might " % 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
2012-08-22 17:51:47 +04:00
if not casting and not result and kb . dynamicParameter and origValue . isdigit ( ) :
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
2012-08-22 13:27:58 +04:00
if casting :
2012-08-22 17:53:40 +04:00
errMsg = " possible %s casting " % ( " integer " if origValue . isdigit ( ) else " type " )
2013-07-08 13:52:46 +04:00
errMsg + = " detected (e.g. \" $ %s =intval($_REQUEST[ ' %s ' ]) \" ) " % ( parameter , parameter )
2012-08-22 13:27:58 +04:00
errMsg + = " at the back-end web application "
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
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
2016-01-15 00:21:47 +03:00
if value . lower ( ) in ( page or " " ) . lower ( ) :
2014-11-21 13:20:54 +03:00
infoMsg = " heuristic (XSS) test shows that %s parameter " % paramType
2016-01-14 11:59:13 +03:00
infoMsg + = " ' %s ' might be vulnerable to cross-site scripting attacks " % parameter
logger . info ( infoMsg )
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 ( ) :
infoMsg = " heuristic (FI) test shows that %s parameter " % paramType
infoMsg + = " ' %s ' might be vulnerable to file inclusion attacks " % parameter
logger . info ( infoMsg )
break
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 .
"""
2012-03-15 23:47:59 +04:00
if kb . redirectChoice :
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
infoMsg = " testing if %s parameter ' %s ' is dynamic " % ( paramType , 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 )
2008-10-15 19:38:22 +04:00
2012-01-14 00:56:06 +04:00
if not dynResult :
2014-11-21 13:20:54 +03:00
infoMsg = " confirming that %s parameter ' %s ' is dynamic " % ( paramType , parameter )
2012-01-14 00:56:06 +04:00
logger . info ( infoMsg )
2008-10-15 19:38:22 +04:00
2012-01-14 00:56:06 +04:00
randInt = randomInt ( )
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 :
2013-04-09 13:48:42 +04:00
warnMsg = " target URL is 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
2013-04-09 13:48:42 +04:00
warnMsg = " target URL is heavily dynamic "
2012-10-04 20:28:36 +04:00
warnMsg + = " . sqlmap is going to retry the request "
2010-12-29 22:39:32 +03:00
logger . critical ( warnMsg )
2010-10-25 23:45:53 +04: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 ) .
"""
2015-07-23 10:55:59 +03:00
infoMsg = " testing if the target URL 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
delay = 1 - ( time . time ( ) - ( kb . originalPageTime or 0 ) )
delay = max ( 0 , min ( 1 , delay ) )
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
2012-03-18 21:27:08 +04:00
if kb . redirectChoice :
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 :
2013-04-09 13:48:42 +04:00
infoMsg = " target URL 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 :
2013-04-09 13:48:42 +04:00
warnMsg = " target URL is not stable. 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 "
warnMsg + = " ' Page comparison ' and provide a string or regular "
warnMsg + = " expression to match on "
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 ) :
2011-01-19 02:03:50 +03:00
warnMsg = " you provided ' %s ' as the regular expression to " % conf . regexp
2010-11-18 01:00:09 +03:00
warnMsg + = " match, but such a regular expression does not have any "
2011-08-12 19:33:37 +04:00
warnMsg + = " match within the target URL raw response, sqlmap "
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
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
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 "
warnMsg + = " is protected by some kind of WAF/IPS/IDS "
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 "
infoMsg + = " some kind of WAF/IPS/IDS "
logger . info ( infoMsg )
2011-07-06 09:44:47 +04:00
retVal = False
2013-07-08 14:44:14 +04:00
payload = " %d %s " % ( randomInt ( ) , IDS_WAF_CHECK_PAYLOAD )
2015-01-31 00:12:35 +03:00
value = " " if not conf . parameters . get ( PLACE . GET ) else conf . parameters [ PLACE . GET ] + DEFAULT_GET_POST_DELIMITER
value + = agent . addPayloadDelimiters ( " %s = %s " % ( randomStr ( ) , payload ) )
2011-07-06 09:44:47 +04:00
2015-09-21 14:23:56 +03:00
pushValue ( conf . timeout )
conf . timeout = IDS_WAF_CHECK_TIMEOUT
2015-01-06 16:01:47 +03:00
try :
2015-01-31 00:12:35 +03:00
retVal = Request . queryPage ( place = PLACE . GET , value = value , getRatioValue = True , noteResponseTime = False , silent = True ) [ 1 ] < IDS_WAF_CHECK_RATIO
2015-01-06 16:01:47 +03:00
except SqlmapConnectionException :
retVal = True
finally :
kb . matchRatio = None
2015-09-21 14:23:56 +03:00
conf . timeout = popValue ( )
2011-07-06 09:44:47 +04:00
if retVal :
2015-01-22 10:55:37 +03:00
warnMsg = " heuristics detected that the target "
warnMsg + = " is protected by some kind of WAF/IPS/IDS "
2015-01-06 16:01:47 +03:00
logger . critical ( warnMsg )
2015-01-20 11:38:18 +03:00
if not conf . identifyWaf :
message = " do you want sqlmap to try to detect backend "
message + = " WAF/IPS/IDS? [y/N] "
2017-04-19 15:46:27 +03:00
if readInput ( message , default = ' N ' , boolean = True ) :
2015-01-20 11:38:18 +03:00
conf . identifyWaf = True
2011-07-06 09:44:47 +04:00
2015-09-21 14:23:56 +03:00
if conf . timeout == defaults . timeout :
2015-09-21 15:46:34 +03:00
logger . warning ( " dropping timeout to %d seconds (i.e. ' --timeout= %d ' ) " % ( IDS_WAF_CHECK_TIMEOUT , IDS_WAF_CHECK_TIMEOUT ) )
conf . timeout = IDS_WAF_CHECK_TIMEOUT
2015-09-21 14:23:56 +03:00
2016-01-09 01:23:41 +03:00
hashDBWrite ( HASHDB_KEYS . CHECK_WAF_RESULT , retVal , True )
2011-07-06 09:44:47 +04:00
return retVal
2013-02-21 14:14:57 +04:00
def identifyWaf ( ) :
if not conf . identifyWaf :
return None
2016-05-27 14:41:03 +03:00
if not kb . wafFunctions :
setWafFunctions ( )
2013-02-26 14:08:06 +04:00
kb . testMode = True
2013-02-21 14:14:57 +04:00
infoMsg = " using WAF scripts to detect "
infoMsg + = " backend WAF/IPS/IDS protection "
logger . info ( infoMsg )
2013-02-21 17:33:12 +04:00
@cachedmethod
def _ ( * args , * * kwargs ) :
2013-03-19 22:06:51 +04:00
page , headers , code = None , None , None
2013-02-21 17:33:12 +04:00
try :
2014-12-04 12:06:15 +03:00
pushValue ( kb . redirectChoice )
kb . redirectChoice = REDIRECTION . NO
2013-02-21 17:33:12 +04:00
if kwargs . get ( " get " ) :
kwargs [ " get " ] = urlencode ( kwargs [ " get " ] )
kwargs [ " raise404 " ] = False
2013-03-19 22:24:14 +04:00
kwargs [ " silent " ] = True
2013-03-19 22:06:51 +04:00
page , headers , code = Request . getPage ( * args , * * kwargs )
except Exception :
pass
2014-12-04 12:06:15 +03:00
finally :
kb . redirectChoice = popValue ( )
2013-03-19 22:06:51 +04:00
return page or " " , headers or { } , code
2013-02-21 17:33:12 +04:00
2016-09-27 14:26:11 +03:00
retVal = [ ]
2013-02-21 14:14:57 +04:00
2013-02-21 17:39:22 +04:00
for function , product in kb . wafFunctions :
try :
2016-10-11 01:35:39 +03:00
logger . debug ( " checking for WAF/IPS/IDS product ' %s ' " % product )
2013-02-21 17:33:12 +04:00
found = function ( _ )
2013-02-21 17:39:22 +04:00
except Exception , ex :
2013-07-31 11:22:45 +04:00
errMsg = " exception occurred while running "
2016-01-12 12:27:04 +03:00
errMsg + = " WAF script for ' %s ' ( ' %s ' ) " % ( product , getSafeExString ( ex ) )
2013-02-21 17:39:22 +04:00
logger . critical ( errMsg )
found = False
2013-02-21 17:33:12 +04:00
2013-02-21 14:14:57 +04:00
if found :
2016-10-11 01:35:39 +03:00
errMsg = " WAF/IPS/IDS identified as ' %s ' " % product
2016-09-27 14:26:11 +03:00
logger . critical ( errMsg )
2013-02-21 14:14:57 +04:00
2016-09-27 14:26:11 +03:00
retVal . append ( product )
2013-05-18 20:26:40 +04:00
2016-09-27 14:26:11 +03:00
if retVal :
2017-07-26 01:24:13 +03:00
if kb . wafSpecificResponse and len ( retVal ) == 1 and " unknown " in retVal [ 0 ] . lower ( ) :
handle , filename = tempfile . mkstemp ( prefix = MKSTEMP_PREFIX . SPECIFIC_RESPONSE )
os . close ( handle )
with openFile ( filename , " w+b " ) as f :
f . write ( kb . wafSpecificResponse )
message = " WAF/IPS/IDS specific response can be found in ' %s ' . " % filename
message + = " If you know the details on used protection please "
message + = " report it along with specific response "
message + = " to ' dev@sqlmap.org ' "
logger . warn ( message )
2013-05-18 20:28:44 +04:00
message = " are you sure that you want to "
message + = " continue with further target testing? [y/N] "
2017-04-18 16:48:05 +03:00
choice = readInput ( message , default = ' N ' , boolean = True )
2013-05-18 20:26:40 +04:00
2016-09-27 14:26:11 +03:00
if not conf . tamper :
warnMsg = " please consider usage of tamper scripts (option ' --tamper ' ) "
singleTimeWarnMessage ( warnMsg )
2017-04-18 16:48:05 +03:00
if not choice :
2013-05-18 20:26:40 +04:00
raise SqlmapUserQuitException
2013-02-21 14:14:57 +04:00
else :
2016-10-11 01:35:39 +03:00
warnMsg = " WAF/IPS/IDS product hasn ' t been identified "
2015-01-20 11:38:18 +03:00
logger . warn ( warnMsg )
2013-02-21 14:14:57 +04:00
2014-09-08 16:33:13 +04:00
kb . testType = None
2013-02-26 14:08:06 +04:00
kb . testMode = False
2013-02-21 14:14:57 +04:00
return retVal
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
2013-04-09 13:48:42 +04:00
infoMsg = " testing NULL connection to the target URL "
2010-09-16 12:43:10 +04:00
logger . info ( infoMsg )
try :
2015-07-18 18:01:34 +03:00
pushValue ( kb . pageCompress )
kb . pageCompress = False
2011-08-12 20:48:11 +04:00
page , headers , _ = Request . getPage ( method = HTTPMETHOD . HEAD )
2010-12-06 18:50:19 +03:00
2013-03-20 14:10:24 +04:00
if not page and HTTP_HEADER . CONTENT_LENGTH in ( headers or { } ) :
2010-11-08 12:49:57 +03:00
kb . nullConnection = NULLCONNECTION . HEAD
2010-10-15 14:24:54 +04:00
2016-09-09 12:37:16 +03:00
infoMsg = " NULL connection is supported with HEAD method (Content-Length) "
2010-10-15 14:24:54 +04:00
logger . info ( infoMsg )
2010-09-16 12:43:10 +04:00
else :
2013-03-20 14:10:24 +04:00
page , headers , _ = Request . getPage ( auxHeaders = { HTTP_HEADER . RANGE : " bytes=-1 " } )
2010-12-06 18:50:19 +03:00
2013-03-20 14:10:24 +04:00
if page and len ( page ) == 1 and HTTP_HEADER . CONTENT_RANGE in ( headers or { } ) :
2010-11-08 12:49:57 +03:00
kb . nullConnection = NULLCONNECTION . RANGE
2010-09-16 12:43:10 +04:00
2016-09-09 12:37:16 +03:00
infoMsg = " NULL connection is supported with GET method (Range) "
2010-10-15 14:24:54 +04:00
infoMsg + = " ' %s ' " % kb . nullConnection
logger . info ( infoMsg )
2013-05-17 17:04:25 +04:00
else :
_ , headers , _ = Request . getPage ( skipRead = True )
if HTTP_HEADER . CONTENT_LENGTH in ( headers or { } ) :
kb . nullConnection = NULLCONNECTION . SKIP_READ
infoMsg = " NULL connection is supported with ' skip-read ' method "
logger . info ( infoMsg )
2010-12-06 18:50:19 +03:00
2015-09-08 12:15:31 +03:00
except SqlmapConnectionException , ex :
2015-09-10 16:51:33 +03:00
errMsg = getSafeExString ( ex )
2013-01-04 02:20:55 +04:00
raise SqlmapConnectionException ( errMsg )
2010-09-16 12:43:10 +04:00
2015-07-18 18:01:34 +03:00
finally :
kb . pageCompress = popValue ( )
2013-05-17 18:04:05 +04:00
2010-09-16 12:43:10 +04:00
return kb . nullConnection is not None
2010-11-15 15:19:22 +03:00
def checkConnection ( suppressOutput = False ) :
2015-07-10 17:10:24 +03:00
if not any ( ( conf . proxy , conf . tor , conf . dummy , conf . offline ) ) :
2011-06-24 21:19:24 +04:00
try :
2014-12-11 15:29:26 +03:00
debugMsg = " resolving hostname ' %s ' " % conf . hostname
logger . debug ( debugMsg )
2011-06-24 21:19:24 +04:00
socket . getaddrinfo ( conf . hostname , None )
except socket . gaierror :
errMsg = " host ' %s ' does not exist " % conf . hostname
2013-07-31 11:22:45 +04:00
raise SqlmapConnectionException ( errMsg )
except socket . error , ex :
errMsg = " problem occurred while "
2015-09-10 16:51:33 +03:00
errMsg + = " resolving a host name ' %s ' ( ' %s ' ) " % ( conf . hostname , getSafeExString ( ex ) )
2013-01-04 02:20:55 +04:00
raise SqlmapConnectionException ( 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 ( )
2017-06-05 17:28:19 +03:00
page , headers , _ = Request . queryPage ( content = True , noteResponseTime = False )
2010-12-06 21:20:57 +03:00
kb . originalPage = kb . pageTemplate = page
2011-01-01 23:19:55 +03:00
kb . errorIsNone = False
2011-01-12 01:18:47 +03:00
2013-01-29 23:53:11 +04:00
if not kb . originalPage and wasLastResponseHTTPError ( ) :
2011-01-26 01:26:28 +03:00
errMsg = " unable to retrieve page content "
2013-01-04 02:20:55 +04:00
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 ( ) :
2017-08-23 14:17:37 +03:00
if getLastRequestHTTPError ( ) != conf . ignoreCode :
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
2015-09-08 12:15:31 +03:00
except SqlmapConnectionException , 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 )
2011-12-16 03:33:44 +04:00
if any ( code in kb . httpErrorCodes for code in ( httplib . 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
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 ]
return CHECK_INTERNET_VALUE in ( content or " " )
2013-10-17 18:54:53 +04:00
def setVerbosity ( ) : # Cross-linked function
raise NotImplementedError
2016-05-27 14:41:03 +03:00
def setWafFunctions ( ) : # Cross-linked function
raise NotImplementedError