filesystem批注

pull/18/head
Warmlight 2 months ago
parent 6aef1b5ef6
commit 9b093e7aa4

@ -5,320 +5,496 @@ Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import codecs
import os
import sys
from lib.core.agent import agent
from lib.core.common import Backend
from lib.core.common import checkFile
from lib.core.common import dataToOutFile
from lib.core.common import decloakToTemp
from lib.core.common import decodeDbmsHexValue
from lib.core.common import isListLike
from lib.core.common import isNumPosStrValue
from lib.core.common import isStackingAvailable
from lib.core.common import isTechniqueAvailable
from lib.core.common import readInput
from lib.core.compat import xrange
from lib.core.convert import encodeBase64
from lib.core.convert import encodeHex
from lib.core.convert import getText
from lib.core.convert import getUnicode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
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.exception import SqlmapUndefinedMethod
from lib.core.settings import UNICODE_ENCODING
from lib.request import inject
import codecs # 用于处理不同编码的文本
import os # 用于与操作系统进行交互
import sys # 用于访问与系统相关的参数和函数
from lib.core.agent import agent # 导入 agent 模块,用于与数据库进行交互
from lib.core.common import Backend # 导入 Backend 模块,用于获取数据库信息
from lib.core.common import checkFile # 导入 checkFile 函数,用于检查文件是否存在
from lib.core.common import dataToOutFile # 导入 dataToOutFile 函数,用于将数据写入文件
from lib.core.common import decloakToTemp # 导入 decloakToTemp 函数,用于将伪装的文件名转换为临时文件路径
from lib.core.common import decodeDbmsHexValue # 导入 decodeDbmsHexValue 函数,用于解码数据库的十六进制数据
from lib.core.common import isListLike # 导入 isListLike 函数,用于检查是否为列表类型
from lib.core.common import isNumPosStrValue # 导入 isNumPosStrValue 函数,用于检查是否为正数字符串
from lib.core.common import isStackingAvailable # 导入 isStackingAvailable 函数,用于检查是否支持堆叠查询
from lib.core.common import isTechniqueAvailable # 导入 isTechniqueAvailable 函数,用于检查是否支持某种注入技术
from lib.core.common import readInput # 导入 readInput 函数,用于读取用户输入
from lib.core.compat import xrange # 导入 xrange 函数,用于生成数字序列
from lib.core.convert import encodeBase64 # 导入 encodeBase64 函数,用于进行 Base64 编码
from lib.core.convert import encodeHex # 导入 encodeHex 函数,用于进行十六进制编码
from lib.core.convert import getText # 导入 getText 函数,用于将数据转换为文本
from lib.core.convert import getUnicode # 导入 getUnicode 函数,用于将数据转换为 Unicode
from lib.core.data import conf # 导入 conf 模块,用于获取全局配置信息
from lib.core.data import kb # 导入 kb 模块,用于获取全局知识库信息
from lib.core.data import logger # 导入 logger 模块,用于打印日志信息
from lib.core.enums import CHARSET_TYPE # 导入 CHARSET_TYPE 枚举,用于指定字符集类型
from lib.core.enums import DBMS # 导入 DBMS 枚举,用于指定数据库类型
from lib.core.enums import EXPECTED # 导入 EXPECTED 枚举,用于指定预期的数据类型
from lib.core.enums import PAYLOAD # 导入 PAYLOAD 枚举,用于指定攻击载荷类型
from lib.core.exception import SqlmapUndefinedMethod # 导入 SqlmapUndefinedMethod 异常,用于处理未定义的方法
from lib.core.settings import UNICODE_ENCODING # 导入 UNICODE_ENCODING 变量,用于指定 Unicode 编码
from lib.request import inject # 导入 inject 模块,用于进行 SQL 注入
class Filesystem(object):
"""
This class defines generic OS file system functionalities for plugins.
这个类定义了插件的通用操作系统文件系统功能
"""
def __init__(self):
self.fileTblName = "%sfile" % conf.tablePrefix
self.tblField = "data"
# 初始化文件表名
self.fileTblName = "%sfile" % conf.tablePrefix # 将配置中的表前缀与 "file" 组合,生成表名
# 初始化表字段名
self.tblField = "data" # 设置表字段名为 "data"
def _checkFileLength(self, localFile, remoteFile, fileRead=False):
"""
检查本地文件和远程文件长度是否相同
Args:
localFile (str): 本地文件路径
remoteFile (str): 远程文件路径
fileRead (bool, optional): 是否为读取文件操作. Defaults to False.
Returns:
bool: 如果文件长度相同返回 True否则返回 False如果无法判断则返回 None
"""
if Backend.isDbms(DBMS.MYSQL):
lengthQuery = "LENGTH(LOAD_FILE('%s'))" % remoteFile
# 如果是 MySQL 数据库
lengthQuery = "LENGTH(LOAD_FILE('%s'))" % remoteFile # 构建获取远程文件长度的 SQL 查询
elif Backend.isDbms(DBMS.PGSQL) and not fileRead:
lengthQuery = "SELECT SUM(LENGTH(data)) FROM pg_largeobject WHERE loid=%d" % self.oid
# 如果是 PostgreSQL 数据库且不是读取文件操作
lengthQuery = "SELECT SUM(LENGTH(data)) FROM pg_largeobject WHERE loid=%d" % self.oid # 构建获取大对象长度的 SQL 查询
elif Backend.isDbms(DBMS.MSSQL):
self.createSupportTbl(self.fileTblName, self.tblField, "VARBINARY(MAX)")
inject.goStacked("INSERT INTO %s(%s) SELECT %s FROM OPENROWSET(BULK '%s', SINGLE_BLOB) AS %s(%s)" % (self.fileTblName, self.tblField, self.tblField, remoteFile, self.fileTblName, self.tblField))
# 如果是 MSSQL 数据库
self.createSupportTbl(self.fileTblName, self.tblField, "VARBINARY(MAX)") # 创建支持表
inject.goStacked("INSERT INTO %s(%s) SELECT %s FROM OPENROWSET(BULK '%s', SINGLE_BLOB) AS %s(%s)" % (self.fileTblName, self.tblField, self.tblField, remoteFile, self.fileTblName, self.tblField)) # 使用 OPENROWSET 将文件内容插入表中
lengthQuery = "SELECT DATALENGTH(%s) FROM %s" % (self.tblField, self.fileTblName)
lengthQuery = "SELECT DATALENGTH(%s) FROM %s" % (self.tblField, self.fileTblName) # 构建获取表数据长度的 SQL 查询
try:
localFileSize = os.path.getsize(localFile)
localFileSize = os.path.getsize(localFile) # 获取本地文件大小
except OSError:
warnMsg = "file '%s' is missing" % localFile
logger.warning(warnMsg)
localFileSize = 0
# 如果本地文件不存在
warnMsg = "file '%s' is missing" % localFile # 构造警告消息
logger.warning(warnMsg) # 打印警告信息
localFileSize = 0 # 将本地文件大小设置为 0
if fileRead and Backend.isDbms(DBMS.PGSQL):
logger.info("length of read file '%s' cannot be checked on PostgreSQL" % remoteFile)
sameFile = True
# 如果是读取文件操作且是 PostgreSQL 数据库
logger.info("length of read file '%s' cannot be checked on PostgreSQL" % remoteFile) # 打印信息,表示 PostgreSQL 无法检查读取文件长度
sameFile = True # 将 sameFile 设置为 True
else:
logger.debug("checking the length of the remote file '%s'" % remoteFile)
remoteFileSize = inject.getValue(lengthQuery, resumeValue=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
sameFile = None
# 如果不是读取文件或者不是 PostgreSQL 数据库
logger.debug("checking the length of the remote file '%s'" % remoteFile) # 打印调试信息,表示正在检查远程文件长度
remoteFileSize = inject.getValue(lengthQuery, resumeValue=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) # 获取远程文件大小
sameFile = None # 将 sameFile 初始化为 None
if isNumPosStrValue(remoteFileSize):
remoteFileSize = int(remoteFileSize)
localFile = getUnicode(localFile, encoding=sys.getfilesystemencoding() or UNICODE_ENCODING)
sameFile = False
# 如果远程文件大小为有效的数字字符串
remoteFileSize = int(remoteFileSize) # 将远程文件大小转换为整数
localFile = getUnicode(localFile, encoding=sys.getfilesystemencoding() or UNICODE_ENCODING) # 将本地文件路径转换为 Unicode
sameFile = False # 将 sameFile 设置为 False
if localFileSize == remoteFileSize:
sameFile = True
infoMsg = "the local file '%s' and the remote file " % localFile
infoMsg += "'%s' have the same size (%d B)" % (remoteFile, localFileSize)
# 如果本地文件大小和远程文件大小相同
sameFile = True # 将 sameFile 设置为 True
infoMsg = "the local file '%s' and the remote file " % localFile # 构造信息消息
infoMsg += "'%s' have the same size (%d B)" % (remoteFile, localFileSize) # 将远程文件路径和文件大小添加到信息消息中
elif remoteFileSize > localFileSize:
infoMsg = "the remote file '%s' is larger (%d B) than " % (remoteFile, remoteFileSize)
infoMsg += "the local file '%s' (%dB)" % (localFile, localFileSize)
# 如果远程文件大小大于本地文件大小
infoMsg = "the remote file '%s' is larger (%d B) than " % (remoteFile, remoteFileSize) # 构造信息消息
infoMsg += "the local file '%s' (%dB)" % (localFile, localFileSize) # 将本地文件路径和文件大小添加到信息消息中
else:
infoMsg = "the remote file '%s' is smaller (%d B) than " % (remoteFile, remoteFileSize)
infoMsg += "file '%s' (%d B)" % (localFile, localFileSize)
# 如果远程文件大小小于本地文件大小
infoMsg = "the remote file '%s' is smaller (%d B) than " % (remoteFile, remoteFileSize) # 构造信息消息
infoMsg += "file '%s' (%d B)" % (localFile, localFileSize) # 将本地文件路径和文件大小添加到信息消息中
logger.info(infoMsg)
logger.info(infoMsg) # 打印信息消息
else:
sameFile = False
warnMsg = "it looks like the file has not been written (usually "
warnMsg += "occurs if the DBMS process user has no write "
warnMsg += "privileges in the destination path)"
logger.warning(warnMsg)
# 如果远程文件大小不是有效的数字字符串
sameFile = False # 将 sameFile 设置为 False
warnMsg = "it looks like the file has not been written (usually " # 构造警告消息
warnMsg += "occurs if the DBMS process user has no write " # 警告消息补充
warnMsg += "privileges in the destination path)" # 警告消息补充
logger.warning(warnMsg) # 打印警告消息
return sameFile
return sameFile # 返回文件长度检查结果
def fileToSqlQueries(self, fcEncodedList):
"""
Called by MySQL and PostgreSQL plugins to write a file on the
back-end DBMS underlying file system
"""
将编码后的文件内容转换为 SQL 查询语句用于 MySQL PostgreSQL
Args:
fcEncodedList (list): 编码后的文件内容列表
counter = 0
sqlQueries = []
Returns:
list: SQL 查询语句列表
"""
counter = 0 # 初始化计数器
sqlQueries = [] # 初始化 SQL 查询语句列表
for fcEncodedLine in fcEncodedList:
for fcEncodedLine in fcEncodedList: # 遍历编码后的文件内容列表
if counter == 0:
# 如果是第一个编码行
sqlQueries.append("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, fcEncodedLine))
# 将带有编码数据的插入语句添加到 SQL 查询列表中
else:
# 如果不是第一个编码行
updatedField = agent.simpleConcatenate(self.tblField, fcEncodedLine)
# 构建更新语句,将编码行添加到数据字段中
sqlQueries.append("UPDATE %s SET %s=%s" % (self.fileTblName, self.tblField, updatedField))
# 将更新语句添加到 SQL 查询列表中
counter += 1
counter += 1 # 计数器加 1
return sqlQueries
return sqlQueries # 返回 SQL 查询语句列表
def fileEncode(self, fileName, encoding, single, chunkSize=256):
"""
Called by MySQL and PostgreSQL plugins to write a file on the
back-end DBMS underlying file system
"""
读取文件内容并进行编码
Args:
fileName (str): 文件路径
encoding (str): 编码方式例如 "hex""base64" 或其他编码
single (bool): 是否将所有内容编码为单行
chunkSize (int, optional): 分块大小. Defaults to 256.
checkFile(fileName)
Returns:
list: 编码后的文件内容列表
"""
checkFile(fileName) # 检查文件是否存在
with open(fileName, "rb") as f:
content = f.read()
# 打开文件进行读取
content = f.read() # 读取文件内容
return self.fileContentEncode(content, encoding, single, chunkSize)
return self.fileContentEncode(content, encoding, single, chunkSize) # 返回编码后的文件内容
def fileContentEncode(self, content, encoding, single, chunkSize=256):
retVal = []
"""
对文件内容进行编码
Args:
content (bytes): 文件内容
encoding (str): 编码方式例如 "hex""base64" 或其他编码
single (bool): 是否将所有内容编码为单行
chunkSize (int, optional): 分块大小. Defaults to 256.
Returns:
list: 编码后的文件内容列表
"""
retVal = [] # 初始化返回列表
if encoding == "hex":
content = encodeHex(content)
# 如果编码方式为 "hex"
content = encodeHex(content) # 将文件内容进行十六进制编码
elif encoding == "base64":
content = encodeBase64(content)
# 如果编码方式为 "base64"
content = encodeBase64(content) # 将文件内容进行 Base64 编码
else:
content = codecs.encode(content, encoding)
# 如果编码方式不是 "hex" 或 "base64"
content = codecs.encode(content, encoding) # 使用指定的编码方式进行编码
content = getText(content).replace("\n", "")
content = getText(content).replace("\
", "") # 将编码后的内容转换为文本,并删除换行符
if not single:
# 如果不是单行编码
if len(content) > chunkSize:
# 如果内容长度大于分块大小
for i in xrange(0, len(content), chunkSize):
_ = content[i:i + chunkSize]
# 按照分块大小进行分块
_ = content[i:i + chunkSize] # 获取当前分块
if encoding == "hex":
_ = "0x%s" % _
# 如果编码方式为 "hex"
_ = "0x%s" % _ # 添加十六进制前缀
elif encoding == "base64":
_ = "'%s'" % _
# 如果编码方式为 "base64"
_ = "'%s'" % _ # 添加单引号
retVal.append(_)
retVal.append(_) # 将当前分块添加到返回列表中
if not retVal:
# 如果返回列表为空
if encoding == "hex":
content = "0x%s" % content
# 如果编码方式为 "hex"
content = "0x%s" % content # 添加十六进制前缀
elif encoding == "base64":
content = "'%s'" % content
# 如果编码方式为 "base64"
content = "'%s'" % content # 添加单引号
retVal = [content]
retVal = [content] # 将编码后的内容添加到返回列表中
return retVal
return retVal # 返回编码后的文件内容列表
def askCheckWrittenFile(self, localFile, remoteFile, forceCheck=False):
choice = None
"""
询问用户是否需要检查写入的文件
Args:
localFile (str): 本地文件路径
remoteFile (str): 远程文件路径
forceCheck (bool, optional): 是否强制检查. Defaults to False.
Returns:
bool: 如果文件写入成功返回 True如果用户选择不检查返回 True否则返回 False
"""
choice = None # 初始化用户选择
if forceCheck is not True:
message = "do you want confirmation that the local file '%s' " % localFile
message += "has been successfully written on the back-end DBMS "
message += "file system ('%s')? [Y/n] " % remoteFile
choice = readInput(message, default='Y', boolean=True)
# 如果不强制检查
message = "do you want confirmation that the local file '%s' " % localFile # 构造询问消息
message += "has been successfully written on the back-end DBMS " # 消息补充
message += "file system ('%s')? [Y/n] " % remoteFile # 消息补充
choice = readInput(message, default='Y', boolean=True) # 读取用户输入
if forceCheck or choice:
return self._checkFileLength(localFile, remoteFile)
# 如果强制检查或者用户选择检查
return self._checkFileLength(localFile, remoteFile) # 调用检查文件长度函数
return True
return True # 如果用户选择不检查,则返回 True
def askCheckReadFile(self, localFile, remoteFile):
"""
询问用户是否需要检查读取的文件
Args:
localFile (str): 本地文件路径
remoteFile (str): 远程文件路径
Returns:
bool: 如果文件读取成功返回 True如果用户选择不检查返回 None
"""
if not kb.bruteMode:
message = "do you want confirmation that the remote file '%s' " % remoteFile
message += "has been successfully downloaded from the back-end "
message += "DBMS file system? [Y/n] "
# 如果不是爆破模式
message = "do you want confirmation that the remote file '%s' " % remoteFile # 构造询问消息
message += "has been successfully downloaded from the back-end " # 消息补充
message += "DBMS file system? [Y/n] " # 消息补充
if readInput(message, default='Y', boolean=True):
return self._checkFileLength(localFile, remoteFile, True)
# 读取用户输入
return self._checkFileLength(localFile, remoteFile, True) # 如果用户选择检查,调用检查文件长度函数
return None
return None # 如果用户选择不检查,则返回 None
def nonStackedReadFile(self, remoteFile):
errMsg = "'nonStackedReadFile' method must be defined "
errMsg += "into the specific DBMS plugin"
raise SqlmapUndefinedMethod(errMsg)
"""
使用非堆叠查询技术读取远程文件需要在子类中实现
Args:
remoteFile (str): 远程文件路径
Raises:
SqlmapUndefinedMethod: 如果没有在子类中实现该方法则抛出该异常
"""
errMsg = "'nonStackedReadFile' method must be defined " # 构造错误消息
errMsg += "into the specific DBMS plugin" # 错误消息补充
raise SqlmapUndefinedMethod(errMsg) # 抛出 SqlmapUndefinedMethod 异常
def stackedReadFile(self, remoteFile):
errMsg = "'stackedReadFile' method must be defined "
errMsg += "into the specific DBMS plugin"
raise SqlmapUndefinedMethod(errMsg)
"""
使用堆叠查询技术读取远程文件需要在子类中实现
Args:
remoteFile (str): 远程文件路径
Raises:
SqlmapUndefinedMethod: 如果没有在子类中实现该方法则抛出该异常
"""
errMsg = "'stackedReadFile' method must be defined " # 构造错误消息
errMsg += "into the specific DBMS plugin" # 错误消息补充
raise SqlmapUndefinedMethod(errMsg) # 抛出 SqlmapUndefinedMethod 异常
def unionWriteFile(self, localFile, remoteFile, fileType, forceCheck=False):
errMsg = "'unionWriteFile' method must be defined "
errMsg += "into the specific DBMS plugin"
raise SqlmapUndefinedMethod(errMsg)
"""
使用 UNION 查询技术写入文件需要在子类中实现
Args:
localFile (str): 本地文件路径
remoteFile (str): 远程文件路径
fileType (str): 文件类型
forceCheck (bool, optional): 是否强制检查. Defaults to False.
Raises:
SqlmapUndefinedMethod: 如果没有在子类中实现该方法则抛出该异常
"""
errMsg = "'unionWriteFile' method must be defined " # 构造错误消息
errMsg += "into the specific DBMS plugin" # 错误消息补充
raise SqlmapUndefinedMethod(errMsg) # 抛出 SqlmapUndefinedMethod 异常
def stackedWriteFile(self, localFile, remoteFile, fileType, forceCheck=False):
errMsg = "'stackedWriteFile' method must be defined "
errMsg += "into the specific DBMS plugin"
raise SqlmapUndefinedMethod(errMsg)
"""
使用堆叠查询技术写入文件需要在子类中实现
Args:
localFile (str): 本地文件路径
remoteFile (str): 远程文件路径
fileType (str): 文件类型
forceCheck (bool, optional): 是否强制检查. Defaults to False.
Raises:
SqlmapUndefinedMethod: 如果没有在子类中实现该方法则抛出该异常
"""
errMsg = "'stackedWriteFile' method must be defined " # 构造错误消息
errMsg += "into the specific DBMS plugin" # 错误消息补充
raise SqlmapUndefinedMethod(errMsg) # 抛出 SqlmapUndefinedMethod 异常
def readFile(self, remoteFile):
localFilePaths = []
"""
读取远程文件
Args:
remoteFile (str): 远程文件路径
Returns:
list: 本地文件路径列表
"""
localFilePaths = [] # 初始化本地文件路径列表
self.checkDbmsOs()
self.checkDbmsOs() # 检查数据库类型和操作系统类型
for remoteFile in remoteFile.split(','):
fileContent = None
kb.fileReadMode = True
# 遍历所有远程文件路径
fileContent = None # 初始化文件内容
kb.fileReadMode = True # 设置文件读取模式为 True
if conf.direct or isStackingAvailable():
# 如果使用直接连接或支持堆叠查询
if isStackingAvailable():
debugMsg = "going to try to read the file with stacked query SQL "
debugMsg += "injection technique"
logger.debug(debugMsg)
# 如果支持堆叠查询
debugMsg = "going to try to read the file with stacked query SQL " # 构造调试消息
debugMsg += "injection technique" # 调试消息补充
logger.debug(debugMsg) # 打印调试消息
fileContent = self.stackedReadFile(remoteFile)
fileContent = self.stackedReadFile(remoteFile) # 使用堆叠查询技术读取文件
elif Backend.isDbms(DBMS.MYSQL):
debugMsg = "going to try to read the file with non-stacked query "
debugMsg += "SQL injection technique"
logger.debug(debugMsg)
# 如果是 MySQL 数据库
debugMsg = "going to try to read the file with non-stacked query " # 构造调试消息
debugMsg += "SQL injection technique" # 调试消息补充
logger.debug(debugMsg) # 打印调试消息
fileContent = self.nonStackedReadFile(remoteFile)
fileContent = self.nonStackedReadFile(remoteFile) # 使用非堆叠查询技术读取文件
else:
errMsg = "none of the SQL injection techniques detected can "
errMsg += "be used to read files from the underlying file "
errMsg += "system of the back-end %s server" % Backend.getDbms()
logger.error(errMsg)
# 如果无法使用以上技术读取文件
errMsg = "none of the SQL injection techniques detected can " # 构造错误消息
errMsg += "be used to read files from the underlying file " # 错误消息补充
errMsg += "system of the back-end %s server" % Backend.getDbms() # 错误消息补充
logger.error(errMsg) # 打印错误消息
fileContent = None
fileContent = None # 将文件内容设置为 None
kb.fileReadMode = False
kb.fileReadMode = False # 设置文件读取模式为 False
if fileContent in (None, "") and not Backend.isDbms(DBMS.PGSQL):
self.cleanup(onlyFileTbl=True)
# 如果文件内容为空并且不是 PostgreSQL 数据库
self.cleanup(onlyFileTbl=True) # 清理文件表
elif isListLike(fileContent):
newFileContent = ""
# 如果文件内容是一个列表
newFileContent = "" # 初始化新的文件内容
for chunk in fileContent:
# 遍历文件内容中的块
if isListLike(chunk):
# 如果块本身是一个列表
if len(chunk) > 0:
chunk = chunk[0]
# 如果块列表不为空
chunk = chunk[0] # 获取块列表的第一个元素
else:
chunk = ""
# 如果块列表为空
chunk = "" # 将块设置为空字符串
if chunk:
newFileContent += chunk
# 如果块不为空
newFileContent += chunk # 将块添加到新的文件内容中
fileContent = newFileContent
fileContent = newFileContent # 将新的文件内容赋值给 fileContent
if fileContent is not None:
fileContent = decodeDbmsHexValue(fileContent, True)
# 如果文件内容不为空
fileContent = decodeDbmsHexValue(fileContent, True) # 解码文件内容
if fileContent.strip():
localFilePath = dataToOutFile(remoteFile, fileContent)
# 如果文件内容不为空
localFilePath = dataToOutFile(remoteFile, fileContent) # 将文件内容写入本地文件
if not Backend.isDbms(DBMS.PGSQL):
self.cleanup(onlyFileTbl=True)
# 如果不是 PostgreSQL 数据库
self.cleanup(onlyFileTbl=True) # 清理文件表
sameFile = self.askCheckReadFile(localFilePath, remoteFile)
sameFile = self.askCheckReadFile(localFilePath, remoteFile) # 询问用户是否需要检查读取的文件
if sameFile is True:
localFilePath += " (same file)"
# 如果文件相同
localFilePath += " (same file)" # 添加 (same file) 后缀
elif sameFile is False:
localFilePath += " (size differs from remote file)"
# 如果文件大小不同
localFilePath += " (size differs from remote file)" # 添加 (size differs from remote file) 后缀
localFilePaths.append(localFilePath)
localFilePaths.append(localFilePath) # 将本地文件路径添加到列表中
elif not kb.bruteMode:
errMsg = "no data retrieved"
logger.error(errMsg)
# 如果文件内容为空并且不是爆破模式
errMsg = "no data retrieved" # 构造错误消息
logger.error(errMsg) # 打印错误消息
return localFilePaths
return localFilePaths # 返回本地文件路径列表
def writeFile(self, localFile, remoteFile, fileType=None, forceCheck=False):
written = False
"""
写入本地文件到远程服务器
Args:
localFile (str): 本地文件路径
remoteFile (str): 远程文件路径
fileType (str, optional): 文件类型. Defaults to None.
forceCheck (bool, optional): 是否强制检查文件长度. Defaults to False.
Returns:
bool: 如果文件写入成功则返回 True否则返回 False
"""
written = False # 初始化写入状态
checkFile(localFile)
checkFile(localFile) # 检查本地文件是否存在
self.checkDbmsOs()
self.checkDbmsOs() # 检查数据库类型和操作系统类型
if localFile.endswith('_'):
localFile = getUnicode(decloakToTemp(localFile))
# 如果本地文件名以 '_' 结尾
localFile = getUnicode(decloakToTemp(localFile)) # 将伪装的文件名转换为临时文件路径
if conf.direct or isStackingAvailable():
# 如果使用直接连接或者支持堆叠查询技术
if isStackingAvailable():
debugMsg = "going to upload the file '%s' with " % fileType
debugMsg += "stacked query technique"
logger.debug(debugMsg)
# 如果支持堆叠查询技术
debugMsg = "going to upload the file '%s' with " % fileType # 构造调试消息
debugMsg += "stacked query technique" # 调试消息补充
logger.debug(debugMsg) # 打印调试信息
written = self.stackedWriteFile(localFile, remoteFile, fileType, forceCheck)
self.cleanup(onlyFileTbl=True)
written = self.stackedWriteFile(localFile, remoteFile, fileType, forceCheck) # 使用堆叠查询技术写入文件
self.cleanup(onlyFileTbl=True) # 清理临时表
elif isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION) and Backend.isDbms(DBMS.MYSQL):
debugMsg = "going to upload the file '%s' with " % fileType
debugMsg += "UNION query technique"
logger.debug(debugMsg)
# 如果支持 UNION 查询技术并且是 MySQL 数据库
debugMsg = "going to upload the file '%s' with " % fileType # 构造调试信息
debugMsg += "UNION query technique" # 调试消息补充
logger.debug(debugMsg) # 打印调试信息
written = self.unionWriteFile(localFile, remoteFile, fileType, forceCheck)
written = self.unionWriteFile(localFile, remoteFile, fileType, forceCheck) # 使用 UNION 查询技术写入文件
elif Backend.isDbms(DBMS.MYSQL):
debugMsg = "going to upload the file '%s' with " % fileType
debugMsg += "LINES TERMINATED BY technique"
logger.debug(debugMsg)
# 如果是 MySQL 数据库
debugMsg = "going to upload the file '%s' with " % fileType # 构造调试信息
debugMsg += "LINES TERMINATED BY technique" # 调试消息补充
logger.debug(debugMsg) # 打印调试信息
written = self.linesTerminatedWriteFile(localFile, remoteFile, fileType, forceCheck)
written = self.linesTerminatedWriteFile(localFile, remoteFile, fileType, forceCheck) # 使用 LINES TERMINATED BY 技术写入文件
else:
errMsg = "none of the SQL injection techniques detected can "
errMsg += "be used to write files to the underlying file "
errMsg += "system of the back-end %s server" % Backend.getDbms()
logger.error(errMsg)
# 如果以上技术都无法使用
errMsg = "none of the SQL injection techniques detected can " # 构造错误消息
errMsg += "be used to write files to the underlying file " # 错误消息补充
errMsg += "system of the back-end %s server" % Backend.getDbms() # 错误消息补充
logger.error(errMsg) # 打印错误消息
return None
return None # 返回 None
return written
return written # 返回写入状态
Loading…
Cancel
Save