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
"""
2011-05-16 02:21:38 +04:00
import os
2010-10-15 04:34:16 +04:00
import re
2008-10-15 19:38:22 +04:00
from lib . controller . action import action
from lib . controller . checks import checkSqlInjection
from lib . controller . checks import checkDynParam
from lib . controller . checks import checkStability
from lib . controller . checks import checkString
2008-12-12 22:06:31 +03:00
from lib . controller . checks import checkRegexp
2008-10-15 19:38:22 +04:00
from lib . controller . checks import checkConnection
2010-09-16 12:43:10 +04:00
from lib . controller . checks import checkNullConnection
2011-07-06 09:44:47 +04:00
from lib . controller . checks import checkWaf
2011-01-03 11:32:06 +03:00
from lib . controller . checks import heuristicCheckSqlInjection
2013-02-21 14:14:57 +04:00
from lib . controller . checks import identifyWaf
2010-11-28 21:10:54 +03:00
from lib . core . agent import agent
2011-03-29 02:48:00 +04:00
from lib . core . common import extractRegexResult
2011-01-14 19:12:44 +03:00
from lib . core . common import getFilteredPageContent
2011-05-16 02:21:38 +04:00
from lib . core . common import getPublicTypeMembers
2010-06-02 16:45:40 +04:00
from lib . core . common import getUnicode
2012-02-24 17:07:20 +04:00
from lib . core . common import hashDBRetrieve
from lib . core . common import hashDBWrite
2011-02-14 00:58:48 +03:00
from lib . core . common import intersect
2010-03-05 18:25:53 +03:00
from lib . core . common import parseTargetUrl
2011-03-29 02:48:00 +04:00
from lib . core . common import randomStr
2008-10-15 19:38:22 +04:00
from lib . core . common import readInput
2012-12-28 00:15:44 +04:00
from lib . core . common import safeCSValue
2011-01-02 10:37:47 +03:00
from lib . core . common import showHttpErrorCodes
2012-07-31 13:03:44 +04:00
from lib . core . common import urlencode
from lib . core . common import urldecode
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
2013-01-30 19:30:34 +04:00
from lib . core . enums import CONTENT_TYPE
2011-12-28 17:50:03 +04:00
from lib . core . enums import HASHDB_KEYS
2012-08-22 13:56:30 +04:00
from lib . core . enums import HEURISTIC_TEST
2010-11-08 12:44:32 +03:00
from lib . core . enums import HTTPMETHOD
2010-11-28 21:10:54 +03:00
from lib . core . enums import PAYLOAD
2010-11-08 12:44:32 +03:00
from lib . core . enums import PLACE
2013-01-14 14:22:38 +04:00
from lib . core . exception import SqlmapBaseException
2012-12-06 17:14:19 +04:00
from lib . core . exception import SqlmapNoneDataException
from lib . core . exception import SqlmapNotVulnerableException
from lib . core . exception import SqlmapSilentQuitException
from lib . core . exception import SqlmapValueException
from lib . core . exception import SqlmapUserQuitException
2012-10-19 13:02:14 +04:00
from lib . core . settings import ASP_NET_CONTROL_REGEX
2011-11-22 01:31:08 +04:00
from lib . core . settings import DEFAULT_GET_POST_DELIMITER
2011-03-29 02:48:00 +04:00
from lib . core . settings import EMPTY_FORM_FIELDS_REGEX
2011-04-13 23:01:02 +04:00
from lib . core . settings import IGNORE_PARAMETERS
2011-05-27 00:48:18 +04:00
from lib . core . settings import LOW_TEXT_PERCENT
2013-12-04 12:56:37 +04:00
from lib . core . settings import GOOGLE_ANALYTICS_COOKIE_PREFIX
2011-12-20 16:52:41 +04:00
from lib . core . settings import HOST_ALIASES
2011-02-14 00:58:48 +03:00
from lib . core . settings import REFERER_ALIASES
from lib . core . settings import USER_AGENT_ALIASES
2010-03-15 14:55:13 +03:00
from lib . core . target import initTargetEnv
from lib . core . target import setupTargetEnv
2012-07-14 19:01:04 +04:00
from thirdparty . pagerank . pagerank import get_pagerank
2008-10-15 19:38:22 +04:00
2012-12-06 17:14:19 +04:00
def _selectInjection ( ) :
2008-10-15 19:38:22 +04:00
"""
Selection function for injection place , parameters and type .
"""
2011-07-04 23:58:41 +04:00
points = { }
2008-10-15 19:38:22 +04:00
2011-07-04 23:58:41 +04:00
for injection in kb . injections :
place = injection . place
parameter = injection . parameter
ptype = injection . ptype
2008-10-15 19:38:22 +04:00
2010-11-28 21:10:54 +03:00
point = ( place , parameter , ptype )
2008-10-15 19:38:22 +04:00
2010-11-28 21:10:54 +03:00
if point not in points :
2011-07-04 23:58:41 +04:00
points [ point ] = injection
else :
for key in points [ point ] . keys ( ) :
if key != ' data ' :
points [ point ] [ key ] = points [ point ] [ key ] or injection [ key ]
points [ point ] [ ' data ' ] . update ( injection [ ' data ' ] )
2008-10-15 19:38:22 +04:00
2010-11-28 21:10:54 +03:00
if len ( points ) == 1 :
kb . injection = kb . injections [ 0 ]
2010-11-30 17:48:13 +03:00
2010-11-28 21:10:54 +03:00
elif len ( points ) > 1 :
message = " there were multiple injection points, please select "
message + = " the one to use for following injections: \n "
2008-10-15 19:38:22 +04:00
2010-11-28 21:10:54 +03:00
points = [ ]
2008-10-15 19:38:22 +04:00
2010-11-28 21:10:54 +03:00
for i in xrange ( 0 , len ( kb . injections ) ) :
place = kb . injections [ i ] . place
parameter = kb . injections [ i ] . parameter
ptype = kb . injections [ i ] . ptype
point = ( place , parameter , ptype )
2008-10-15 19:38:22 +04:00
2010-11-28 21:10:54 +03:00
if point not in points :
points . append ( point )
2010-11-29 04:04:42 +03:00
ptype = PAYLOAD . PARAMETER [ ptype ] if isinstance ( ptype , int ) else ptype
2008-10-15 19:38:22 +04:00
2010-11-28 21:10:54 +03:00
message + = " [ %d ] place: %s , parameter: " % ( i , place )
2010-11-29 04:04:42 +03:00
message + = " %s , type: %s " % ( parameter , ptype )
2008-10-15 19:38:22 +04:00
2010-11-28 21:10:54 +03:00
if i == 0 :
message + = " (default) "
2008-10-15 19:38:22 +04:00
2010-11-28 21:10:54 +03:00
message + = " \n "
message + = " [q] Quit "
select = readInput ( message , default = " 0 " )
if select . isdigit ( ) and int ( select ) < len ( kb . injections ) and int ( select ) > = 0 :
index = int ( select )
2013-01-09 18:38:41 +04:00
elif select [ 0 ] in ( " Q " , " q " ) :
2012-12-06 17:14:19 +04:00
raise SqlmapUserQuitException
2010-11-28 21:10:54 +03:00
else :
errMsg = " invalid choice "
2013-01-04 02:20:55 +04:00
raise SqlmapValueException ( errMsg )
2010-11-28 21:10:54 +03:00
kb . injection = kb . injections [ index ]
2012-12-06 17:14:19 +04:00
def _formatInjection ( inj ) :
2010-11-29 00:27:47 +03:00
data = " Place: %s \n " % inj . place
data + = " Parameter: %s \n " % inj . parameter
2010-11-28 21:10:54 +03:00
for stype , sdata in inj . data . items ( ) :
2011-08-03 14:34:50 +04:00
title = sdata . title
2012-02-10 19:34:04 +04:00
vector = sdata . vector
2012-09-26 13:27:43 +04:00
comment = sdata . comment
2013-01-13 19:22:43 +04:00
payload = agent . adjustLateValues ( sdata . payload )
if inj . place == PLACE . CUSTOM_HEADER :
payload = payload . split ( ' , ' , 1 ) [ 1 ]
2011-08-03 14:34:50 +04:00
if stype == PAYLOAD . TECHNIQUE . UNION :
2012-05-09 18:58:16 +04:00
count = re . sub ( r " (?i)( \ (.+ \ ))|( \ blimit[^A-Za-z]+) " , " " , sdata . payload ) . count ( ' , ' ) + 1
2011-08-03 14:34:50 +04:00
title = re . sub ( r " \ d+ to \ d+ " , str ( count ) , title )
2012-10-28 02:36:09 +04:00
vector = agent . forgeUnionQuery ( " [QUERY] " , vector [ 0 ] , vector [ 1 ] , vector [ 2 ] , None , None , vector [ 5 ] , vector [ 6 ] )
2011-08-03 14:34:50 +04:00
if count == 1 :
title = title . replace ( " columns " , " column " )
2012-09-26 13:27:43 +04:00
elif comment :
vector = " %s %s " % ( vector , comment )
2012-12-05 13:45:17 +04:00
data + = " Type: %s \n " % PAYLOAD . SQLINJECTION [ stype ]
2011-08-03 14:34:50 +04:00
data + = " Title: %s \n " % title
2013-06-19 12:50:00 +04:00
data + = " Payload: %s \n " % urldecode ( payload , unsafe = " & " , plusspace = ( inj . place == PLACE . POST and kb . postSpaceToPlus ) )
2012-02-10 19:34:04 +04:00
data + = " Vector: %s \n \n " % vector if conf . verbose > 1 else " \n "
2010-11-28 21:10:54 +03:00
2010-11-29 00:27:47 +03:00
return data
2010-11-28 21:10:54 +03:00
2012-12-06 17:14:19 +04:00
def _showInjections ( ) :
2011-01-12 01:18:47 +03:00
header = " sqlmap identified the following injection points with "
header + = " a total of %d HTTP(s) requests " % kb . testQueryCount
2010-11-29 00:27:47 +03:00
2013-01-29 19:34:53 +04:00
if hasattr ( conf , " api " ) :
2013-01-30 19:30:34 +04:00
conf . dumper . string ( " " , kb . injections , content_type = CONTENT_TYPE . TECHNIQUES )
2013-01-29 19:34:53 +04:00
else :
data = " " . join ( set ( map ( lambda x : _formatInjection ( x ) , kb . injections ) ) ) . rstrip ( " \n " )
conf . dumper . string ( header , data )
2008-10-15 19:38:22 +04:00
2011-06-09 13:58:42 +04:00
if conf . tamper :
2012-12-10 15:40:28 +04:00
warnMsg = " changes made by tampering scripts are not "
warnMsg + = " included in shown payload content(s) "
logger . warn ( warnMsg )
if conf . hpp :
warnMsg = " changes made by HTTP parameter pollution are not "
warnMsg + = " included in shown payload content(s) "
logger . warn ( warnMsg )
2011-06-09 13:58:42 +04:00
2012-12-06 17:14:19 +04:00
def _randomFillBlankFields ( value ) :
2011-04-11 15:38:41 +04:00
retVal = value
if extractRegexResult ( EMPTY_FORM_FIELDS_REGEX , value ) :
message = " do you want to fill blank fields with random values? [Y/n] "
test = readInput ( message , default = " Y " )
if not test or test [ 0 ] in ( " y " , " Y " ) :
2012-09-06 16:13:54 +04:00
for match in re . finditer ( EMPTY_FORM_FIELDS_REGEX , retVal ) :
item = match . group ( " result " )
2012-10-19 13:02:14 +04:00
if not any ( _ in item for _ in IGNORE_PARAMETERS ) and not re . search ( ASP_NET_CONTROL_REGEX , item ) :
2012-09-06 16:13:54 +04:00
if item [ - 1 ] == DEFAULT_GET_POST_DELIMITER :
retVal = retVal . replace ( item , " %s %s %s " % ( item [ : - 1 ] , randomStr ( ) , DEFAULT_GET_POST_DELIMITER ) )
else :
retVal = retVal . replace ( item , " %s %s " % ( item , randomStr ( ) ) )
2011-04-11 15:38:41 +04:00
return retVal
2012-12-06 17:14:19 +04:00
def _saveToHashDB ( ) :
2012-02-27 19:28:36 +04:00
injections = hashDBRetrieve ( HASHDB_KEYS . KB_INJECTIONS , True ) or [ ]
injections . extend ( _ for _ in kb . injections if _ and _ . place is not None and _ . parameter is not None )
_ = dict ( )
for injection in injections :
key = ( injection . place , injection . parameter , injection . ptype )
if key not in _ :
_ [ key ] = injection
else :
_ [ key ] . data . update ( injection . data )
hashDBWrite ( HASHDB_KEYS . KB_INJECTIONS , _ . values ( ) , True )
2012-02-27 17:44:07 +04:00
2012-02-24 17:07:20 +04:00
_ = hashDBRetrieve ( HASHDB_KEYS . KB_ABS_FILE_PATHS , True ) or set ( )
2011-12-28 17:50:03 +04:00
_ . update ( kb . absFilePaths )
2012-02-24 17:07:20 +04:00
hashDBWrite ( HASHDB_KEYS . KB_ABS_FILE_PATHS , _ , True )
2011-12-28 17:50:03 +04:00
2012-02-24 17:07:20 +04:00
if not hashDBRetrieve ( HASHDB_KEYS . KB_CHARS ) :
hashDBWrite ( HASHDB_KEYS . KB_CHARS , kb . chars , True )
2011-12-22 16:20:21 +04:00
2012-02-28 18:04:13 +04:00
if not hashDBRetrieve ( HASHDB_KEYS . KB_DYNAMIC_MARKINGS ) :
hashDBWrite ( HASHDB_KEYS . KB_DYNAMIC_MARKINGS , kb . dynamicMarkings , True )
2012-12-06 17:14:19 +04:00
def _saveToResultsFile ( ) :
2011-05-16 02:21:38 +04:00
if not conf . resultsFP :
return
results = { }
2011-06-08 19:31:27 +04:00
techniques = dict ( map ( lambda x : ( x [ 1 ] , x [ 0 ] ) , getPublicTypeMembers ( PAYLOAD . TECHNIQUE ) ) )
2011-05-16 02:21:38 +04:00
for inj in kb . injections :
if inj . place is None or inj . parameter is None :
continue
key = ( inj . place , inj . parameter )
if key not in results :
results [ key ] = [ ]
results [ key ] . extend ( inj . data . keys ( ) )
for key , value in results . items ( ) :
place , parameter = key
2012-12-28 00:15:44 +04:00
line = " %s , %s , %s , %s %s " % ( safeCSValue ( kb . originalUrls . get ( conf . url ) or conf . url ) , place , parameter , " " . join ( map ( lambda x : techniques [ x ] [ 0 ] . upper ( ) , sorted ( value ) ) ) , os . linesep )
2011-05-16 02:21:38 +04:00
conf . resultsFP . writelines ( line )
if not results :
line = " %s ,,, %s " % ( conf . url , os . linesep )
conf . resultsFP . writelines ( line )
2011-06-08 18:15:34 +04:00
2008-10-15 19:38:22 +04:00
def start ( ) :
"""
This function calls a function that performs checks on both URL
stability and all GET , POST , Cookie and User - Agent parameters to
check if they are dynamic and SQL injection affected
"""
2010-03-27 02:23:25 +03:00
if conf . direct :
initTargetEnv ( )
setupTargetEnv ( )
action ( )
2010-09-26 18:56:55 +04:00
return True
2010-03-27 02:23:25 +03:00
2012-08-22 18:50:01 +04:00
if conf . url and not any ( ( conf . forms , conf . crawlDepth ) ) :
2012-10-30 21:38:10 +04:00
kb . targets . add ( ( conf . url , conf . method , conf . data , conf . cookie ) )
2008-10-15 19:38:22 +04:00
2012-10-30 21:38:10 +04:00
if conf . configFile and not kb . targets :
2011-04-30 17:20:05 +04:00
errMsg = " you did not edit the configuration file properly, set "
2013-04-09 13:48:42 +04:00
errMsg + = " the target URL, list of targets or google dork "
2008-10-15 19:38:22 +04:00
logger . error ( errMsg )
2010-09-26 18:56:55 +04:00
return False
2008-10-15 19:38:22 +04:00
2012-10-30 21:38:10 +04:00
if kb . targets and len ( kb . targets ) > 1 :
infoMsg = " sqlmap got a total of %d targets " % len ( kb . targets )
2008-11-28 01:33:33 +03:00
logger . info ( infoMsg )
2011-04-30 17:20:05 +04:00
hostCount = 0
2008-10-15 19:38:22 +04:00
2012-10-30 21:38:10 +04:00
for targetUrl , targetMethod , targetData , targetCookie in kb . targets :
2010-03-16 15:14:02 +03:00
try :
2011-04-30 17:20:05 +04:00
conf . url = targetUrl
2010-03-16 15:14:02 +03:00
conf . method = targetMethod
2011-04-30 17:20:05 +04:00
conf . data = targetData
2010-03-16 15:14:02 +03:00
conf . cookie = targetCookie
2010-10-15 13:54:29 +04:00
2010-10-15 04:34:16 +04:00
initTargetEnv ( )
parseTargetUrl ( )
2010-10-15 13:54:29 +04:00
2010-10-15 04:34:16 +04:00
testSqlInj = False
2011-04-22 01:15:23 +04:00
2011-09-20 17:08:35 +04:00
if PLACE . GET in conf . parameters and not any ( [ conf . data , conf . testParameter ] ) :
2014-04-06 19:02:32 +04:00
for parameter in re . findall ( r " ([^=]+)=([^ %s ]+ %s ?| \ Z) " % ( re . escape ( conf . paramDel ) or DEFAULT_GET_POST_DELIMITER , re . escape ( conf . paramDel ) or DEFAULT_GET_POST_DELIMITER ) , conf . parameters [ PLACE . GET ] ) :
2011-04-11 15:38:41 +04:00
paramKey = ( conf . hostname , conf . path , PLACE . GET , parameter [ 0 ] )
2011-04-22 01:15:23 +04:00
2010-10-15 04:34:16 +04:00
if paramKey not in kb . testedParams :
testSqlInj = True
break
2010-10-15 13:54:29 +04:00
else :
paramKey = ( conf . hostname , conf . path , None , None )
if paramKey not in kb . testedParams :
testSqlInj = True
2013-08-13 20:55:23 +04:00
if testSqlInj and conf . hostname in kb . vulnHosts :
if kb . skipVulnHost is None :
2013-08-13 20:58:24 +04:00
message = " SQL injection vulnerability has already been detected "
2013-08-13 20:55:23 +04:00
message + = " against ' %s ' . Do you want to skip " % conf . hostname
message + = " further tests involving it? [Y/n] "
kb . skipVulnHost = readInput ( message , default = " Y " ) . upper ( ) != ' N '
testSqlInj = not kb . skipVulnHost
2011-01-07 18:41:09 +03:00
2010-10-15 04:34:16 +04:00
if not testSqlInj :
infoMsg = " skipping ' %s ' " % targetUrl
logger . info ( infoMsg )
continue
2010-03-16 15:14:02 +03:00
if conf . multipleTargets :
hostCount + = 1
2011-04-22 01:15:23 +04:00
2010-11-15 14:50:33 +03:00
if conf . forms :
2010-11-29 15:46:18 +03:00
message = " [# %d ] form: \n %s %s " % ( hostCount , conf . method or HTTPMETHOD . GET , targetUrl )
2010-11-15 14:50:33 +03:00
else :
2013-04-09 13:48:42 +04:00
message = " URL %d : \n %s %s %s " % ( hostCount , conf . method or HTTPMETHOD . GET , targetUrl , " (PageRank: %s ) " % get_pagerank ( targetUrl ) if conf . googleDork and conf . pageRank else " " )
2008-11-28 01:33:33 +03:00
2010-03-16 15:14:02 +03:00
if conf . cookie :
message + = " \n Cookie: %s " % conf . cookie
2008-11-28 01:33:33 +03:00
2012-11-13 13:21:11 +04:00
if conf . data is not None :
2011-03-03 13:39:04 +03:00
message + = " \n POST data: %s " % urlencode ( conf . data ) if conf . data else " "
2010-11-15 14:34:57 +03:00
if conf . forms :
if conf . method == HTTPMETHOD . GET and targetUrl . find ( " ? " ) == - 1 :
continue
message + = " \n do you want to test this form? [Y/n/q] "
test = readInput ( message , default = " Y " )
if not test or test [ 0 ] in ( " y " , " Y " ) :
if conf . method == HTTPMETHOD . POST :
2011-04-02 02:19:42 +04:00
message = " Edit POST data [default: %s ] %s : " % ( urlencode ( conf . data ) if conf . data else " None " , " (Warning: blank fields detected) " if conf . data and extractRegexResult ( EMPTY_FORM_FIELDS_REGEX , conf . data ) else " " )
2011-03-29 02:48:00 +04:00
conf . data = readInput ( message , default = conf . data )
2012-12-06 17:14:19 +04:00
conf . data = _randomFillBlankFields ( conf . data )
2011-11-22 01:31:08 +04:00
conf . data = urldecode ( conf . data ) if conf . data and urlencode ( DEFAULT_GET_POST_DELIMITER , None ) not in conf . data else conf . data
2010-11-15 14:34:57 +03:00
elif conf . method == HTTPMETHOD . GET :
2011-04-11 15:38:41 +04:00
if targetUrl . find ( " ? " ) > - 1 :
firstPart = targetUrl [ : targetUrl . find ( " ? " ) ]
2013-01-10 16:18:44 +04:00
secondPart = targetUrl [ targetUrl . find ( " ? " ) + 1 : ]
2010-11-15 14:34:57 +03:00
message = " Edit GET data [default: %s ]: " % secondPart
test = readInput ( message , default = secondPart )
2012-12-06 17:14:19 +04:00
test = _randomFillBlankFields ( test )
2010-11-15 14:34:57 +03:00
conf . url = " %s ? %s " % ( firstPart , test )
2011-04-11 15:38:41 +04:00
parseTargetUrl ( )
2010-11-15 14:34:57 +03:00
elif test [ 0 ] in ( " n " , " N " ) :
continue
elif test [ 0 ] in ( " q " , " Q " ) :
break
2008-10-15 19:38:22 +04:00
2010-12-20 13:48:53 +03:00
else :
2013-04-09 13:48:42 +04:00
message + = " \n do you want to test this URL? [Y/n/q] "
2010-11-15 14:34:57 +03:00
test = readInput ( message , default = " Y " )
2008-11-28 01:33:33 +03:00
2010-11-15 14:34:57 +03:00
if not test or test [ 0 ] in ( " y " , " Y " ) :
pass
elif test [ 0 ] in ( " n " , " N " ) :
continue
elif test [ 0 ] in ( " q " , " Q " ) :
break
2008-10-15 19:38:22 +04:00
2013-04-09 13:48:42 +04:00
infoMsg = " testing URL ' %s ' " % targetUrl
2011-04-30 19:29:59 +04:00
logger . info ( infoMsg )
2010-03-16 18:21:42 +03:00
2010-03-16 15:14:02 +03:00
setupTargetEnv ( )
2010-12-03 16:19:34 +03:00
if not checkConnection ( suppressOutput = conf . forms ) or not checkString ( ) or not checkRegexp ( ) :
2008-10-15 19:38:22 +04:00
continue
2011-07-06 09:44:47 +04:00
if conf . checkWaf :
checkWaf ( )
2013-02-21 14:14:57 +04:00
if conf . identifyWaf :
identifyWaf ( )
2010-10-17 01:52:16 +04:00
if conf . nullConnection :
2010-09-16 14:01:33 +04:00
checkNullConnection ( )
2010-09-16 12:43:10 +04:00
2011-05-11 01:33:06 +04:00
if ( len ( kb . injections ) == 0 or ( len ( kb . injections ) == 1 and kb . injections [ 0 ] . place is None ) ) \
and ( kb . injection . place is None or kb . injection . parameter is None ) :
2011-05-05 20:38:46 +04:00
2012-07-26 14:06:02 +04:00
if not any ( ( conf . string , conf . notString , conf . regexp ) ) and PAYLOAD . TECHNIQUE . BOOLEAN in conf . tech :
2010-03-16 15:14:02 +03:00
# NOTE: this is not needed anymore, leaving only to display
# a warning message to the user in case the page is not stable
checkStability ( )
2009-04-22 15:48:07 +04:00
2013-01-04 02:57:07 +04:00
# Do a little prioritization reorder of a testable parameter list
2010-11-08 02:37:15 +03:00
parameters = conf . parameters . keys ( )
2010-11-08 15:36:48 +03:00
2013-01-06 00:16:47 +04:00
# Order of testing list (first to last)
2013-01-13 19:22:43 +04:00
orderList = ( PLACE . CUSTOM_POST , PLACE . CUSTOM_HEADER , PLACE . URI , PLACE . POST , PLACE . GET )
2011-03-28 20:14:08 +04:00
2013-01-06 00:16:47 +04:00
for place in orderList [ : : - 1 ] :
2010-11-08 02:37:15 +03:00
if place in parameters :
parameters . remove ( place )
parameters . insert ( 0 , place )
2010-12-01 01:40:25 +03:00
proceed = True
2010-11-08 02:37:15 +03:00
for place in parameters :
2011-02-14 00:08:42 +03:00
# Test User-Agent and Referer headers only if
# --level >= 3
2012-07-26 14:26:57 +04:00
skip = ( place == PLACE . USER_AGENT and conf . level < 3 )
2011-03-29 10:38:19 +04:00
skip | = ( place == PLACE . REFERER and conf . level < 3 )
2011-12-20 16:52:41 +04:00
# Test Host header only if
# --level >= 5
skip | = ( place == PLACE . HOST and conf . level < 5 )
2011-02-14 00:08:42 +03:00
# Test Cookie header only if --level >= 2
2011-03-29 10:38:19 +04:00
skip | = ( place == PLACE . COOKIE and conf . level < 2 )
2010-11-29 19:33:20 +03:00
2012-07-26 14:26:57 +04:00
skip | = ( place == PLACE . USER_AGENT and intersect ( USER_AGENT_ALIASES , conf . skip , True ) not in ( [ ] , None ) )
2011-08-29 17:47:32 +04:00
skip | = ( place == PLACE . REFERER and intersect ( REFERER_ALIASES , conf . skip , True ) not in ( [ ] , None ) )
2012-02-12 23:22:33 +04:00
skip | = ( place == PLACE . COOKIE and intersect ( PLACE . COOKIE , conf . skip , True ) not in ( [ ] , None ) )
2011-08-29 17:47:32 +04:00
2012-07-26 14:26:57 +04:00
skip & = not ( place == PLACE . USER_AGENT and intersect ( USER_AGENT_ALIASES , conf . testParameter , True ) )
2011-08-29 17:47:32 +04:00
skip & = not ( place == PLACE . REFERER and intersect ( REFERER_ALIASES , conf . testParameter , True ) )
2011-12-20 16:52:41 +04:00
skip & = not ( place == PLACE . HOST and intersect ( HOST_ALIASES , conf . testParameter , True ) )
2013-05-12 18:24:13 +04:00
skip & = not ( place == PLACE . COOKIE and intersect ( ( PLACE . COOKIE , ) , conf . testParameter , True ) )
2011-02-14 00:58:48 +03:00
2011-03-29 10:38:19 +04:00
if skip :
2010-11-29 19:33:20 +03:00
continue
2012-07-14 13:01:30 +04:00
if place not in conf . paramDict :
2010-03-16 15:14:02 +03:00
continue
2009-04-22 15:48:07 +04:00
2010-03-16 15:14:02 +03:00
paramDict = conf . paramDict [ place ]
2011-04-22 01:53:35 +04:00
2010-03-16 15:14:02 +03:00
for parameter , value in paramDict . items ( ) :
2010-12-31 18:00:19 +03:00
if not proceed :
break
2011-05-24 21:15:25 +04:00
kb . vainRun = False
testSqlInj = True
2011-06-08 19:31:27 +04:00
paramKey = ( conf . hostname , conf . path , place , parameter )
2011-05-24 21:15:25 +04:00
2010-07-30 00:01:04 +04:00
if paramKey in kb . testedParams :
testSqlInj = False
2010-10-15 04:34:16 +04:00
infoMsg = " skipping previously processed %s parameter ' %s ' " % ( place , parameter )
logger . info ( infoMsg )
2011-08-29 17:29:42 +04:00
elif parameter in conf . testParameter :
pass
2011-08-29 16:50:52 +04:00
elif parameter == conf . rParam :
testSqlInj = False
infoMsg = " skipping randomizing %s parameter ' %s ' " % ( place , parameter )
logger . info ( infoMsg )
2011-08-29 17:29:42 +04:00
elif parameter in conf . skip :
testSqlInj = False
infoMsg = " skipping %s parameter ' %s ' " % ( place , parameter )
logger . info ( infoMsg )
2011-06-16 18:11:30 +04:00
2011-08-02 21:35:43 +04:00
# Ignore session-like parameters for --level < 4
2013-12-04 12:56:37 +04:00
elif conf . level < 4 and ( parameter . upper ( ) in IGNORE_PARAMETERS or parameter . upper ( ) . startswith ( GOOGLE_ANALYTICS_COOKIE_PREFIX ) ) :
2011-04-13 23:01:02 +04:00
testSqlInj = False
infoMsg = " ignoring %s parameter ' %s ' " % ( place , parameter )
logger . info ( infoMsg )
2011-10-22 02:21:41 +04:00
elif PAYLOAD . TECHNIQUE . BOOLEAN in conf . tech :
2013-01-13 19:22:43 +04:00
check = checkDynParam ( place , parameter , value )
2012-08-20 14:14:01 +04:00
2013-01-13 19:22:43 +04:00
if not check :
warnMsg = " %s parameter ' %s ' does not appear dynamic " % ( place , parameter )
logger . warn ( warnMsg )
2010-10-15 04:34:16 +04:00
2013-01-13 19:22:43 +04:00
else :
infoMsg = " %s parameter ' %s ' is dynamic " % ( place , parameter )
logger . info ( infoMsg )
2008-10-15 19:38:22 +04:00
2010-07-30 00:01:04 +04:00
kb . testedParams . add ( paramKey )
2010-03-16 15:14:02 +03:00
if testSqlInj :
2011-01-15 16:15:10 +03:00
check = heuristicCheckSqlInjection ( place , parameter )
2011-04-22 01:53:35 +04:00
2012-08-22 13:56:30 +04:00
if check != HEURISTIC_TEST . POSITIVE :
if conf . smart or ( kb . ignoreCasted and check == HEURISTIC_TEST . CASTED ) :
2011-07-10 19:16:58 +04:00
infoMsg = " skipping %s parameter ' %s ' " % ( place , parameter )
logger . info ( infoMsg )
continue
2010-10-15 04:34:16 +04:00
2012-06-19 12:33:51 +04:00
infoMsg = " testing for SQL injection on %s " % place
2011-04-30 19:29:59 +04:00
infoMsg + = " parameter ' %s ' " % parameter
logger . info ( infoMsg )
2010-10-15 04:34:16 +04:00
2010-11-28 21:10:54 +03:00
injection = checkSqlInjection ( place , parameter , value )
2010-12-22 02:55:55 +03:00
proceed = not kb . endDetection
2010-12-01 01:40:25 +03:00
if injection is not None and injection . place is not None :
2010-11-28 21:10:54 +03:00
kb . injections . append ( injection )
2010-12-01 01:40:25 +03:00
2010-12-22 16:15:44 +03:00
# In case when user wants to end detection phase (Ctrl+C)
if not proceed :
break
2010-12-01 01:40:25 +03:00
msg = " %s parameter ' %s ' " % ( injection . place , injection . parameter )
2012-02-13 15:18:47 +04:00
msg + = " is vulnerable. Do you want to keep testing the others (if any)? [y/N] "
test = readInput ( msg , default = " N " )
2010-12-01 01:40:25 +03:00
2012-02-13 15:18:47 +04:00
if test [ 0 ] not in ( " y " , " Y " ) :
2010-12-01 01:40:25 +03:00
proceed = False
2010-12-23 14:28:13 +03:00
paramKey = ( conf . hostname , conf . path , None , None )
kb . testedParams . add ( paramKey )
2010-11-28 21:10:54 +03:00
else :
2011-01-12 01:18:47 +03:00
warnMsg = " %s parameter ' %s ' is not " % ( place , parameter )
2010-03-16 15:14:02 +03:00
warnMsg + = " injectable "
logger . warn ( warnMsg )
2008-11-22 04:57:22 +03:00
2010-12-01 01:40:25 +03:00
if len ( kb . injections ) == 0 or ( len ( kb . injections ) == 1 and kb . injections [ 0 ] . place is None ) :
2011-05-24 21:15:25 +04:00
if kb . vainRun and not conf . multipleTargets :
2011-11-15 15:17:39 +04:00
errMsg = " no parameter(s) found for testing in the provided data "
2011-05-24 21:15:25 +04:00
errMsg + = " (e.g. GET parameter ' id ' in ' www.site.com/index.php?id=1 ' ) "
2013-01-04 02:20:55 +04:00
raise SqlmapNoneDataException ( errMsg )
2012-08-20 13:40:49 +04:00
else :
2012-08-22 14:00:17 +04:00
errMsg = " all tested parameters appear to be not injectable. "
2011-04-06 18:41:44 +04:00
2011-04-22 02:04:20 +04:00
if conf . level < 5 or conf . risk < 3 :
2012-07-23 15:57:38 +04:00
errMsg + = " Try to increase ' --level ' / ' --risk ' values "
2011-04-22 02:04:20 +04:00
errMsg + = " to perform more tests. "
if isinstance ( conf . tech , list ) and len ( conf . tech ) < 5 :
2012-02-01 18:49:42 +04:00
errMsg + = " Rerun without providing the option ' --technique ' . "
2011-01-16 02:11:36 +03:00
2011-01-14 19:12:44 +03:00
if not conf . textOnly and kb . originalPage :
2011-01-16 21:11:35 +03:00
percent = ( 100.0 * len ( getFilteredPageContent ( kb . originalPage ) ) / len ( kb . originalPage ) )
2011-05-27 00:48:18 +04:00
2012-08-20 13:28:41 +04:00
if kb . dynamicMarkings :
2012-07-23 15:57:38 +04:00
errMsg + = " You can give it a go with the switch ' --text-only ' "
errMsg + = " if the target page has a low percentage "
2011-06-15 21:37:28 +04:00
errMsg + = " of textual content (~ %.2f %% of " % percent
2012-08-20 13:29:23 +04:00
errMsg + = " page content is text). "
2011-05-27 12:21:02 +04:00
elif percent < LOW_TEXT_PERCENT and not kb . errorIsNone :
2012-07-23 15:57:38 +04:00
errMsg + = " Please retry with the switch ' --text-only ' "
2011-05-27 00:58:24 +04:00
errMsg + = " (along with --technique=BU) as this case "
errMsg + = " looks like a perfect candidate "
2011-05-27 00:48:18 +04:00
errMsg + = " (low textual content along with inability "
errMsg + = " of comparison engine to detect at least "
2012-08-20 13:29:23 +04:00
errMsg + = " one dynamic parameter). "
2011-04-22 01:31:16 +04:00
2012-08-22 13:56:30 +04:00
if kb . heuristicTest == HEURISTIC_TEST . POSITIVE :
2011-06-15 21:37:28 +04:00
errMsg + = " As heuristic test turned out positive you are "
errMsg + = " strongly advised to continue on with the tests. "
errMsg + = " Please, consider usage of tampering scripts as "
errMsg + = " your target might filter the queries. "
2012-07-26 14:06:02 +04:00
if not conf . string and not conf . notString and not conf . regexp :
2011-06-15 21:37:28 +04:00
errMsg + = " Also, you can try to rerun by providing "
2012-07-23 15:57:38 +04:00
errMsg + = " either a valid value for option ' --string ' "
errMsg + = " (or ' --regexp ' ) "
2011-04-22 01:31:16 +04:00
elif conf . string :
2011-06-15 21:37:28 +04:00
errMsg + = " Also, you can try to rerun by providing a "
2012-07-23 15:57:38 +04:00
errMsg + = " valid value for option ' --string ' as perhaps the string you "
2013-10-15 21:26:24 +04:00
errMsg + = " have chosen does not match "
2011-06-15 21:37:28 +04:00
errMsg + = " exclusively True responses "
2011-04-22 01:31:16 +04:00
elif conf . regexp :
2011-06-15 21:37:28 +04:00
errMsg + = " Also, you can try to rerun by providing a "
2012-07-23 15:57:38 +04:00
errMsg + = " valid value for option ' --regexp ' as perhaps the regular "
2013-10-15 21:26:24 +04:00
errMsg + = " expression that you have chosen "
2011-06-15 21:37:28 +04:00
errMsg + = " does not match exclusively True responses "
2011-01-16 02:11:36 +03:00
2013-01-04 02:20:55 +04:00
raise SqlmapNotVulnerableException ( errMsg )
2010-11-28 21:10:54 +03:00
else :
2011-01-12 01:18:47 +03:00
# Flush the flag
kb . testMode = False
2012-12-06 17:14:19 +04:00
_saveToResultsFile ( )
_saveToHashDB ( )
_showInjections ( )
_selectInjection ( )
2008-10-15 19:38:22 +04:00
2010-12-01 20:09:52 +03:00
if kb . injection . place is not None and kb . injection . parameter is not None :
2012-08-20 13:40:49 +04:00
if conf . multipleTargets :
2010-03-16 15:14:02 +03:00
message = " do you want to exploit this SQL injection? [Y/n] "
exploit = readInput ( message , default = " Y " )
2008-10-15 19:38:22 +04:00
2010-03-16 15:14:02 +03:00
condition = not exploit or exploit [ 0 ] in ( " y " , " Y " )
else :
condition = True
if condition :
action ( )
2010-11-05 18:59:25 +03:00
except KeyboardInterrupt :
2010-11-05 19:03:12 +03:00
if conf . multipleTargets :
2011-04-08 14:39:07 +04:00
warnMsg = " user aborted in multiple target mode "
2010-11-05 19:03:12 +03:00
logger . warn ( warnMsg )
2010-11-05 18:59:25 +03:00
2010-11-07 19:23:03 +03:00
message = " do you want to skip to the next target in list? [Y/n/q] "
2010-11-05 19:03:12 +03:00
test = readInput ( message , default = " Y " )
2010-11-05 18:59:25 +03:00
2010-11-05 19:03:12 +03:00
if not test or test [ 0 ] in ( " y " , " Y " ) :
pass
elif test [ 0 ] in ( " n " , " N " ) :
return False
elif test [ 0 ] in ( " q " , " Q " ) :
2012-12-06 17:14:19 +04:00
raise SqlmapUserQuitException
2010-11-05 19:03:12 +03:00
else :
raise
2010-11-05 18:59:25 +03:00
2012-12-06 17:14:19 +04:00
except SqlmapUserQuitException :
2010-09-30 23:45:23 +04:00
raise
2012-12-06 17:14:19 +04:00
except SqlmapSilentQuitException :
2010-11-10 22:44:51 +03:00
raise
2013-07-27 13:20:43 +04:00
except SqlmapBaseException , ex :
errMsg = getUnicode ( ex . message )
2008-10-15 19:38:22 +04:00
2010-03-16 15:14:02 +03:00
if conf . multipleTargets :
2013-07-27 13:20:43 +04:00
errMsg + = " , skipping to the next %s " % ( " form " if conf . forms else " URL " )
logger . error ( errMsg )
2010-03-16 15:14:02 +03:00
else :
2013-07-27 13:20:43 +04:00
logger . critical ( errMsg )
2010-09-26 18:56:55 +04:00
return False
2008-10-15 19:38:22 +04:00
2011-01-02 10:37:47 +03:00
finally :
showHttpErrorCodes ( )
2012-04-12 13:44:54 +04:00
if kb . maxConnectionsFlag :
2013-01-10 16:18:44 +04:00
warnMsg = " it appears that the target "
2012-04-12 13:44:54 +04:00
warnMsg + = " has a maximum connections "
warnMsg + = " constraint "
logger . warn ( warnMsg )
2011-05-11 00:44:36 +04:00
if kb . dataOutputFlag and not conf . multipleTargets :
2012-04-12 13:44:54 +04:00
logger . info ( " fetched data logged to text files under ' %s ' " % conf . outputPath )
2010-11-03 13:08:27 +03:00
2011-06-20 15:32:30 +04:00
if conf . multipleTargets and conf . resultsFilename :
2013-01-10 16:18:44 +04:00
infoMsg = " you can find results of scanning in multiple targets "
2011-06-08 19:31:27 +04:00
infoMsg + = " mode inside the CSV file ' %s ' " % conf . resultsFilename
2011-05-16 02:21:38 +04:00
logger . info ( infoMsg )
2010-09-26 18:56:55 +04:00
return True