2013-02-14 15:32:17 +04:00
#!/usr/bin/env python
2008-10-15 19:38:22 +04:00
"""
2014-01-13 21:24:49 +04:00
Copyright ( c ) 2006 - 2014 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
2008-12-12 22:06:31 +03:00
import re
2010-05-21 17:36:49 +04:00
import socket
2008-10-15 19:38:22 +04:00
import time
2012-12-11 15:48:58 +04:00
from subprocess import Popen as execute
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-02-14 00:20:21 +03:00
from lib . core . common import arrayizeValue
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
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
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
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
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
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
2013-07-08 14:44:14 +04:00
from lib . core . enums import CUSTOM_LOGGING
2013-01-25 15:34:57 +04:00
from lib . core . enums import DBMS
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
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
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
from lib . core . exception import SqlmapUserQuitException
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
2013-01-16 05:31:03 +04:00
from lib . core . settings import SUHOSIN_MAX_VALUE_LENGTH
2013-01-25 15:34:57 +04:00
from lib . core . settings import UNKNOWN_DBMS
2011-01-21 21:32:10 +03:00
from lib . core . settings import LOWER_RATIO_BOUND
2010-12-29 22:01:29 +03:00
from lib . core . settings import UPPER_RATIO_BOUND
2011-07-06 09:44:47 +04:00
from lib . core . settings import IDS_WAF_CHECK_PAYLOAD
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
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 ( )
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
2011-01-20 02:06:15 +03:00
for test in getSortedInjectionTests ( ) :
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 :
if not injection . dbms and PAYLOAD . TECHNIQUE . BOOLEAN in injection . data :
if not Backend . getIdentifiedDbms ( ) and not kb . heuristicDbms :
kb . heuristicDbms = heuristicCheckDbms ( injection ) or UNKNOWN_DBMS
if not conf . testFilter and ( Backend . getErrorParsedDBMSes ( ) or kb . heuristicDbms ) not in ( [ ] , None , UNKNOWN_DBMS ) :
if kb . reduceTests is None and Backend . getErrorParsedDBMSes ( ) :
msg = " heuristic (parsing) test showed that the "
msg + = " back-end DBMS could be ' %s ' . " % ( Format . getErrorParsedDBMSes ( ) if Backend . getErrorParsedDBMSes ( ) else kb . heuristicDbms )
msg + = " Do you want to skip test payloads specific for other DBMSes? [Y/n] "
kb . reduceTests = [ ] if readInput ( msg , default = ' Y ' ) . upper ( ) != ' Y ' else ( Backend . getErrorParsedDBMSes ( ) or [ kb . heuristicDbms ] )
if kb . extendTests is None :
_ = ( Format . getErrorParsedDBMSes ( ) if Backend . getErrorParsedDBMSes ( ) else kb . heuristicDbms )
msg = " do you want to include all tests for ' %s ' " % _
2013-03-26 17:08:35 +04:00
msg + = " extending provided level ( %d ) and risk ( %s )? [Y/n] " % ( conf . level , conf . risk )
2013-02-01 20:24:04 +04:00
kb . extendTests = [ ] if readInput ( msg , default = ' Y ' ) . upper ( ) != ' Y ' else ( Backend . getErrorParsedDBMSes ( ) or [ kb . heuristicDbms ] )
2010-12-18 13:42:09 +03:00
title = test . title
stype = test . stype
clause = test . clause
2012-05-07 17:51:31 +04:00
unionExtended = False
2010-12-18 13:42:09 +03:00
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 :
2012-05-07 17:51:31 +04:00
unionExtended = True
2012-04-23 17:41:36 +04:00
test . request . columns = re . sub ( r " \ b %d \ b " % _ , str ( 2 * _ ) , test . request . columns )
title = re . sub ( r " \ b %d \ b " % _ , str ( 2 * _ ) , title )
test . title = re . sub ( r " \ b %d \ b " % _ , str ( 2 * _ ) , test . title )
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 "
2011-05-03 01:48:08 +04:00
debugMsg + = " %s techniques " % " & " . join ( map ( lambda x : PAYLOAD . SQLINJECTION [ x ] , 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
2013-02-01 20:24:04 +04:00
# Skip DBMS-specific test if it does not match either the
# previously identified or the user's provided DBMS (either
# from program switch or from parsed error message(s))
if " details " in test and " dbms " in test . details :
dbms = test . details . dbms
else :
dbms = None
2011-09-27 18:09:25 +04:00
# Skip tests if title is not included by the given filter
2012-07-24 17:43:29 +04:00
if conf . testFilter :
2013-10-27 02:24:57 +04:00
if not any ( conf . testFilter in str ( item ) or re . search ( conf . testFilter , str ( item ) , re . I ) for item in ( test . title , test . vector , dbms ) ) :
2011-09-27 18:31:58 +04:00
debugMsg = " skipping test ' %s ' because " % title
2012-03-14 02:03:23 +04:00
debugMsg + = " its name/vector/dbms is not included by the given filter "
2011-09-27 18:31:58 +04:00
logger . debug ( debugMsg )
continue
2013-02-01 20:24:04 +04:00
2013-02-05 13:58:02 +04:00
elif not ( kb . extendTests and intersect ( dbms , kb . extendTests ) ) :
2011-09-27 18:31:58 +04:00
# Skip test if the risk is higher than the provided (or default)
# value
# Parse test's <risk>
if test . risk > conf . risk :
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
# Parse test's <level>
if test . level > conf . level :
debugMsg = " skipping test ' %s ' because the level ( %d ) " % ( title , test . level )
debugMsg + = " is higher than the provided ( %d ) " % conf . level
logger . debug ( debugMsg )
continue
2011-09-27 18:09:25 +04:00
2010-12-18 13:42:09 +03:00
if dbms is not None :
2011-02-14 00:20:21 +03:00
if injection . dbms is not None and not intersect ( injection . dbms , dbms ) :
2010-12-18 13:42:09 +03:00
debugMsg = " skipping test ' %s ' because " % title
debugMsg + = " the back-end DBMS identified is "
debugMsg + = " %s " % injection . dbms
logger . debug ( debugMsg )
continue
2010-11-28 21:10:54 +03:00
2013-10-07 14:54:19 +04:00
if conf . dbms is not None and not intersect ( conf . dbms . lower ( ) , [ _ . lower ( ) for _ in arrayizeValue ( dbms ) ] ) :
2010-12-18 13:42:09 +03:00
debugMsg = " skipping test ' %s ' because " % title
debugMsg + = " the provided DBMS is %s " % conf . dbms
logger . debug ( debugMsg )
continue
2013-02-01 20:24:04 +04:00
if kb . reduceTests and not intersect ( dbms , kb . reduceTests ) :
2011-01-02 02:38:11 +03:00
debugMsg = " skipping test ' %s ' because " % title
2011-01-02 10:09:04 +03:00
debugMsg + = " the parsed error message(s) showed "
debugMsg + = " that the back-end DBMS could be "
2011-01-28 19:36:09 +03:00
debugMsg + = " %s " % Format . getErrorParsedDBMSes ( )
2011-01-02 02:38:11 +03:00
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
debugMsg + = " differs from the clause already identified "
logger . debug ( debugMsg )
2010-11-28 21:10:54 +03:00
continue
2011-05-10 19:34:54 +04:00
# Skip test if the user provided custom character
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
2011-02-07 02:27:56 +03:00
# Force back-end DBMS according to the current
# test value for proper payload unescaping
2011-02-14 00:20:21 +03:00
Backend . forceDbms ( dbms [ 0 ] if isinstance ( dbms , list ) else dbms )
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
# Favoring non-string specific boundaries in case of digit-like parameter values
if value . isdigit ( ) :
boundaries = sorted ( copy . deepcopy ( conf . boundaries ) , key = lambda x : any ( _ in ( x . prefix or " " ) or _ in ( x . suffix or " " ) for _ in ( ' " ' , ' \' ' ) ) )
else :
boundaries = conf . boundaries
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>
if boundary . level > conf . level :
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 " "
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
ptype = boundary . ptype
# 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
if condBound or condType :
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
2013-07-15 18:24:49 +04:00
kb . data . setdefault ( " randomInt " , str ( randomInt ( 10 ) ) )
2014-01-24 00:56:06 +04:00
kb . data . setdefault ( " randomStr " , str ( randomStr ( 10 ) ) )
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 ]
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
2011-01-12 01:18:47 +03:00
boundPayload = agent . prefixQuery ( fstPayload , prefix , where , clause )
2011-01-24 15:25:45 +03:00
boundPayload = agent . suffixQuery ( boundPayload , comment , suffix , where )
2011-01-12 01:18:47 +03:00
reqPayload = agent . payload ( place , parameter , newValue = boundPayload , where = where )
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 )
2013-01-18 19:49:35 +04:00
falsePage = threadData . lastComparisonPage or " "
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 )
2013-01-18 19:49:35 +04:00
truePage = threadData . lastComparisonPage or " "
2010-11-28 21:10:54 +03:00
2010-12-18 13:42:09 +03:00
if trueResult :
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
# Perform the test's False request
if not falseResult :
2014-02-09 20:50:16 +04:00
infoMsg = " %s parameter ' %s ' seems to be ' %s ' injectable " % ( place , parameter , title )
2010-12-18 13:42:09 +03:00
logger . info ( infoMsg )
2010-11-28 21:10:54 +03:00
2010-12-18 13:42:09 +03:00
injectable = True
2012-04-11 01:57:00 +04:00
2012-07-26 14:06:02 +04:00
if not injectable and not any ( ( conf . string , conf . notString , conf . regexp ) ) and kb . pageStable :
2013-01-18 19:49:35 +04:00
trueSet = set ( extractTextTagContent ( truePage ) )
falseSet = set ( extractTextTagContent ( falsePage ) )
2013-01-18 20:00:11 +04:00
candidates = filter ( None , ( _ . strip ( ) if _ . strip ( ) in ( kb . pageTemplate or " " ) and _ . strip ( ) not in falsePage and _ . strip ( ) not in threadData . lastComparisonHeaders else None for _ in ( trueSet - falseSet ) ) )
2012-04-13 14:54:30 +04:00
if candidates :
2013-01-18 19:35:09 +04:00
conf . string = candidates [ 0 ]
2012-07-31 13:32:53 +04:00
infoMsg = " %s parameter ' %s ' seems to be ' %s ' injectable (with --string= \" %s \" ) " % ( place , parameter , title , repr ( conf . string ) . lstrip ( ' u ' ) . strip ( " ' " ) )
2012-04-11 01:48:34 +04:00
logger . info ( infoMsg )
2012-04-11 01:57:00 +04:00
2012-04-11 01:48:34 +04:00
injectable = True
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 :
page , headers = Request . queryPage ( reqPayload , place , content = True , raise404 = False )
output = extractRegexResult ( check , page , re . DOTALL | re . IGNORECASE ) \
or extractRegexResult ( check , listToStrValue ( headers . headers \
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 )
if output :
result = output == " 1 "
if result :
infoMsg = " %s parameter ' %s ' is ' %s ' injectable " % ( place , parameter , title )
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 )
2010-12-18 13:42:09 +03:00
if trueResult :
# 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 :
2014-02-09 20:50:16 +04:00
infoMsg = " %s parameter ' %s ' seems to be ' %s ' injectable " % ( place , 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 )
2011-04-20 03:04:10 +04:00
if not Backend . getIdentifiedDbms ( ) :
2013-02-01 14:24:17 +04:00
if kb . heuristicDbms in ( None , UNKNOWN_DBMS ) :
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 "
warnMsg + = " explicitly set it using option ' --dbms ' "
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 :
infoMsg = " automatically extending ranges "
infoMsg + = " for UNION 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
if isinstance ( reqPayload , basestring ) :
infoMsg = " %s parameter ' %s ' is ' %s ' injectable " % ( place , parameter , title )
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
2013-10-11 01:08:20 +04:00
if conf . dummy :
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 " ) :
for dKey , dValue in test . details . items ( ) :
2011-06-02 02:47:54 +04:00
if dKey == " dbms " :
2012-10-28 03:11:50 +04:00
injection . dbms = dValue
2011-06-02 02:47:54 +04:00
if not isinstance ( dValue , list ) :
2012-10-28 03:11:50 +04:00
Backend . setDbms ( dValue )
2011-06-02 02:47:54 +04:00
else :
2011-06-02 03:00:18 +04:00
Backend . forceDbms ( dValue [ 0 ] , True )
2012-07-24 17:43:29 +04:00
elif dKey == " dbms_version " and injection . dbms_version is None and not conf . testFilter :
2011-02-06 18:20:44 +03:00
injection . dbms_version = Backend . setVersion ( dValue )
elif dKey == " os " and injection . os is None :
injection . os = Backend . setOs ( dValue )
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
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
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 )
process = execute ( conf . alert , shell = True )
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 )
2013-10-17 18:54:53 +04:00
msg = " how do you want to proceed? [(S)kip current test/(e)nd detection phase/(n)ext parameter/(c)hange verbosity/(q)uit] "
2013-02-01 20:24:04 +04:00
choice = readInput ( msg , default = " S " , checkBatch = False )
2011-06-27 18:14:49 +04:00
if choice [ 0 ] in ( " s " , " S " ) :
pass
2013-10-17 18:54:53 +04:00
elif choice [ 0 ] in ( " c " , " C " ) :
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] "
choice = readInput ( msg , default = str ( conf . verbose ) , checkBatch = False ) . strip ( )
conf . verbose = int ( choice )
setVerbosity ( )
2011-06-27 18:14:49 +04:00
elif choice [ 0 ] in ( " n " , " N " ) :
return None
elif choice [ 0 ] in ( " e " , " E " ) :
2011-06-08 18:44:11 +04:00
kb . endDetection = True
2011-06-27 18:14:49 +04:00
elif choice [ 0 ] in ( " q " , " 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 ' ) :
2011-06-08 18:40:42 +04:00
warnMsg = " in OR boolean-based injections, 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 )
2011-04-22 16:24:16 +04:00
injection = checkFalsePositives ( injection )
2010-11-29 00:27:47 +03:00
else :
2012-10-25 15:21:32 +04:00
injection = None
if injection :
2013-01-16 05:31:03 +04:00
checkSuhosinPatch ( 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 ) :
retVal = None
2013-02-01 14:24:17 +04:00
pushValue ( kb . injection )
kb . injection = injection
randStr1 , randStr2 = randomStr ( ) , randomStr ( )
2013-01-25 15:34:57 +04:00
2013-02-01 14:24:17 +04:00
for dbms in getPublicTypeMembers ( DBMS , True ) :
Backend . forceDbms ( dbms )
2013-01-25 15:34:57 +04:00
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 :
2013-02-01 20:24:04 +04: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 )
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
"""
retVal = injection
2011-10-10 21:29:54 +04:00
if len ( injection . data ) == 1 and any ( map ( lambda x : x in injection . data , [ PAYLOAD . TECHNIQUE . BOOLEAN , PAYLOAD . TECHNIQUE . TIME , PAYLOAD . TECHNIQUE . STACKED ] ) ) \
2013-01-16 05:31:03 +04:00
or len ( injection . data ) == 2 and all ( map ( lambda x : x in injection . data , [ PAYLOAD . TECHNIQUE . TIME , PAYLOAD . TECHNIQUE . STACKED ] ) ) :
# or len(injection.data) == 1 and 'Generic' in injection.data.values()[0].title and not Backend.getIdentifiedDbms():
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
2011-06-08 18:40:42 +04:00
# Simple arithmetic operations which should show basic
2011-05-27 00:48:18 +04:00
# arithmetic ability of the backend if it's really injectable
2014-02-23 22:40:01 +04:00
for i in xrange ( conf . level ) :
2012-10-16 12:24:05 +04:00
randInt1 , randInt2 , randInt3 = ( _ ( ) for j in xrange ( 3 ) )
2013-06-26 12:55:34 +04:00
randInt1 = min ( randInt1 , randInt2 , randInt3 )
randInt3 = max ( randInt1 , randInt2 , randInt3 )
while randInt1 > = randInt2 :
2012-10-16 12:24:05 +04:00
randInt2 = _ ( )
2013-06-26 12:55:34 +04:00
while randInt2 > = randInt3 :
randInt3 = _ ( )
if not checkBooleanExpression ( " %d = %d " % ( randInt1 , randInt1 ) ) :
2012-10-16 12:24:05 +04:00
retVal = None
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
2013-06-26 12:55:34 +04:00
if checkBooleanExpression ( " %d > %d " % ( randInt1 , randInt2 ) ) :
2012-10-16 12:24:05 +04:00
retVal = None
break
2013-06-26 12:55:34 +04:00
elif checkBooleanExpression ( " %d > %d " % ( randInt2 , randInt3 ) ) :
2012-10-16 12:24:05 +04:00
retVal = None
break
2013-06-26 12:55:34 +04:00
elif not checkBooleanExpression ( " %d > %d " % ( randInt3 , randInt1 ) ) :
2012-10-16 12:24:05 +04:00
retVal = None
break
2011-04-22 16:24:16 +04:00
if retVal is None :
2012-03-09 18:21:41 +04:00
warnMsg = " false positive or unexploitable injection point detected "
2011-04-22 16:24:16 +04:00
logger . warn ( warnMsg )
2013-02-22 14:12:41 +04:00
if PAYLOAD . TECHNIQUE . BOOLEAN in injection . data :
if all ( _ . __name__ != " between " for _ in kb . tamperFunctions ) :
warnMsg = " there is a possibility that the character ' > ' is "
warnMsg + = " filtered by the back-end server. You can try "
warnMsg + = " to rerun with ' --tamper=between ' "
logger . warn ( warnMsg )
2011-04-22 16:24:16 +04:00
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 :
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 ) ) :
2012-10-25 15:21:32 +04:00
warnMsg = " parameter length constraint "
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 ( )
2011-01-15 16:15:10 +03:00
def heuristicCheckSqlInjection ( place , parameter ) :
2010-11-05 16:14:12 +03:00
if kb . nullConnection :
2013-07-08 14:38:36 +04:00
debugMsg = " heuristic check skipped "
2010-11-05 16:14:12 +03:00
debugMsg + = " because NULL connection used "
logger . debug ( debugMsg )
2012-03-05 13:42:52 +04:00
return None
2013-01-29 23:53:11 +04:00
if wasLastResponseDBMSError ( ) :
2013-07-08 14:38:36 +04:00
debugMsg = " heuristic check skipped "
2012-03-05 13:42:52 +04:00
debugMsg + = " because original page content "
debugMsg + = " contains DBMS error "
logger . debug ( debugMsg )
return None
2010-11-05 16:14:12 +03:00
2012-08-22 17:51:47 +04:00
origValue = conf . paramDict [ place ] [ parameter ]
2010-10-11 16:26:35 +04:00
prefix = " "
2010-11-18 01:00:09 +03:00
suffix = " "
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
2012-10-28 03:42:08 +04:00
randStr = " "
while ' \' ' not in randStr :
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 )
2011-11-22 12:39:13 +04:00
page , _ = Request . queryPage ( payload , place , content = True , raise404 = False )
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
2013-03-26 17:18:37 +04:00
infoMsg = " heuristic (basic) test shows that %s " % place
2010-11-16 13:52:49 +03:00
infoMsg + = " parameter ' %s ' might " % parameter
2010-10-16 19:10:48 +04:00
2012-08-22 17:51:47 +04:00
def _ ( page ) :
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 ( )
payload = " %s %s %s " % ( prefix , " %s %s " % ( origValue , randStr ) , suffix )
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] " )
2012-08-22 18:06:09 +04:00
kb . ignoreCasted = readInput ( message , default = ' Y ' if conf . multipleTargets else ' N ' ) . upper ( ) != ' N '
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 )
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
2008-12-09 00:24:24 +03:00
infoMsg = " testing if %s parameter ' %s ' is dynamic " % ( place , parameter )
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 :
infoMsg = " confirming that %s parameter ' %s ' is dynamic " % ( place , parameter )
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
2011-01-16 13:52:42 +03:00
seqMatcher = getCurrentThreadData ( ) . seqMatcher
seqMatcher . set_seq1 ( firstPage )
seqMatcher . set_seq2 ( secondPage )
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
2011-01-16 13:52:42 +03:00
if seqMatcher . quick_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
2010-12-29 22:39:32 +03:00
secondPage , _ = Request . queryPage ( content = True )
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 ) .
"""
2013-04-09 13:48:42 +04:00
infoMsg = " testing if the target URL is stable. This can take a couple of seconds "
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()
2008-12-21 19:35:03 +03:00
time . sleep ( 1 )
2011-11-29 20:59:06 +04:00
secondPage , _ = Request . queryPage ( content = True , 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] "
2012-08-20 13:40:49 +04:00
test = readInput ( message , default = " C " )
2010-10-16 19:10:48 +04:00
2010-10-12 19:49:04 +04:00
if test and test [ 0 ] in ( " q " , " Q " ) :
2012-12-06 17:14:19 +04:00
raise SqlmapUserQuitException
2010-10-16 19:10:48 +04:00
2010-10-12 19:49:04 +04:00
elif test and test [ 0 ] in ( " s " , " S " ) :
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 ' : "
test = readInput ( message )
2010-10-16 19:10:48 +04:00
2010-10-12 19:49:04 +04:00
if test :
conf . string = test
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
2010-10-12 19:49:04 +04:00
elif test and test [ 0 ] in ( " r " , " R " ) :
message = " please enter value for parameter ' regex ' : "
test = readInput ( message )
2010-10-16 19:10:48 +04:00
2010-10-12 19:49:04 +04:00
if test :
conf . regex = test
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
2011-08-12 19:33:37 +04:00
page , headers = Request . queryPage ( content = True )
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 )
2011-08-12 19:33:37 +04:00
page , headers = Request . queryPage ( content = True )
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
"""
if not conf . checkWaf :
return False
2013-07-08 14:38:36 +04:00
infoMsg = " heuristically checking if the target is protected by "
2011-07-06 09:44:47 +04:00
infoMsg + = " some kind of WAF/IPS/IDS "
logger . info ( infoMsg )
retVal = False
backup = dict ( conf . parameters )
2013-07-08 14:44:14 +04:00
payload = " %d %s " % ( randomInt ( ) , IDS_WAF_CHECK_PAYLOAD )
2011-07-06 09:44:47 +04:00
conf . parameters = dict ( backup )
conf . parameters [ PLACE . GET ] = " " if not conf . parameters . get ( PLACE . GET ) else conf . parameters [ PLACE . GET ] + " & "
2013-07-08 14:44:14 +04:00
conf . parameters [ PLACE . GET ] + = " %s = %s " % ( randomStr ( ) , payload )
logger . log ( CUSTOM_LOGGING . PAYLOAD , payload )
2011-07-06 09:44:47 +04:00
kb . matchRatio = None
2012-02-22 14:40:11 +04:00
Request . queryPage ( )
2011-07-06 09:44:47 +04:00
if kb . errorIsNone and kb . matchRatio is None :
kb . matchRatio = LOWER_RATIO_BOUND
conf . parameters = dict ( backup )
conf . parameters [ PLACE . GET ] = " " if not conf . parameters . get ( PLACE . GET ) else conf . parameters [ PLACE . GET ] + " & "
conf . parameters [ PLACE . GET ] + = " %s = %d " % ( randomStr ( ) , randomInt ( ) )
trueResult = Request . queryPage ( )
if trueResult :
conf . parameters = dict ( backup )
conf . parameters [ PLACE . GET ] = " " if not conf . parameters . get ( PLACE . GET ) else conf . parameters [ PLACE . GET ] + " & "
conf . parameters [ PLACE . GET ] + = " %s = %d %s " % ( randomStr ( ) , randomInt ( ) , IDS_WAF_CHECK_PAYLOAD )
falseResult = Request . queryPage ( )
if not falseResult :
retVal = True
conf . parameters = dict ( backup )
if retVal :
2011-07-07 00:41:13 +04:00
warnMsg = " it appears that the target is protected. Please "
2012-02-01 18:49:42 +04:00
warnMsg + = " consider usage of tamper scripts (option ' --tamper ' ) "
2011-07-06 09:44:47 +04:00
logger . warn ( warnMsg )
else :
infoMsg = " it appears that the target is not protected "
logger . info ( infoMsg )
return retVal
2013-02-21 14:14:57 +04:00
def identifyWaf ( ) :
if not conf . identifyWaf :
return None
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 :
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
return page or " " , headers or { } , code
2013-02-21 17:33:12 +04:00
2013-02-21 14:14:57 +04:00
retVal = False
2013-02-21 17:39:22 +04:00
for function , product in kb . wafFunctions :
try :
2013-02-21 17:52:56 +04:00
logger . debug ( " checking for WAF/IDS/IPS 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 "
2013-02-21 17:39:22 +04:00
errMsg + = " WAF script for ' %s ' ( ' %s ' ) " % ( product , ex )
logger . critical ( errMsg )
found = False
2013-02-21 17:33:12 +04:00
2013-02-21 14:14:57 +04:00
if found :
retVal = product
break
if retVal :
2013-02-26 14:16:09 +04:00
errMsg = " WAF/IDS/IPS identified ' %s ' . Please " % retVal
2013-02-21 17:39:22 +04:00
errMsg + = " consider usage of tamper scripts (option ' --tamper ' ) "
logger . critical ( errMsg )
2013-05-18 20:26:40 +04:00
2013-05-18 20:28:44 +04:00
message = " are you sure that you want to "
message + = " continue with further target testing? [y/N] "
2013-05-18 20:26:40 +04:00
output = readInput ( message , default = " N " )
if output and output [ 0 ] not in ( " Y " , " y " ) :
raise SqlmapUserQuitException
2013-02-21 14:14:57 +04:00
else :
2013-02-22 15:15:38 +04:00
infoMsg = " no WAF/IDS/IPS product has been identified "
logger . info ( infoMsg )
2013-02-21 14:14:57 +04:00
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 )
2013-05-17 18:04:05 +04:00
pushValue ( kb . pageCompress )
kb . pageCompress = False
2010-09-16 12:43:10 +04:00
try :
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
2010-10-15 16:46:41 +04:00
infoMsg = " NULL connection is supported with HEAD header "
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
2010-10-15 16:46:41 +04:00
infoMsg = " NULL connection is supported with GET header "
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
2012-12-06 17:14:19 +04:00
except SqlmapConnectionException , errMsg :
2010-09-16 12:43:10 +04:00
errMsg = getUnicode ( errMsg )
2013-01-04 02:20:55 +04:00
raise SqlmapConnectionException ( errMsg )
2010-09-16 12:43:10 +04:00
2013-05-17 18:04:05 +04:00
kb . pageCompress = popValue ( )
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 ) :
2013-02-28 23:20:08 +04:00
if not any ( ( conf . proxy , conf . tor , conf . dummy ) ) :
2011-06-24 21:19:24 +04:00
try :
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 "
errMsg + = " resolving a host name ' %s ' ( ' %s ' ) " % ( conf . hostname , str ( ex ) )
2013-01-04 02:20:55 +04:00
raise SqlmapConnectionException ( errMsg )
2010-05-21 17:36:49 +04:00
2013-02-28 23:28:34 +04:00
if not suppressOutput and not conf . dummy :
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 :
2014-03-15 01:20:20 +04:00
Request . queryPage ( content = True , noteResponseTime = False ) # dropping first page because it can be totally different than subsequent (e.g. WebGoat) before the Cookie is set up
2011-04-19 12:55:38 +04:00
page , _ = 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 ( ) :
2012-01-14 00:56:06 +04:00
warnMsg = " the web server responded with an HTTP error code ( %d ) " % getLastRequestHTTPError ( )
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 )
else :
kb . errorIsNone = True
2012-05-25 12:30:24 +04:00
2012-12-06 17:14:19 +04:00
except SqlmapConnectionException , errMsg :
2010-06-02 16:45:40 +04:00
errMsg = getUnicode ( errMsg )
2011-11-21 03:11:18 +04:00
logger . critical ( errMsg )
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 , ) ) :
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] "
if readInput ( msg , default = " Y " ) not in ( " n " , " N " ) :
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
def setVerbosity ( ) : # Cross-linked function
raise NotImplementedError