2019-05-08 13:47:52 +03:00
#!/usr/bin/env python
2008-10-15 19:38:22 +04:00
"""
2023-01-03 01:24:59 +03:00
Copyright ( c ) 2006 - 2023 sqlmap developers ( https : / / sqlmap . org / )
2017-10-11 15:50:46 +03:00
See the file ' LICENSE ' for copying permission
2008-10-15 19:38:22 +04:00
"""
2019-01-22 03:28:24 +03:00
from __future__ import print_function
2008-10-15 19:38:22 +04:00
import re
import time
from lib . core . agent import agent
2012-02-16 13:46:41 +04:00
from lib . core . bigarray import BigArray
2020-11-05 12:59:36 +03:00
from lib . core . common import applyFunctionRecursively
2011-01-28 19:36:09 +03:00
from lib . core . common import Backend
2010-05-13 15:05:35 +04:00
from lib . core . common import calculateDeltaSeconds
2008-10-15 19:38:22 +04:00
from lib . core . common import cleanQuery
from lib . core . common import expandAsteriskForColumns
2012-02-17 18:22:48 +04:00
from lib . core . common import extractExpectedValue
2019-03-29 04:28:16 +03:00
from lib . core . common import filterNone
2010-12-15 15:10:33 +03:00
from lib . core . common import getPublicTypeMembers
2019-07-01 11:43:05 +03:00
from lib . core . common import getTechnique
2013-02-12 20:35:14 +04:00
from lib . core . common import getTechniqueData
2012-02-24 17:07:20 +04:00
from lib . core . common import hashDBRetrieve
from lib . core . common import hashDBWrite
2010-12-18 12:51:34 +03:00
from lib . core . common import initTechnique
2019-10-07 15:20:18 +03:00
from lib . core . common import isDigit
2012-05-28 18:51:23 +04:00
from lib . core . common import isNoneValue
2011-01-19 02:02:11 +03:00
from lib . core . common import isNumPosStrValue
2010-12-15 15:10:33 +03:00
from lib . core . common import isTechniqueAvailable
2008-12-10 20:23:07 +03:00
from lib . core . common import parseUnionPage
2010-10-11 17:52:32 +04:00
from lib . core . common import popValue
from lib . core . common import pushValue
2013-01-31 13:01:52 +04:00
from lib . core . common import randomStr
2008-10-15 19:38:22 +04:00
from lib . core . common import readInput
2019-07-01 11:43:05 +03:00
from lib . core . common import setTechnique
2012-03-08 19:43:22 +04:00
from lib . core . common import singleTimeWarnMessage
2019-03-28 18:04:38 +03:00
from lib . core . compat import xrange
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
from lib . core . data import queries
2019-07-18 15:59:42 +03:00
from lib . core . decorators import lockedmethod
2018-04-01 13:45:47 +03:00
from lib . core . decorators import stackedmethod
2012-08-21 13:19:15 +04:00
from lib . core . dicts import FROM_DUMMY_TABLE
2012-03-01 14:10:19 +04:00
from lib . core . enums import CHARSET_TYPE
2010-11-08 12:20:02 +03:00
from lib . core . enums import DBMS
2010-12-10 15:30:36 +03:00
from lib . core . enums import EXPECTED
2010-12-08 16:04:48 +03:00
from lib . core . enums import PAYLOAD
2014-10-21 11:23:34 +04:00
from lib . core . exception import SqlmapConnectionException
2015-10-11 16:20:10 +03:00
from lib . core . exception import SqlmapDataException
2012-12-06 17:14:19 +04:00
from lib . core . exception import SqlmapNotVulnerableException
from lib . core . exception import SqlmapUserQuitException
2017-07-05 13:35:48 +03:00
from lib . core . settings import GET_VALUE_UPPERCASE_KEYWORDS
2017-10-31 13:05:25 +03:00
from lib . core . settings import INFERENCE_MARKER
2010-12-21 18:26:23 +03:00
from lib . core . settings import MAX_TECHNIQUES_PER_VALUE
2011-05-19 20:45:05 +04:00
from lib . core . settings import SQL_SCALAR_REGEX
2017-12-27 14:23:35 +03:00
from lib . core . settings import UNICODE_ENCODING
2011-01-07 19:39:47 +03:00
from lib . core . threads import getCurrentThreadData
2008-11-12 03:36:50 +03:00
from lib . request . connect import Connect as Request
2010-03-31 14:50:47 +04:00
from lib . request . direct import direct
2008-11-13 02:44:09 +03:00
from lib . techniques . blind . inference import bisection
2012-06-21 14:09:10 +04:00
from lib . techniques . blind . inference import queryOutputLength
2012-04-04 16:42:58 +04:00
from lib . techniques . dns . test import dnsTest
2012-04-02 18:05:30 +04:00
from lib . techniques . dns . use import dnsUse
2010-10-20 13:09:04 +04:00
from lib . techniques . error . use import errorUse
2012-04-02 18:05:30 +04:00
from lib . techniques . union . use import unionUse
2019-03-28 15:53:54 +03:00
from thirdparty import six
2008-10-15 19:38:22 +04:00
2012-12-06 17:14:19 +04:00
def _goDns ( payload , expression ) :
2012-07-11 14:55:05 +04:00
value = None
2016-10-22 22:52:18 +03:00
if conf . dnsDomain and kb . dnsTest is not False and not kb . testMode and Backend . getDbms ( ) is not None :
2012-07-11 14:55:05 +04:00
if kb . dnsTest is None :
dnsTest ( payload )
if kb . dnsTest :
value = dnsUse ( payload , expression )
return value
2012-12-06 17:14:19 +04:00
def _goInference ( payload , expression , charsetType = None , firstChar = None , lastChar = None , dump = False , field = None ) :
2008-11-12 03:36:50 +03:00
start = time . time ( )
2012-04-02 18:05:30 +04:00
value = None
count = 0
2012-12-06 17:14:19 +04:00
value = _goDns ( payload , expression )
2008-10-15 19:38:22 +04:00
2018-05-18 00:07:52 +03:00
if payload is None :
return None
2014-06-27 15:07:34 +04:00
if value is not None :
2012-07-11 14:55:05 +04:00
return value
2011-01-16 20:52:42 +03:00
2019-07-01 11:43:05 +03:00
timeBasedCompare = ( getTechnique ( ) in ( PAYLOAD . TECHNIQUE . TIME , PAYLOAD . TECHNIQUE . STACKED ) )
2008-10-15 19:38:22 +04:00
2019-06-04 14:04:31 +03: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 14:55:05 +04:00
if not ( timeBasedCompare and kb . dnsTest ) :
2019-06-01 17:33:27 +03: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 13:01:52 +04:00
2017-10-31 13:38:09 +03:00
if field and re . search ( r " \ ASELECT \ s+DISTINCT \ ((.+?) \ ) \ s+FROM " , expression , re . I ) :
2020-02-03 13:33:19 +03:00
if Backend . getIdentifiedDbms ( ) in ( DBMS . MYSQL , DBMS . PGSQL , DBMS . MONETDB , DBMS . VERTICA , DBMS . CRATEDB , DBMS . CUBRID ) :
2020-01-17 19:14:41 +03: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 13:01:52 +04:00
2021-01-11 19:36:23 +03:00
if field and conf . hexConvert or conf . binaryFields and field in conf . binaryFields or Backend . getIdentifiedDbms ( ) in ( DBMS . RAIMA , ) :
2013-01-15 21:51:40 +04:00
nulledCastedField = agent . nullAndCastField ( field )
injExpression = expression . replace ( field , nulledCastedField , 1 )
else :
injExpression = expression
length = queryOutputLength ( injExpression , payload )
2012-07-11 14:55:05 +04:00
else :
length = None
2008-10-15 19:38:22 +04:00
2012-07-11 14:55:05 +04:00
kb . inferenceMode = True
count , value = bisection ( payload , expression , length , charsetType , firstChar , lastChar , dump )
kb . inferenceMode = False
2008-10-15 19:38:22 +04:00
2012-07-11 14:55:05 +04:00
if not kb . bruteMode :
2020-10-27 16:57:12 +03:00
debugMsg = " performed %d quer %s in %.2f seconds " % ( count , ' y ' if count == 1 else " ies " , calculateDeltaSeconds ( start ) )
2012-07-11 14:55:05 +04:00
logger . debug ( debugMsg )
2012-04-03 13:18:30 +04:00
return value
2012-12-06 17:14:19 +04:00
def _goInferenceFields ( expression , expressionFields , expressionFieldsList , payload , num = None , charsetType = None , firstChar = None , lastChar = None , dump = False ) :
2011-01-19 02:02:11 +03:00
outputs = [ ]
origExpr = None
2008-10-15 19:38:22 +04:00
for field in expressionFieldsList :
output = None
2008-12-24 02:34:50 +03:00
if field . startswith ( " ROWNUM " ) :
continue
2008-12-22 22:36:01 +03:00
if isinstance ( num , int ) :
2011-01-19 02:02:11 +03:00
origExpr = expression
2013-04-15 17:57:28 +04:00
expression = agent . limitQuery ( num , expression , field , expressionFieldsList [ 0 ] )
2008-12-22 22:36:01 +03:00
2008-12-24 02:34:50 +03:00
if " ROWNUM " in expressionFieldsList :
expressionReplaced = expression
2009-01-23 01:28:27 +03:00
else :
expressionReplaced = expression . replace ( expressionFields , field , 1 )
2008-12-24 02:34:50 +03:00
2012-12-06 17:14:19 +04:00
output = _goInference ( payload , expressionReplaced , charsetType , firstChar , lastChar , dump , field )
2008-10-15 19:38:22 +04:00
2008-12-22 22:36:01 +03:00
if isinstance ( num , int ) :
expression = origExpr
2008-10-15 19:38:22 +04:00
outputs . append ( output )
return outputs
2012-12-06 17:14:19 +04:00
def _goInferenceProxy ( expression , fromUser = False , batch = False , unpack = True , charsetType = None , firstChar = None , lastChar = None , dump = False ) :
2008-10-15 19:38:22 +04: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 18:11:47 +04:00
2019-07-01 11:43:05 +03:00
initTechnique ( getTechnique ( ) )
2010-12-18 12:51:34 +03:00
2019-07-18 12:27:00 +03:00
query = agent . prefixQuery ( getTechniqueData ( ) . vector )
2010-12-14 00:33:42 +03:00
query = agent . suffixQuery ( query )
payload = agent . payload ( newValue = query )
count = None
startLimit = 0
stopLimit = None
2011-07-24 13:19:33 +04:00
outputs = BigArray ( )
2008-10-15 19:38:22 +04:00
2010-01-02 05:02:12 +03:00
if not unpack :
2012-12-06 17:14:19 +04:00
return _goInference ( payload , expression , charsetType , firstChar , lastChar , dump )
2009-04-22 15:48:07 +04:00
2011-01-20 02:06:15 +03:00
_ , _ , _ , _ , _ , expressionFieldsList , expressionFields , _ = agent . getFields ( expression )
2008-10-15 19:38:22 +04:00
2017-10-31 13:38:09 +03:00
rdbRegExp = re . search ( r " RDB \ $GET_CONTEXT \ ([^)]+ \ ) " , expression , re . I )
2011-04-30 18:54:29 +04:00
if rdbRegExp and Backend . isDbms ( DBMS . FIREBIRD ) :
2011-01-20 02:06:15 +03:00
expressionFieldsList = [ expressionFields ]
2008-10-15 19:38:22 +04:00
2011-01-20 02:06:15 +03:00
if len ( expressionFieldsList ) > 1 :
2012-04-05 03:34:08 +04:00
infoMsg = " the SQL query provided has more than one field. "
2011-01-20 02:06:15 +03: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 19:38:22 +04:00
2011-01-20 02:06:15 +03: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 16:17:56 +04: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-20 02:06:15 +03:00
# can return multiple entries
2021-02-14 16:47:28 +03: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 16:17:56 +04:00
expression , limitCond , topLimit , startLimit , stopLimit = agent . limitCondition ( expression )
2011-02-02 01:27:36 +03:00
2011-01-20 02:06:15 +03:00
if limitCond :
2012-10-20 15:17:45 +04:00
test = True
2012-12-19 16:17:56 +04:00
2011-01-20 02:06:15 +03:00
if not stopLimit or stopLimit < = 1 :
2012-02-07 18:57:48 +04:00
if Backend . getIdentifiedDbms ( ) in FROM_DUMMY_TABLE and expression . upper ( ) . endswith ( FROM_DUMMY_TABLE [ Backend . getIdentifiedDbms ( ) ] ) :
2011-01-20 02:06:15 +03:00
test = False
if test :
# Count the number of SQL query entries output
2011-01-28 19:36:09 +03:00
countFirstField = queries [ Backend . getIdentifiedDbms ( ) ] . count . query % expressionFieldsList [ 0 ]
2011-01-20 02:06:15 +03:00
countedExpression = expression . replace ( expressionFields , countFirstField , 1 )
2015-10-19 11:38:38 +03:00
if " ORDER BY " in countedExpression . upper ( ) :
2012-12-19 16:17:56 +04:00
_ = countedExpression . upper ( ) . rindex ( " ORDER BY " )
countedExpression = countedExpression [ : _ ]
2011-01-20 02:06:15 +03:00
if not stopLimit :
2012-12-06 17:14:19 +04:00
count = _goInference ( payload , countedExpression , charsetType = CHARSET_TYPE . DIGITS , firstChar = firstChar , lastChar = lastChar )
2011-01-20 02:06:15 +03:00
if isNumPosStrValue ( count ) :
count = int ( count )
2013-11-19 04:24:47 +04:00
if batch or count == 1 :
2011-01-20 02:06:15 +03: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 15:46:27 +03:00
choice = readInput ( message , default = ' A ' ) . upper ( )
2011-01-20 02:06:15 +03:00
2017-04-18 16:48:05 +03:00
if choice == ' A ' :
2008-10-15 19:38:22 +04:00
stopLimit = count
2017-04-18 16:48:05 +03:00
elif choice == ' Q ' :
2012-12-06 17:14:19 +04:00
raise SqlmapUserQuitException
2008-10-15 19:38:22 +04:00
2019-10-07 15:20:18 +03:00
elif isDigit ( choice ) and int ( choice ) > 0 and int ( choice ) < = count :
2017-04-18 16:48:05 +03:00
stopLimit = int ( choice )
2008-10-15 19:38:22 +04:00
2011-01-20 02:06:15 +03:00
infoMsg = " sqlmap is now going to retrieve the "
infoMsg + = " first %d query output entries " % stopLimit
logger . info ( infoMsg )
2008-10-15 19:38:22 +04:00
2017-04-18 16:48:05 +03:00
elif choice in ( ' # ' , ' S ' ) :
2011-01-20 02:06:15 +03:00
message = " how many? "
stopLimit = readInput ( message , default = " 10 " )
2008-10-15 19:38:22 +04:00
2019-10-07 15:20:18 +03:00
if not isDigit ( stopLimit ) :
2011-01-19 02:02:11 +03:00
errMsg = " invalid choice "
2009-04-22 15:48:07 +04:00
logger . error ( errMsg )
return None
2008-10-15 19:38:22 +04:00
2011-01-20 02:06:15 +03:00
else :
stopLimit = int ( stopLimit )
else :
errMsg = " invalid choice "
logger . error ( errMsg )
2008-12-17 23:11:18 +03:00
2011-01-20 02:06:15 +03:00
return None
2008-12-17 23:11:18 +03:00
2019-10-07 15:20:18 +03:00
elif count and not isDigit ( count ) :
2011-01-20 02:06:15 +03: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 13:04:34 +03:00
logger . warning ( warnMsg )
2008-10-15 19:38:22 +04:00
2011-01-20 02:06:15 +03:00
stopLimit = 1
2008-10-15 19:38:22 +04:00
2011-01-20 02:06:15 +03:00
elif ( not count or int ( count ) == 0 ) :
2012-01-07 21:45:45 +04:00
if not count :
warnMsg = " the SQL query provided does not "
warnMsg + = " return any output "
2022-06-22 13:04:34 +03:00
logger . warning ( warnMsg )
2008-10-15 19:38:22 +04:00
return None
2012-02-17 18:22:48 +04:00
elif ( not stopLimit or stopLimit == 0 ) :
2011-01-20 02:06:15 +03:00
return None
2008-10-15 19:38:22 +04:00
2011-01-20 02:06:15 +03:00
try :
2015-10-11 16:20:10 +03:00
try :
2020-11-16 12:28:53 +03:00
for num in xrange ( startLimit or 0 , stopLimit or 0 ) :
2015-10-11 16:20:10 +03: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 19:38:22 +04:00
2011-01-20 02:06:15 +03:00
except KeyboardInterrupt :
2019-01-22 03:28:24 +03:00
print ( )
2011-04-08 14:39:07 +04:00
warnMsg = " user aborted during dumping phase "
2022-06-22 13:04:34 +03:00
logger . warning ( warnMsg )
2008-10-15 19:38:22 +04:00
2011-01-20 02:06:15 +03:00
return outputs
2012-02-07 16:05:23 +04: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-20 02:06:15 +03:00
2012-12-06 17:14:19 +04:00
outputs = _goInferenceFields ( expression , expressionFields , expressionFieldsList , payload , charsetType = charsetType , firstChar = firstChar , lastChar = lastChar , dump = dump )
2008-10-15 19:38:22 +04:00
2016-06-13 16:30:38 +03:00
return " , " . join ( output or " " for output in outputs ) if not isNoneValue ( outputs ) else None
2008-10-15 19:38:22 +04:00
2012-12-06 17:14:19 +04:00
def _goBooleanProxy ( expression ) :
2011-01-19 02:02:11 +03:00
"""
Retrieve the output of a boolean based SQL query
"""
2019-07-01 11:43:05 +03:00
initTechnique ( getTechnique ( ) )
2011-01-19 02:02:11 +03:00
2016-10-22 22:52:18 +03:00
if conf . dnsDomain :
2019-07-18 12:27:00 +03:00
query = agent . prefixQuery ( getTechniqueData ( ) . vector )
2014-07-20 01:17:23 +04:00
query = agent . suffixQuery ( query )
payload = agent . payload ( newValue = query )
output = _goDns ( payload , expression )
if output is not None :
return output
2014-06-27 15:07:34 +04:00
2019-07-18 12:27:00 +03:00
vector = getTechniqueData ( ) . vector
2017-10-31 13:05:25 +03:00
vector = vector . replace ( INFERENCE_MARKER , expression )
2014-06-27 16:22:00 +04:00
query = agent . prefixQuery ( vector )
query = agent . suffixQuery ( query )
payload = agent . payload ( newValue = query )
2019-07-01 11:43:05 +03:00
timeBasedCompare = getTechnique ( ) in ( PAYLOAD . TECHNIQUE . TIME , PAYLOAD . TECHNIQUE . STACKED )
2011-01-19 02:02:11 +03:00
2012-07-12 04:39:15 +04:00
output = hashDBRetrieve ( expression , checkConf = True )
2011-01-19 02:02:11 +03:00
2012-05-09 12:41:05 +04:00
if output is None :
2011-01-19 02:02:11 +03:00
output = Request . queryPage ( payload , timeBasedCompare = timeBasedCompare , raise404 = False )
2012-05-09 12:41:05 +04:00
if output is not None :
hashDBWrite ( expression , output )
2012-02-17 18:22:48 +04:00
2011-01-19 02:02:11 +03:00
return output
2012-12-06 17:14:19 +04:00
def _goUnion ( expression , unpack = True , dump = False ) :
2008-10-15 19:38:22 +04:00
"""
2012-10-28 02:36:09 +04:00
Retrieve the output of a SQL query taking advantage of an union SQL
2008-10-15 19:38:22 +04:00
injection vulnerability on the affected parameter .
"""
2012-02-17 18:22:48 +04:00
output = unionUse ( expression , unpack = unpack , dump = dump )
2012-07-12 18:38:43 +04:00
2019-03-28 15:53:54 +03:00
if isinstance ( output , six . string_types ) :
2012-06-16 00:41:53 +04:00
output = parseUnionPage ( output )
2008-10-15 19:38:22 +04:00
2012-02-17 18:22:48 +04:00
return output
2008-10-15 19:38:22 +04:00
2019-07-18 15:59:42 +03:00
@lockedmethod
2018-04-01 13:45:47 +03:00
@stackedmethod
2012-10-28 02:36:09 +04: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 19:38:22 +04:00
"""
Called each time sqlmap inject a SQL query on the SQL injection
2012-10-28 02:36:09 +04:00
affected parameter .
2008-10-15 19:38:22 +04:00
"""
2012-10-28 02:19:00 +04:00
2019-02-28 03:05:23 +03:00
if conf . hexConvert and expected != EXPECTED . BOOL and Backend . getIdentifiedDbms ( ) :
2019-02-07 18:45:16 +03: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 15:22:33 +04:00
2011-07-26 00:40:31 +04:00
kb . safeCharEncode = safeCharEncode
2012-02-17 18:22:48 +04:00
kb . resumeValues = resumeValue
2011-07-26 00:40:31 +04:00
2017-07-05 13:35:48 +03:00
for keyword in GET_VALUE_UPPERCASE_KEYWORDS :
2017-10-31 13:38:09 +03:00
expression = re . sub ( r " (?i)( \ A| \ (| \ )| \ s) %s ( \ Z| \ (| \ )| \ s) " % keyword , r " \ g<1> %s \ g<2> " % keyword , expression )
2017-07-05 13:15:14 +03:00
2011-02-20 15:20:44 +03:00
if suppressOutput is not None :
pushValue ( getCurrentThreadData ( ) . disableStdOut )
getCurrentThreadData ( ) . disableStdOut = suppressOutput
2010-10-19 16:02:04 +04:00
2010-12-09 01:38:26 +03:00
try :
2014-08-27 00:57:08 +04:00
pushValue ( conf . db )
pushValue ( conf . tbl )
2012-02-14 21:29:00 +04:00
if expected == EXPECTED . BOOL :
forgeCaseExpression = booleanExpression = expression
2017-07-05 13:15:14 +03:00
if expression . startswith ( " SELECT " ) :
2013-01-18 01:03:03 +04:00
booleanExpression = " ( %s )= %s " % ( booleanExpression , " ' 1 ' " if " ' 1 ' " in booleanExpression else " 1 " )
2012-02-14 21:29:00 +04:00
else :
forgeCaseExpression = agent . forgeCaseStatement ( expression )
2010-12-09 01:38:26 +03:00
if conf . direct :
2012-07-12 18:38:43 +04:00
value = direct ( forgeCaseExpression if expected == EXPECTED . BOOL else expression )
2010-12-15 15:15:43 +03:00
2016-12-20 01:47:39 +03:00
elif any ( isTechniqueAvailable ( _ ) for _ in getPublicTypeMembers ( PAYLOAD . TECHNIQUE , onlyValues = True ) ) :
2010-12-10 18:06:53 +03:00
query = cleanQuery ( expression )
query = expandAsteriskForColumns ( query )
2010-12-10 18:24:25 +03:00
value = None
found = False
2012-07-12 18:38:43 +04:00
count = 0
2011-01-19 02:02:11 +03:00
2012-11-29 15:21:12 +04:00
if query and not re . search ( r " COUNT.*FROM.* \ (.*DISTINCT " , query , re . I ) :
2010-12-27 17:17:20 +03:00
query = query . replace ( " DISTINCT " , " " )
2011-01-19 02:02:11 +03:00
2012-07-30 23:50:46 +04:00
if not conf . forceDns :
2012-10-28 02:36:09 +04:00
if union and isTechniqueAvailable ( PAYLOAD . TECHNIQUE . UNION ) :
2019-07-01 11:43:05 +03:00
setTechnique ( PAYLOAD . TECHNIQUE . UNION )
2014-08-22 17:08:05 +04:00
kb . forcePartialUnion = kb . injection . data [ PAYLOAD . TECHNIQUE . UNION ] . vector [ 8 ]
2014-10-21 11:23:34 +04:00
fallback = not expected and kb . injection . data [ PAYLOAD . TECHNIQUE . UNION ] . where == PAYLOAD . WHERE . ORIGINAL and not kb . forcePartialUnion
2020-02-07 16:02:45 +03: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 11:23:34 +04:00
try :
value = _goUnion ( forgeCaseExpression if expected == EXPECTED . BOOL else query , unpack , dump )
except SqlmapConnectionException :
if not fallback :
raise
2012-07-30 23:50:46 +04:00
count + = 1
found = ( value is not None ) or ( value is None and expectingNone ) or count > = MAX_TECHNIQUES_PER_VALUE
2014-10-21 11:23:34 +04:00
if not found and fallback :
2013-07-31 23:15:03 +04:00
warnMsg = " something went wrong with full UNION "
2014-08-21 01:47:57 +04:00
warnMsg + = " technique (could be because of "
2014-08-21 01:53:15 +04: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 18:01:34 +03: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-21 01:53:15 +04:00
else :
singleTimeWarnMessage ( warnMsg )
2013-07-31 23:15:03 +04:00
2012-12-05 13:45:17 +04:00
if error and any ( isTechniqueAvailable ( _ ) for _ in ( PAYLOAD . TECHNIQUE . ERROR , PAYLOAD . TECHNIQUE . QUERY ) ) and not found :
2019-07-01 11:43:05 +03:00
setTechnique ( PAYLOAD . TECHNIQUE . ERROR if isTechniqueAvailable ( PAYLOAD . TECHNIQUE . ERROR ) else PAYLOAD . TECHNIQUE . QUERY )
2012-07-30 23:50:46 +04: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 22:52:18 +03:00
if found and conf . dnsDomain :
2019-03-29 04:28:16 +03: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 23:50:46 +04:00
warnMsg = " option ' --dns-domain ' will be ignored "
warnMsg + = " as faster techniques are usable "
warnMsg + = " ( %s ) " % _
singleTimeWarnMessage ( warnMsg )
2012-07-27 11:48:48 +04:00
2010-12-15 15:10:33 +03:00
if blind and isTechniqueAvailable ( PAYLOAD . TECHNIQUE . BOOLEAN ) and not found :
2019-07-01 11:43:05 +03:00
setTechnique ( PAYLOAD . TECHNIQUE . BOOLEAN )
2010-12-14 00:33:42 +03:00
2010-12-10 15:30:36 +03:00
if expected == EXPECTED . BOOL :
2012-12-06 17:14:19 +04:00
value = _goBooleanProxy ( booleanExpression )
2010-12-10 00:15:18 +03:00
else :
2012-12-06 17:14:19 +04:00
value = _goInferenceProxy ( query , fromUser , batch , unpack , charsetType , firstChar , lastChar , dump )
2010-12-14 00:33:42 +03:00
2010-12-21 18:24:14 +03:00
count + = 1
2010-12-31 15:04:39 +03:00
found = ( value is not None ) or ( value is None and expectingNone ) or count > = MAX_TECHNIQUES_PER_VALUE
2010-12-08 15:49:26 +03:00
2010-12-15 15:10:33 +03:00
if time and ( isTechniqueAvailable ( PAYLOAD . TECHNIQUE . TIME ) or isTechniqueAvailable ( PAYLOAD . TECHNIQUE . STACKED ) ) and not found :
2018-06-30 00:57:20 +03: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 19:32:19 +03:00
2010-12-15 15:10:33 +03:00
if isTechniqueAvailable ( PAYLOAD . TECHNIQUE . TIME ) :
2019-07-01 11:43:05 +03:00
setTechnique ( PAYLOAD . TECHNIQUE . TIME )
2010-12-15 15:10:33 +03:00
else :
2019-07-01 11:43:05 +03:00
setTechnique ( PAYLOAD . TECHNIQUE . STACKED )
2010-12-08 15:28:54 +03:00
2010-12-10 19:03:32 +03:00
if expected == EXPECTED . BOOL :
2012-12-06 17:14:19 +04:00
value = _goBooleanProxy ( booleanExpression )
2010-12-10 19:03:32 +03:00
else :
2012-12-06 17:14:19 +04:00
value = _goInferenceProxy ( query , fromUser , batch , unpack , charsetType , firstChar , lastChar , dump )
2010-12-09 01:38:26 +03:00
else :
errMsg = " none of the injection types identified can be "
errMsg + = " leveraged to retrieve queries output "
2013-01-04 02:20:55 +04:00
raise SqlmapNotVulnerableException ( errMsg )
2010-12-15 15:34:14 +03:00
2010-12-09 01:38:26 +03:00
finally :
2012-02-17 18:22:48 +04:00
kb . resumeValues = True
2016-01-09 19:32:19 +03:00
kb . responseTimeMode = None
2012-07-12 18:38:43 +04:00
2014-08-27 00:57:08 +04:00
conf . tbl = popValue ( )
conf . db = popValue ( )
2014-08-28 14:50:39 +04:00
if suppressOutput is not None :
getCurrentThreadData ( ) . disableStdOut = popValue ( )
2011-07-26 00:40:31 +04:00
kb . safeCharEncode = False
2011-04-10 03:13:16 +04:00
2020-03-26 16:58:58 +03: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 18:40:41 +03: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 19:43:22 +04:00
2020-11-05 12:59:36 +03: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 14:23:35 +03:00
# Dirty patch (safe-encoded unicode characters)
2019-04-19 12:24:34 +03:00
if isinstance ( value , six . text_type ) and " \\ x " in value :
2017-12-27 14:23:35 +03:00
try :
2017-12-30 18:35:45 +03:00
candidate = eval ( repr ( value ) . replace ( " \\ \\ x " , " \\ x " ) . replace ( " u ' " , " ' " , 1 ) ) . decode ( conf . encoding or UNICODE_ENCODING )
2017-12-27 14:23:35 +03:00
if " \\ x " not in candidate :
value = candidate
except :
pass
2012-02-17 18:22:48 +04:00
return extractExpectedValue ( value , expected )
2008-11-12 03:36:50 +03:00
2009-04-22 15:48:07 +04:00
def goStacked ( expression , silent = False ) :
2013-02-12 20:35:14 +04:00
if PAYLOAD . TECHNIQUE . STACKED in kb . injection . data :
2019-07-01 11:43:05 +03:00
setTechnique ( PAYLOAD . TECHNIQUE . STACKED )
2013-02-12 20:35:14 +04:00
else :
for technique in getPublicTypeMembers ( PAYLOAD . TECHNIQUE , True ) :
_ = getTechniqueData ( technique )
if _ and " stacked " in _ [ " title " ] . lower ( ) :
2019-07-01 11:43:05 +03:00
setTechnique ( technique )
2013-02-12 20:35:14 +04:00
break
2008-12-19 23:09:46 +03:00
expression = cleanQuery ( expression )
2010-03-27 02:23:25 +03:00
if conf . direct :
2011-02-01 00:22:39 +03:00
return direct ( expression )
2010-03-27 02:23:25 +03:00
2012-07-02 03:22:34 +04:00
query = agent . prefixQuery ( " ; %s " % expression )
2012-09-26 13:27:43 +04:00
query = agent . suffixQuery ( query )
2008-12-17 00:30:24 +03:00
payload = agent . payload ( newValue = query )
2015-02-16 13:48:53 +03:00
Request . queryPage ( payload , content = False , silent = silent , noteResponseTime = False , timeBasedCompare = " SELECT " in ( payload or " " ) . upper ( ) )
2010-12-06 21:20:57 +03:00
2010-12-14 12:05:00 +03:00
def checkBooleanExpression ( expression , expectingNone = True ) :
2012-10-15 14:24:30 +04:00
return getValue ( expression , expected = EXPECTED . BOOL , charsetType = CHARSET_TYPE . BINARY , suppressOutput = True , expectingNone = expectingNone )