代码批注

wangshenghui_new_branch
Warmlight 1 month ago
parent 97d70fe02a
commit 138eb2afc6

@ -5,13 +5,15 @@ Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
import copy # 导入必要的模块
import threading import copy # 导入 copy 模块,用于对象复制
import types import threading # 导入 threading 模块,用于线程同步
import types # 导入 types 模块,用于类型判断
from thirdparty.odict import OrderedDict from thirdparty.odict import OrderedDict # 导入 thirdparty 中的 OrderedDict 类,用于实现有序字典
from thirdparty.six.moves import collections_abc as _collections from thirdparty.six.moves import collections_abc as _collections # 导入 six 库中的 collections_abc 模块,用于抽象集合类
# 定义 AttribDict 类,继承自 dict允许以属性方式访问字典成员
class AttribDict(dict): class AttribDict(dict):
""" """
This class defines the dictionary with added capability to access members as attributes This class defines the dictionary with added capability to access members as attributes
@ -22,20 +24,20 @@ class AttribDict(dict):
1 1
""" """
# 初始化方法,接受一个字典 indict一个属性 attribute 和一个布尔值 keycheck
def __init__(self, indict=None, attribute=None, keycheck=True): def __init__(self, indict=None, attribute=None, keycheck=True):
if indict is None: if indict is None: # 如果 indict 为空,初始化为空字典
indict = {} indict = {}
# Set any attributes here - before initialisation # 设置属性,这些属性在初始化前是普通属性
# these remain as normal attributes
self.attribute = attribute self.attribute = attribute
self.keycheck = keycheck self.keycheck = keycheck
dict.__init__(self, indict) dict.__init__(self, indict) # 调用 dict 的初始化方法
self.__initialised = True self.__initialised = True # 设置初始化完成标志
# After initialisation, setting attributes # 在初始化之后,设置属性与设置字典项相同
# is the same as setting an item
# 定义 __getattr__ 方法,用于获取属性
def __getattr__(self, item): def __getattr__(self, item):
""" """
Maps values to attributes Maps values to attributes
@ -43,89 +45,95 @@ class AttribDict(dict):
""" """
try: try:
return self.__getitem__(item) return self.__getitem__(item) # 尝试获取字典项
except KeyError: except KeyError: # 如果字典中不存在此键
if self.keycheck: if self.keycheck: # 如果 keycheck 为 True
raise AttributeError("unable to access item '%s'" % item) raise AttributeError("unable to access item '%s'" % item) # 抛出属性错误
else: else: # 如果 keycheck 为 False
return None return None # 返回 None
# 定义 __delattr__ 方法,用于删除属性
def __delattr__(self, item): def __delattr__(self, item):
""" """
Deletes attributes Deletes attributes
""" """
try: try:
return self.pop(item) return self.pop(item) # 尝试从字典中删除项
except KeyError: except KeyError: # 如果字典中不存在此键
if self.keycheck: if self.keycheck: # 如果 keycheck 为 True
raise AttributeError("unable to access item '%s'" % item) raise AttributeError("unable to access item '%s'" % item) # 抛出属性错误
else: else: # 如果 keycheck 为 False
return None return None # 返回 None
# 定义 __setattr__ 方法,用于设置属性
def __setattr__(self, item, value): def __setattr__(self, item, value):
""" """
Maps attributes to values Maps attributes to values
Only if we are initialised Only if we are initialised
""" """
# This test allows attributes to be set in the __init__ method # 在初始化方法中允许设置属性
if "_AttribDict__initialised" not in self.__dict__: if "_AttribDict__initialised" not in self.__dict__:
return dict.__setattr__(self, item, value) return dict.__setattr__(self, item, value)
# Any normal attributes are handled normally # 正常处理普通属性
elif item in self.__dict__: elif item in self.__dict__:
dict.__setattr__(self, item, value) dict.__setattr__(self, item, value)
else: else: # 其他情况,将属性映射到字典项
self.__setitem__(item, value) self.__setitem__(item, value)
# 定义 __getstate__ 方法,用于支持序列化
def __getstate__(self): def __getstate__(self):
return self.__dict__ return self.__dict__
# 定义 __setstate__ 方法,用于支持反序列化
def __setstate__(self, dict): def __setstate__(self, dict):
self.__dict__ = dict self.__dict__ = dict
# 定义 __deepcopy__ 方法,用于深拷贝
def __deepcopy__(self, memo): def __deepcopy__(self, memo):
retVal = self.__class__() retVal = self.__class__() # 创建一个新实例
memo[id(self)] = retVal memo[id(self)] = retVal # 将新实例添加到 memo 中
for attr in dir(self): for attr in dir(self): # 遍历所有属性
if not attr.startswith('_'): if not attr.startswith('_'): # 忽略私有属性
value = getattr(self, attr) value = getattr(self, attr) # 获取属性值
if not isinstance(value, (types.BuiltinFunctionType, types.FunctionType, types.MethodType)): if not isinstance(value, (types.BuiltinFunctionType, types.FunctionType, types.MethodType)): # 忽略内置函数、函数和方法
setattr(retVal, attr, copy.deepcopy(value, memo)) setattr(retVal, attr, copy.deepcopy(value, memo)) # 深拷贝属性值
for key, value in self.items(): for key, value in self.items(): # 遍历所有字典项
retVal.__setitem__(key, copy.deepcopy(value, memo)) retVal.__setitem__(key, copy.deepcopy(value, memo)) # 深拷贝字典项
return retVal return retVal # 返回深拷贝后的实例
# 定义 InjectionDict 类,继承自 AttribDict用于存储注入相关信息
class InjectionDict(AttribDict): class InjectionDict(AttribDict):
def __init__(self): def __init__(self):
AttribDict.__init__(self) AttribDict.__init__(self) # 调用 AttribDict 的初始化方法
self.place = None # 初始化注入信息
self.parameter = None self.place = None # 注入位置
self.ptype = None self.parameter = None # 注入参数
self.prefix = None self.ptype = None # 参数类型
self.suffix = None self.prefix = None # 前缀
self.clause = None self.suffix = None # 后缀
self.notes = [] # Note: https://github.com/sqlmapproject/sqlmap/issues/1888 self.clause = None # 子句
self.notes = [] # 备注列表
# data is a dict with various stype, each which is a dict with
# all the information specific for that stype # data 字典存储不同类型的注入数据
self.data = AttribDict() self.data = AttribDict()
# conf is a dict which stores current snapshot of important # conf 字典存储检测期间使用的重要选项的快照
# options used during detection
self.conf = AttribDict() self.conf = AttribDict()
self.dbms = None self.dbms = None # 数据库类型
self.dbms_version = None self.dbms_version = None # 数据库版本
self.os = None self.os = None # 操作系统
# Reference: https://www.kunxi.org/2014/05/lru-cache-in-python # 定义 LRUDict 类,实现 LRU 缓存字典
# 参考https://www.kunxi.org/2014/05/lru-cache-in-python
class LRUDict(object): class LRUDict(object):
""" """
This class defines the LRU dictionary This class defines the LRU dictionary
@ -141,40 +149,41 @@ class LRUDict(object):
""" """
def __init__(self, capacity): def __init__(self, capacity):
self.capacity = capacity self.capacity = capacity # 设置缓存容量
self.cache = OrderedDict() self.cache = OrderedDict() # 使用 OrderedDict 作为缓存
self.__lock = threading.Lock() self.__lock = threading.Lock() # 创建一个锁,用于线程同步
def __len__(self): def __len__(self):
return len(self.cache) return len(self.cache) # 返回缓存长度
def __contains__(self, key): def __contains__(self, key):
return key in self.cache return key in self.cache # 判断键是否存在于缓存中
def __getitem__(self, key): def __getitem__(self, key):
value = self.cache.pop(key) value = self.cache.pop(key) # 将键从缓存中移除
self.cache[key] = value self.cache[key] = value # 将键添加回缓存,移动到最后
return value return value # 返回键的值
def get(self, key): def get(self, key):
return self.__getitem__(key) return self.__getitem__(key) # 获取键的值
def __setitem__(self, key, value): def __setitem__(self, key, value):
with self.__lock: with self.__lock: # 获取锁,保证线程安全
try: try:
self.cache.pop(key) self.cache.pop(key) # 尝试从缓存中删除键
except KeyError: except KeyError: # 如果键不存在
if len(self.cache) >= self.capacity: if len(self.cache) >= self.capacity: # 如果缓存已满
self.cache.popitem(last=False) self.cache.popitem(last=False) # 删除最老的项
self.cache[key] = value self.cache[key] = value # 将键值添加到缓存中
def set(self, key, value): def set(self, key, value):
self.__setitem__(key, value) self.__setitem__(key, value) # 设置键值
def keys(self): def keys(self):
return self.cache.keys() return self.cache.keys() # 返回缓存的所有键
# Reference: https://code.activestate.com/recipes/576694/ # 定义 OrderedSet 类,实现有序集合
# 参考https://code.activestate.com/recipes/576694/
class OrderedSet(_collections.MutableSet): class OrderedSet(_collections.MutableSet):
""" """
This class defines the set with ordered (as added) items This class defines the set with ordered (as added) items
@ -192,57 +201,57 @@ class OrderedSet(_collections.MutableSet):
""" """
def __init__(self, iterable=None): def __init__(self, iterable=None):
self.end = end = [] self.end = end = [] # 创建哨兵节点
end += [None, end, end] # sentinel node for doubly linked list end += [None, end, end] # 双向链表的哨兵节点
self.map = {} # key --> [key, prev, next] self.map = {} # 存储键值和链表节点的映射
if iterable is not None: if iterable is not None:
self |= iterable self |= iterable # 添加可迭代对象
def __len__(self): def __len__(self):
return len(self.map) return len(self.map) # 返回集合长度
def __contains__(self, key): def __contains__(self, key):
return key in self.map return key in self.map # 判断键是否存在于集合中
def add(self, value): def add(self, value):
if value not in self.map: if value not in self.map: # 如果值不在集合中
end = self.end end = self.end
curr = end[1] curr = end[1]
curr[2] = end[1] = self.map[value] = [value, curr, end] curr[2] = end[1] = self.map[value] = [value, curr, end] # 添加新节点到链表尾部
def discard(self, value): def discard(self, value):
if value in self.map: if value in self.map: # 如果值在集合中
value, prev, next = self.map.pop(value) value, prev, next = self.map.pop(value) # 移除节点
prev[2] = next prev[2] = next # 更新链表
next[1] = prev next[1] = prev
def __iter__(self): def __iter__(self):
end = self.end end = self.end
curr = end[2] curr = end[2] # 从链表头开始遍历
while curr is not end: while curr is not end:
yield curr[0] yield curr[0]
curr = curr[2] curr = curr[2] # 移动到下一个节点
def __reversed__(self): def __reversed__(self):
end = self.end end = self.end
curr = end[1] curr = end[1] # 从链表尾开始遍历
while curr is not end: while curr is not end:
yield curr[0] yield curr[0]
curr = curr[1] curr = curr[1] # 移动到上一个节点
def pop(self, last=True): def pop(self, last=True):
if not self: if not self: # 如果集合为空
raise KeyError('set is empty') raise KeyError('set is empty')
key = self.end[1][0] if last else self.end[2][0] key = self.end[1][0] if last else self.end[2][0] # 获取最后一个或第一个元素
self.discard(key) self.discard(key) # 移除元素
return key return key # 返回元素值
def __repr__(self): def __repr__(self):
if not self: if not self: # 如果集合为空
return '%s()' % (self.__class__.__name__,) return '%s()' % (self.__class__.__name__,)
return '%s(%r)' % (self.__class__.__name__, list(self)) return '%s(%r)' % (self.__class__.__name__, list(self)) # 返回字符串表示
def __eq__(self, other): def __eq__(self, other):
if isinstance(other, OrderedSet): if isinstance(other, OrderedSet): # 如果另一个对象是有序集合
return len(self) == len(other) and list(self) == list(other) return len(self) == len(other) and list(self) == list(other) # 比较长度和内容
return set(self) == set(other) return set(self) == set(other) # 比较集合内容

@ -5,89 +5,96 @@ Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
from lib.core.common import Backend # 导入必要的模块
from lib.core.common import Format from lib.core.common import Backend # 导入 Backend 类,用于访问后端数据库信息
from lib.core.convert import getUnicode from lib.core.common import Format # 导入 Format 类,用于格式化输出信息
from lib.core.data import conf from lib.core.convert import getUnicode # 导入 getUnicode 函数,用于获取 Unicode 字符串
from lib.core.data import kb from lib.core.data import conf # 导入 conf 对象,用于访问全局配置信息
from lib.core.data import logger from lib.core.data import kb # 导入 kb 对象,用于访问全局知识库
from lib.core.enums import DBMS from lib.core.data import logger # 导入 logger 对象,用于输出日志
from lib.core.enums import OS from lib.core.enums import DBMS # 导入 DBMS 枚举,定义数据库管理系统类型
from lib.core.session import setDbms from lib.core.enums import OS # 导入 OS 枚举,定义操作系统类型
from lib.core.settings import MSSQL_ALIASES from lib.core.session import setDbms # 导入 setDbms 函数,用于设置数据库类型
from lib.request import inject from lib.core.settings import MSSQL_ALIASES # 导入 MSSQL_ALIASES 常量,定义 SQL Server 的别名
from plugins.generic.fingerprint import Fingerprint as GenericFingerprint from lib.request import inject # 导入 inject 函数,用于执行 SQL 注入请求
from plugins.generic.fingerprint import Fingerprint as GenericFingerprint # 导入 GenericFingerprint 类,作为当前类的父类
# 定义 Fingerprint 类,继承自 GenericFingerprint
class Fingerprint(GenericFingerprint): class Fingerprint(GenericFingerprint):
# 初始化 Fingerprint 类,设置数据库类型为 MSSQL
def __init__(self): def __init__(self):
GenericFingerprint.__init__(self, DBMS.MSSQL) GenericFingerprint.__init__(self, DBMS.MSSQL)
# 定义 getFingerprint 方法,用于获取数据库指纹信息
def getFingerprint(self): def getFingerprint(self):
value = "" value = "" # 初始化指纹信息字符串
wsOsFp = Format.getOs("web server", kb.headersFp) wsOsFp = Format.getOs("web server", kb.headersFp) # 获取 Web 服务器操作系统信息
if wsOsFp: if wsOsFp:
value += "%s\n" % wsOsFp value += "%s\
" % wsOsFp # 将 Web 服务器操作系统信息添加到指纹信息
if kb.data.banner: if kb.data.banner: # 如果存在数据库 banner 信息
dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) # 获取数据库操作系统信息
if dbmsOsFp: if dbmsOsFp:
value += "%s\n" % dbmsOsFp value += "%s\
" % dbmsOsFp # 将数据库操作系统信息添加到指纹信息
value += "back-end DBMS: " value += "back-end DBMS: " # 添加数据库类型标签
actVer = Format.getDbms() actVer = Format.getDbms() # 获取数据库类型
if not conf.extensiveFp: if not conf.extensiveFp: # 如果不需要详细指纹信息
value += actVer value += actVer # 将数据库类型添加到指纹信息
return value return value # 返回指纹信息
blank = " " * 15 blank = " " * 15 # 定义缩进空格
value += "active fingerprint: %s" % actVer value += "active fingerprint: %s" % actVer # 添加当前指纹信息
if kb.bannerFp: if kb.bannerFp: # 如果存在数据库 banner 信息
release = kb.bannerFp.get("dbmsRelease") release = kb.bannerFp.get("dbmsRelease") # 获取数据库版本发布信息
version = kb.bannerFp.get("dbmsVersion") version = kb.bannerFp.get("dbmsVersion") # 获取数据库版本信息
servicepack = kb.bannerFp.get("dbmsServicePack") servicepack = kb.bannerFp.get("dbmsServicePack") # 获取数据库服务包信息
if release and version and servicepack: if release and version and servicepack: # 如果所有信息都存在
banVer = "%s %s " % (DBMS.MSSQL, release) banVer = "%s %s " % (DBMS.MSSQL, release) # 构建 banner 版本信息
banVer += "Service Pack %s " % servicepack banVer += "Service Pack %s " % servicepack # 添加服务包信息
banVer += "version %s" % version banVer += "version %s" % version # 添加版本信息
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) value += "\
%sbanner parsing fingerprint: %s" % (blank, banVer) # 将 banner 版本信息添加到指纹信息
htmlErrorFp = Format.getErrorParsedDBMSes() htmlErrorFp = Format.getErrorParsedDBMSes() # 获取 HTML 错误信息中的数据库信息
if htmlErrorFp: if htmlErrorFp:
value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) value += "\
%shtml error message fingerprint: %s" % (blank, htmlErrorFp) # 将 HTML 错误信息中的数据库信息添加到指纹信息
return value return value # 返回指纹信息
# 定义 checkDbms 方法,用于检查数据库类型是否为 MSSQL
def checkDbms(self): def checkDbms(self):
if not conf.extensiveFp and Backend.isDbmsWithin(MSSQL_ALIASES): if not conf.extensiveFp and Backend.isDbmsWithin(MSSQL_ALIASES): # 如果不需要详细指纹并且数据库别名匹配
setDbms("%s %s" % (DBMS.MSSQL, Backend.getVersion())) setDbms("%s %s" % (DBMS.MSSQL, Backend.getVersion())) # 设置数据库类型
self.getBanner() # 获取数据库 banner 信息
self.getBanner() Backend.setOs(OS.WINDOWS) # 设置操作系统类型为 Windows
return True # 返回 True
Backend.setOs(OS.WINDOWS)
return True
infoMsg = "testing %s" % DBMS.MSSQL infoMsg = "testing %s" % DBMS.MSSQL # 输出正在测试 MSSQL 的信息
logger.info(infoMsg) logger.info(infoMsg)
# NOTE: SELECT LEN(@@VERSION)=LEN(@@VERSION) FROM DUAL does not # NOTE: SELECT LEN(@@VERSION)=LEN(@@VERSION) FROM DUAL does not
# work connecting directly to the Microsoft SQL Server database # work connecting directly to the Microsoft SQL Server database
if conf.direct: if conf.direct: # 如果是直接连接
result = True result = True # 直接设置为 True
else: else:
result = inject.checkBooleanExpression("UNICODE(SQUARE(NULL)) IS NULL") result = inject.checkBooleanExpression("UNICODE(SQUARE(NULL)) IS NULL") # 使用 SQL 注入检查
if result: if result: # 如果检查结果为 True
infoMsg = "confirming %s" % DBMS.MSSQL infoMsg = "confirming %s" % DBMS.MSSQL # 输出确认是 MSSQL 的信息
logger.info(infoMsg) logger.info(infoMsg)
# 遍历不同的 MSSQL 版本及其检查语句
for version, check in ( for version, check in (
("2022", "CHARINDEX('16.0.',@@VERSION)>0"), ("2022", "CHARINDEX('16.0.',@@VERSION)>0"),
("2019", "CHARINDEX('15.0.',@@VERSION)>0"), ("2019", "CHARINDEX('15.0.',@@VERSION)>0"),
@ -100,48 +107,46 @@ class Fingerprint(GenericFingerprint):
("2005", "XACT_STATE()=XACT_STATE()"), ("2005", "XACT_STATE()=XACT_STATE()"),
("2000", "HOST_NAME()=HOST_NAME()"), ("2000", "HOST_NAME()=HOST_NAME()"),
): ):
result = inject.checkBooleanExpression(check) result = inject.checkBooleanExpression(check) # 使用 SQL 注入检查版本
if result: if result:
Backend.setVersion(version) Backend.setVersion(version) # 设置数据库版本
break break
if Backend.getVersion(): if Backend.getVersion():
setDbms("%s %s" % (DBMS.MSSQL, Backend.getVersion())) setDbms("%s %s" % (DBMS.MSSQL, Backend.getVersion())) # 设置数据库类型和版本
else: else:
setDbms(DBMS.MSSQL) setDbms(DBMS.MSSQL) # 设置数据库类型
self.getBanner() self.getBanner() # 获取数据库 banner 信息
Backend.setOs(OS.WINDOWS) # 设置操作系统类型为 Windows
Backend.setOs(OS.WINDOWS) return True # 返回 True
else: # 如果检查结果为 False
return True warnMsg = "the back-end DBMS is not %s" % DBMS.MSSQL # 输出警告信息
else:
warnMsg = "the back-end DBMS is not %s" % DBMS.MSSQL
logger.warning(warnMsg) logger.warning(warnMsg)
return False # 返回 False
return False # 定义 checkDbmsOs 方法,用于检查数据库操作系统信息
def checkDbmsOs(self, detailed=False): def checkDbmsOs(self, detailed=False):
if Backend.getOs() and Backend.getOsVersion() and Backend.getOsServicePack(): if Backend.getOs() and Backend.getOsVersion() and Backend.getOsServicePack(): # 如果已获取操作系统信息,则直接返回
return return
if not Backend.getOs(): if not Backend.getOs(): # 如果没有获取操作系统信息
Backend.setOs(OS.WINDOWS) Backend.setOs(OS.WINDOWS) # 设置操作系统类型为 Windows
if not detailed: if not detailed: # 如果不需要详细信息,则直接返回
return return
infoMsg = "fingerprinting the back-end DBMS operating system " infoMsg = "fingerprinting the back-end DBMS operating system " # 输出正在获取操作系统版本和服务包的信息
infoMsg += "version and service pack" infoMsg += "version and service pack"
logger.info(infoMsg) logger.info(infoMsg)
infoMsg = "the back-end DBMS operating system is %s" % Backend.getOs() infoMsg = "the back-end DBMS operating system is %s" % Backend.getOs() # 输出操作系统类型
self.createSupportTbl(self.fileTblName, self.tblField, "varchar(1000)") self.createSupportTbl(self.fileTblName, self.tblField, "varchar(1000)") # 创建支持表,用于存储版本信息
inject.goStacked("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, "@@VERSION")) inject.goStacked("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, "@@VERSION")) # 将 @@VERSION 写入支持表
# Reference: https://en.wikipedia.org/wiki/Comparison_of_Microsoft_Windows_versions # 参考:https://en.wikipedia.org/wiki/Comparison_of_Microsoft_Windows_versions
# https://en.wikipedia.org/wiki/Windows_NT#Releases # https://en.wikipedia.org/wiki/Windows_NT#Releases
versions = { versions = {
"NT": ("4.0", (6, 5, 4, 3, 2, 1)), "NT": ("4.0", (6, 5, 4, 3, 2, 1)),
@ -155,50 +160,50 @@ class Fingerprint(GenericFingerprint):
"10 or 11 or 2016 or 2019 or 2022": ("10.0", (0,)) "10 or 11 or 2016 or 2019 or 2022": ("10.0", (0,))
} }
# Get back-end DBMS underlying operating system version # 获取数据库操作系统版本
for version, data in versions.items(): for version, data in versions.items():
query = "EXISTS(SELECT %s FROM %s WHERE %s " % (self.tblField, self.fileTblName, self.tblField) query = "EXISTS(SELECT %s FROM %s WHERE %s " % (self.tblField, self.fileTblName, self.tblField) # 构建查询语句
query += "LIKE '%Windows NT " + data[0] + "%')" query += "LIKE '%Windows NT " + data[0] + "%')" # 添加版本判断条件
result = inject.checkBooleanExpression(query) result = inject.checkBooleanExpression(query) # 使用 SQL 注入检查
if result: if result:
Backend.setOsVersion(version) Backend.setOsVersion(version) # 设置操作系统版本
infoMsg += " %s" % Backend.getOsVersion() infoMsg += " %s" % Backend.getOsVersion() # 将操作系统版本信息添加到日志信息
break break
if not Backend.getOsVersion(): if not Backend.getOsVersion(): # 如果没有获取到操作系统版本
Backend.setOsVersion("2003") Backend.setOsVersion("2003") # 默认设置为 2003
Backend.setOsServicePack(2) Backend.setOsServicePack(2) # 默认设置为服务包 2
warnMsg = "unable to fingerprint the underlying operating " warnMsg = "unable to fingerprint the underlying operating "
warnMsg += "system version, assuming it is Windows " warnMsg += "system version, assuming it is Windows "
warnMsg += "%s Service Pack %d" % (Backend.getOsVersion(), Backend.getOsServicePack()) warnMsg += "%s Service Pack %d" % (Backend.getOsVersion(), Backend.getOsServicePack())
logger.warning(warnMsg) logger.warning(warnMsg)
self.cleanup(onlyFileTbl=True) self.cleanup(onlyFileTbl=True) # 清理支持表
return return
# Get back-end DBMS underlying operating system service pack # 获取操作系统服务包
sps = versions[Backend.getOsVersion()][1] sps = versions[Backend.getOsVersion()][1] # 获取服务包列表
for sp in sps: for sp in sps:
query = "EXISTS(SELECT %s FROM %s WHERE %s " % (self.tblField, self.fileTblName, self.tblField) query = "EXISTS(SELECT %s FROM %s WHERE %s " % (self.tblField, self.fileTblName, self.tblField) # 构建查询语句
query += "LIKE '%Service Pack " + getUnicode(sp) + "%')" query += "LIKE '%Service Pack " + getUnicode(sp) + "%')" # 添加服务包判断条件
result = inject.checkBooleanExpression(query) result = inject.checkBooleanExpression(query) # 使用 SQL 注入检查
if result: if result:
Backend.setOsServicePack(sp) Backend.setOsServicePack(sp) # 设置操作系统服务包
break break
if not Backend.getOsServicePack(): if not Backend.getOsServicePack(): # 如果没有获取到服务包
debugMsg = "assuming the operating system has no service pack" debugMsg = "assuming the operating system has no service pack" # 输出调试信息
logger.debug(debugMsg) logger.debug(debugMsg)
Backend.setOsServicePack(0) Backend.setOsServicePack(0) # 默认设置为服务包 0
if Backend.getOsVersion(): if Backend.getOsVersion():
infoMsg += " Service Pack %d" % Backend.getOsServicePack() infoMsg += " Service Pack %d" % Backend.getOsServicePack() # 将服务包信息添加到日志信息
logger.info(infoMsg) logger.info(infoMsg)
self.cleanup(onlyFileTbl=True) self.cleanup(onlyFileTbl=True) # 清理支持表

@ -5,102 +5,107 @@ Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
from lib.core.common import Backend # 导入必要的模块
from lib.core.common import Format from lib.core.common import Backend # 导入 Backend 类,用于访问后端数据库信息
from lib.core.data import conf from lib.core.common import Format # 导入 Format 类,用于格式化输出信息
from lib.core.data import kb from lib.core.data import conf # 导入 conf 对象,用于访问全局配置信息
from lib.core.data import logger from lib.core.data import kb # 导入 kb 对象,用于访问全局知识库
from lib.core.enums import DBMS from lib.core.data import logger # 导入 logger 对象,用于输出日志
from lib.core.session import setDbms from lib.core.enums import DBMS # 导入 DBMS 枚举,定义数据库管理系统类型
from lib.core.settings import VERTICA_ALIASES from lib.core.session import setDbms # 导入 setDbms 函数,用于设置数据库类型
from lib.request import inject from lib.core.settings import VERTICA_ALIASES # 导入 VERTICA_ALIASES 常量,定义 Vertica 数据库的别名
from plugins.generic.fingerprint import Fingerprint as GenericFingerprint from lib.request import inject # 导入 inject 函数,用于执行 SQL 注入请求
from plugins.generic.fingerprint import Fingerprint as GenericFingerprint # 导入 GenericFingerprint 类,作为当前类的父类
# 定义 Fingerprint 类,继承自 GenericFingerprint
class Fingerprint(GenericFingerprint): class Fingerprint(GenericFingerprint):
# 初始化 Fingerprint 类,设置数据库类型为 Vertica
def __init__(self): def __init__(self):
GenericFingerprint.__init__(self, DBMS.VERTICA) GenericFingerprint.__init__(self, DBMS.VERTICA)
# 定义 getFingerprint 方法,用于获取数据库指纹信息
def getFingerprint(self): def getFingerprint(self):
value = "" value = "" # 初始化指纹信息字符串
wsOsFp = Format.getOs("web server", kb.headersFp) wsOsFp = Format.getOs("web server", kb.headersFp) # 获取 Web 服务器操作系统信息
if wsOsFp: if wsOsFp:
value += "%s\n" % wsOsFp value += "%s\
" % wsOsFp # 将 Web 服务器操作系统信息添加到指纹信息
if kb.data.banner: if kb.data.banner: # 如果存在数据库 banner 信息
dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) # 获取数据库操作系统信息
if dbmsOsFp: if dbmsOsFp:
value += "%s\n" % dbmsOsFp value += "%s\
" % dbmsOsFp # 将数据库操作系统信息添加到指纹信息
value += "back-end DBMS: " value += "back-end DBMS: " # 添加数据库类型标签
if not conf.extensiveFp: if not conf.extensiveFp: # 如果不需要详细指纹信息
value += DBMS.VERTICA value += DBMS.VERTICA # 将数据库类型添加到指纹信息
return value return value # 返回指纹信息
actVer = Format.getDbms() actVer = Format.getDbms() # 获取数据库类型
blank = " " * 15 blank = " " * 15 # 定义缩进空格
value += "active fingerprint: %s" % actVer value += "active fingerprint: %s" % actVer # 添加当前指纹信息
if kb.bannerFp: if kb.bannerFp: # 如果存在数据库 banner 信息
banVer = kb.bannerFp.get("dbmsVersion") banVer = kb.bannerFp.get("dbmsVersion") # 获取数据库版本信息
if banVer: if banVer:
banVer = Format.getDbms([banVer]) banVer = Format.getDbms([banVer]) # 格式化数据库版本信息
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) value += "\
%sbanner parsing fingerprint: %s" % (blank, banVer) # 将 banner 版本信息添加到指纹信息
htmlErrorFp = Format.getErrorParsedDBMSes() htmlErrorFp = Format.getErrorParsedDBMSes() # 获取 HTML 错误信息中的数据库信息
if htmlErrorFp: if htmlErrorFp:
value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) value += "\
%shtml error message fingerprint: %s" % (blank, htmlErrorFp) # 将 HTML 错误信息中的数据库信息添加到指纹信息
return value return value # 返回指纹信息
# 定义 checkDbms 方法,用于检查数据库类型是否为 Vertica
def checkDbms(self): def checkDbms(self):
if not conf.extensiveFp and Backend.isDbmsWithin(VERTICA_ALIASES): if not conf.extensiveFp and Backend.isDbmsWithin(VERTICA_ALIASES): # 如果不需要详细指纹并且数据库别名匹配
setDbms(DBMS.VERTICA) setDbms(DBMS.VERTICA) # 设置数据库类型为 Vertica
self.getBanner() # 获取数据库 banner 信息
self.getBanner() return True # 返回 True
return True
infoMsg = "testing %s" % DBMS.VERTICA infoMsg = "testing %s" % DBMS.VERTICA # 输出正在测试 Vertica 的信息
logger.info(infoMsg) logger.info(infoMsg)
# NOTE: Vertica works too without the CONVERT_TO() # NOTE: Vertica works too without the CONVERT_TO()
result = inject.checkBooleanExpression("BITSTRING_TO_BINARY(NULL) IS NULL") result = inject.checkBooleanExpression("BITSTRING_TO_BINARY(NULL) IS NULL") # 使用 SQL 注入检查
if result: if result: # 如果检查结果为 True
infoMsg = "confirming %s" % DBMS.VERTICA infoMsg = "confirming %s" % DBMS.VERTICA # 输出确认是 Vertica 的信息
logger.info(infoMsg) logger.info(infoMsg)
result = inject.checkBooleanExpression("HEX_TO_INTEGER(NULL) IS NULL") result = inject.checkBooleanExpression("HEX_TO_INTEGER(NULL) IS NULL") # 使用 SQL 注入检查
if not result: if not result: # 如果检查结果为 False
warnMsg = "the back-end DBMS is not %s" % DBMS.VERTICA warnMsg = "the back-end DBMS is not %s" % DBMS.VERTICA # 输出警告信息
logger.warning(warnMsg) logger.warning(warnMsg)
return False # 返回 False
return False setDbms(DBMS.VERTICA) # 设置数据库类型为 Vertica
self.getBanner() # 获取数据库 banner 信息
setDbms(DBMS.VERTICA) if not conf.extensiveFp: # 如果不需要详细指纹信息
return True # 返回 True
self.getBanner() infoMsg = "actively fingerprinting %s" % DBMS.VERTICA # 输出正在进行详细指纹识别的信息
if not conf.extensiveFp:
return True
infoMsg = "actively fingerprinting %s" % DBMS.VERTICA
logger.info(infoMsg) logger.info(infoMsg)
# 根据 CALENDAR_HIERARCHY_DAY(NULL) 的结果判断 Vertica 版本
if inject.checkBooleanExpression("CALENDAR_HIERARCHY_DAY(NULL) IS NULL"): if inject.checkBooleanExpression("CALENDAR_HIERARCHY_DAY(NULL) IS NULL"):
Backend.setVersion(">= 9.0") Backend.setVersion(">= 9.0") # 设置数据库版本为 >= 9.0
else: else:
Backend.setVersion("< 9.0") Backend.setVersion("< 9.0") # 设置数据库版本为 < 9.0
return True return True # 返回 True
else: else: # 如果检查结果为 False
warnMsg = "the back-end DBMS is not %s" % DBMS.VERTICA warnMsg = "the back-end DBMS is not %s" % DBMS.VERTICA # 输出警告信息
logger.warning(warnMsg) logger.warning(warnMsg)
return False # 返回 False
return False

@ -5,146 +5,107 @@ Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
from __future__ import print_function # 导入必要的模块
from lib.core.common import Backend # 导入 Backend 类,用于访问后端数据库信息
import re from lib.core.common import Format # 导入 Format 类,用于格式化输出信息
import sys from lib.core.data import conf # 导入 conf 对象,用于访问全局配置信息
from lib.core.data import kb # 导入 kb 对象,用于访问全局知识库
from lib.core.common import Backend from lib.core.data import logger # 导入 logger 对象,用于输出日志
from lib.core.common import dataToStdout from lib.core.enums import DBMS # 导入 DBMS 枚举,定义数据库管理系统类型
from lib.core.common import getSQLSnippet from lib.core.session import setDbms # 导入 setDbms 函数,用于设置数据库类型
from lib.core.common import isStackingAvailable from lib.core.settings import VERTICA_ALIASES # 导入 VERTICA_ALIASES 常量,定义 Vertica 数据库的别名
from lib.core.convert import getUnicode from lib.request import inject # 导入 inject 函数,用于执行 SQL 注入请求
from lib.core.data import conf from plugins.generic.fingerprint import Fingerprint as GenericFingerprint # 导入 GenericFingerprint 类,作为当前类的父类
from lib.core.data import logger
from lib.core.dicts import SQL_STATEMENTS # 定义 Fingerprint 类,继承自 GenericFingerprint
from lib.core.enums import AUTOCOMPLETE_TYPE class Fingerprint(GenericFingerprint):
from lib.core.enums import DBMS # 初始化 Fingerprint 类,设置数据库类型为 Vertica
from lib.core.exception import SqlmapNoneDataException
from lib.core.settings import METADB_SUFFIX
from lib.core.settings import NULL
from lib.core.settings import PARAMETER_SPLITTING_REGEX
from lib.core.shell import autoCompletion
from lib.request import inject
from thirdparty.six.moves import input as _input
class Custom(object):
"""
This class defines custom enumeration functionalities for plugins.
"""
def __init__(self): def __init__(self):
pass GenericFingerprint.__init__(self, DBMS.VERTICA)
def sqlQuery(self, query):
output = None
sqlType = None
query = query.rstrip(';')
try: # 定义 getFingerprint 方法,用于获取数据库指纹信息
for sqlTitle, sqlStatements in SQL_STATEMENTS.items(): def getFingerprint(self):
for sqlStatement in sqlStatements: value = "" # 初始化指纹信息字符串
if query.lower().startswith(sqlStatement): wsOsFp = Format.getOs("web server", kb.headersFp) # 获取 Web 服务器操作系统信息
sqlType = sqlTitle
break
if not re.search(r"\b(OPENROWSET|INTO)\b", query, re.I) and (not sqlType or "SELECT" in sqlType): if wsOsFp:
infoMsg = "fetching %s query output: '%s'" % (sqlType if sqlType is not None else "SQL", query) value += "%s\
logger.info(infoMsg) " % wsOsFp # 将 Web 服务器操作系统信息添加到指纹信息
if Backend.isDbms(DBMS.MSSQL): if kb.data.banner: # 如果存在数据库 banner 信息
match = re.search(r"(\bFROM\s+)([^\s]+)", query, re.I) dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) # 获取数据库操作系统信息
if match and match.group(2).count('.') == 1:
query = query.replace(match.group(0), "%s%s" % (match.group(1), match.group(2).replace('.', ".dbo.")))
query = re.sub(r"(?i)\w+%s\.?" % METADB_SUFFIX, "", query) if dbmsOsFp:
value += "%s\
" % dbmsOsFp # 将数据库操作系统信息添加到指纹信息
output = inject.getValue(query, fromUser=True) value += "back-end DBMS: " # 添加数据库类型标签
return output if not conf.extensiveFp: # 如果不需要详细指纹信息
elif not isStackingAvailable() and not conf.direct: value += DBMS.VERTICA # 将数据库类型添加到指纹信息
warnMsg = "execution of non-query SQL statements is only " return value # 返回指纹信息
warnMsg += "available when stacked queries are supported"
logger.warning(warnMsg)
return None actVer = Format.getDbms() # 获取数据库类型
else: blank = " " * 15 # 定义缩进空格
if sqlType: value += "active fingerprint: %s" % actVer # 添加当前指纹信息
infoMsg = "executing %s statement: '%s'" % (sqlType if sqlType is not None else "SQL", query)
else:
infoMsg = "executing unknown SQL command: '%s'" % query
logger.info(infoMsg)
inject.goStacked(query) if kb.bannerFp: # 如果存在数据库 banner 信息
banVer = kb.bannerFp.get("dbmsVersion") # 获取数据库版本信息
output = NULL if banVer:
banVer = Format.getDbms([banVer]) # 格式化数据库版本信息
value += "\
%sbanner parsing fingerprint: %s" % (blank, banVer) # 将 banner 版本信息添加到指纹信息
except SqlmapNoneDataException as ex: htmlErrorFp = Format.getErrorParsedDBMSes() # 获取 HTML 错误信息中的数据库信息
logger.warning(ex)
return output
def sqlShell(self):
infoMsg = "calling %s shell. To quit type " % Backend.getIdentifiedDbms()
infoMsg += "'x' or 'q' and press ENTER"
logger.info(infoMsg)
autoCompletion(AUTOCOMPLETE_TYPE.SQL) if htmlErrorFp:
value += "\
%shtml error message fingerprint: %s" % (blank, htmlErrorFp) # 将 HTML 错误信息中的数据库信息添加到指纹信息
while True: return value # 返回指纹信息
query = None
try: # 定义 checkDbms 方法,用于检查数据库类型是否为 Vertica
query = _input("sql-shell> ") def checkDbms(self):
query = getUnicode(query, encoding=sys.stdin.encoding) if not conf.extensiveFp and Backend.isDbmsWithin(VERTICA_ALIASES): # 如果不需要详细指纹并且数据库别名匹配
query = query.strip("; ") setDbms(DBMS.VERTICA) # 设置数据库类型为 Vertica
except UnicodeDecodeError: self.getBanner() # 获取数据库 banner 信息
print() return True # 返回 True
errMsg = "invalid user input"
logger.error(errMsg)
except KeyboardInterrupt:
print()
errMsg = "user aborted"
logger.error(errMsg)
except EOFError:
print()
errMsg = "exit"
logger.error(errMsg)
break
if not query: infoMsg = "testing %s" % DBMS.VERTICA # 输出正在测试 Vertica 的信息
continue logger.info(infoMsg)
if query.lower() in ("x", "q", "exit", "quit"):
break
output = self.sqlQuery(query)
if output and output != "Quit": # NOTE: Vertica works too without the CONVERT_TO()
conf.dumper.sqlQuery(query, output) result = inject.checkBooleanExpression("BITSTRING_TO_BINARY(NULL) IS NULL") # 使用 SQL 注入检查
elif not output: if result: # 如果检查结果为 True
pass infoMsg = "confirming %s" % DBMS.VERTICA # 输出确认是 Vertica 的信息
logger.info(infoMsg)
elif output != "Quit": result = inject.checkBooleanExpression("HEX_TO_INTEGER(NULL) IS NULL") # 使用 SQL 注入检查
dataToStdout("No output\n")
def sqlFile(self): if not result: # 如果检查结果为 False
infoMsg = "executing SQL statements from given file(s)" warnMsg = "the back-end DBMS is not %s" % DBMS.VERTICA # 输出警告信息
logger.info(infoMsg) logger.warning(warnMsg)
return False # 返回 False
for filename in re.split(PARAMETER_SPLITTING_REGEX, conf.sqlFile): setDbms(DBMS.VERTICA) # 设置数据库类型为 Vertica
filename = filename.strip() self.getBanner() # 获取数据库 banner 信息
if not filename: if not conf.extensiveFp: # 如果不需要详细指纹信息
continue return True # 返回 True
snippet = getSQLSnippet(Backend.getDbms(), filename) infoMsg = "actively fingerprinting %s" % DBMS.VERTICA # 输出正在进行详细指纹识别的信息
logger.info(infoMsg)
if snippet and all(query.strip().upper().startswith("SELECT") for query in (_ for _ in snippet.split(';' if ';' in snippet else '\n') if _)): # 根据 CALENDAR_HIERARCHY_DAY(NULL) 的结果判断 Vertica 版本
for query in (_ for _ in snippet.split(';' if ';' in snippet else '\n') if _): if inject.checkBooleanExpression("CALENDAR_HIERARCHY_DAY(NULL) IS NULL"):
query = query.strip() Backend.setVersion(">= 9.0") # 设置数据库版本为 >= 9.0
if query:
conf.dumper.sqlQuery(query, self.sqlQuery(query))
else: else:
conf.dumper.sqlQuery(snippet, self.sqlQuery(snippet)) Backend.setVersion("< 9.0") # 设置数据库版本为 < 9.0
return True # 返回 True
else: # 如果检查结果为 False
warnMsg = "the back-end DBMS is not %s" % DBMS.VERTICA # 输出警告信息
logger.warning(warnMsg)
return False # 返回 False

@ -5,200 +5,211 @@ Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission See the file 'LICENSE' for copying permission
""" """
import ntpath # 导入必要的模块
import re import ntpath # 导入 ntpath 模块,用于处理 Windows 路径
import re # 导入 re 模块,用于正则表达式
from lib.core.common import Backend
from lib.core.common import hashDBWrite from lib.core.common import Backend # 导入 Backend 类,用于访问后端数据库信息
from lib.core.common import isStackingAvailable from lib.core.common import hashDBWrite # 导入 hashDBWrite 函数,用于写入哈希数据库
from lib.core.common import normalizePath from lib.core.common import isStackingAvailable # 导入 isStackingAvailable 函数,用于检查是否支持堆叠查询
from lib.core.common import ntToPosixSlashes from lib.core.common import normalizePath # 导入 normalizePath 函数,用于规范化路径
from lib.core.common import posixToNtSlashes from lib.core.common import ntToPosixSlashes # 导入 ntToPosixSlashes 函数,用于将 Windows 路径转换为 POSIX 路径
from lib.core.common import readInput from lib.core.common import posixToNtSlashes # 导入 posixToNtSlashes 函数,用于将 POSIX 路径转换为 Windows 路径
from lib.core.common import singleTimeDebugMessage from lib.core.common import readInput # 导入 readInput 函数,用于读取用户输入
from lib.core.common import unArrayizeValue from lib.core.common import singleTimeDebugMessage # 导入 singleTimeDebugMessage 函数,用于输出单次调试信息
from lib.core.data import conf from lib.core.common import unArrayizeValue # 导入 unArrayizeValue 函数,用于将数组值转换为单个值
from lib.core.data import kb from lib.core.data import conf # 导入 conf 对象,用于访问全局配置信息
from lib.core.data import logger from lib.core.data import kb # 导入 kb 对象,用于访问全局知识库
from lib.core.data import queries from lib.core.data import logger # 导入 logger 对象,用于输出日志
from lib.core.enums import DBMS from lib.core.data import queries # 导入 queries 字典,存储数据库查询语句
from lib.core.enums import HASHDB_KEYS from lib.core.enums import DBMS # 导入 DBMS 枚举,定义数据库管理系统类型
from lib.core.enums import OS from lib.core.enums import HASHDB_KEYS # 导入 HASHDB_KEYS 枚举,定义哈希数据库键值
from lib.core.exception import SqlmapNoneDataException from lib.core.enums import OS # 导入 OS 枚举,定义操作系统类型
from lib.request import inject from lib.core.exception import SqlmapNoneDataException # 导入 SqlmapNoneDataException 异常类
from lib.request import inject # 导入 inject 函数,用于执行 SQL 注入请求
# 定义 Miscellaneous 类,用于实现杂项功能
class Miscellaneous(object): class Miscellaneous(object):
""" """
This class defines miscellaneous functionalities for plugins. This class defines miscellaneous functionalities for plugins.
""" """
# 初始化 Miscellaneous 类
def __init__(self): def __init__(self):
pass pass
# 定义 getRemoteTempPath 方法,用于获取远程临时路径
def getRemoteTempPath(self): def getRemoteTempPath(self):
if not conf.tmpPath and Backend.isDbms(DBMS.MSSQL): if not conf.tmpPath and Backend.isDbms(DBMS.MSSQL): # 如果没有设置临时路径且数据库是 MSSQL
debugMsg = "identifying Microsoft SQL Server error log directory " debugMsg = "identifying Microsoft SQL Server error log directory " # 输出调试信息
debugMsg += "that sqlmap will use to store temporary files with " debugMsg += "that sqlmap will use to store temporary files with "
debugMsg += "commands' output" debugMsg += "commands' output"
logger.debug(debugMsg) logger.debug(debugMsg)
_ = unArrayizeValue(inject.getValue("SELECT SERVERPROPERTY('ErrorLogFileName')", safeCharEncode=False)) _ = unArrayizeValue(inject.getValue("SELECT SERVERPROPERTY('ErrorLogFileName')", safeCharEncode=False)) # 获取错误日志文件路径
if _: if _: # 如果获取到路径
conf.tmpPath = ntpath.dirname(_) conf.tmpPath = ntpath.dirname(_) # 设置临时路径为错误日志文件所在的目录
if not conf.tmpPath: if not conf.tmpPath: # 如果没有设置临时路径
if Backend.isOs(OS.WINDOWS): if Backend.isOs(OS.WINDOWS): # 如果操作系统是 Windows
if conf.direct: if conf.direct: # 如果是直接连接
conf.tmpPath = "%TEMP%" conf.tmpPath = "%TEMP%" # 设置临时路径为 %TEMP%
else: else:
self.checkDbmsOs(detailed=True) self.checkDbmsOs(detailed=True) # 检测数据库操作系统
if Backend.getOsVersion() in ("2000", "NT"): if Backend.getOsVersion() in ("2000", "NT"): # 如果是 Windows 2000 或 NT
conf.tmpPath = "C:/WINNT/Temp" conf.tmpPath = "C:/WINNT/Temp" # 设置临时路径
elif Backend.isOs("XP"): elif Backend.isOs("XP"): # 如果是 Windows XP
conf.tmpPath = "C:/Documents and Settings/All Users/Application Data/Temp" conf.tmpPath = "C:/Documents and Settings/All Users/Application Data/Temp" # 设置临时路径
else: else: # 如果是其他 Windows 版本
conf.tmpPath = "C:/Windows/Temp" conf.tmpPath = "C:/Windows/Temp" # 设置临时路径
else: else: # 如果操作系统不是 Windows
conf.tmpPath = "/tmp" conf.tmpPath = "/tmp" # 设置临时路径为 /tmp
if re.search(r"\A[\w]:[\/\\]+", conf.tmpPath, re.I): if re.search(r"\A[\w]:[\/\$$+", conf.tmpPath, re.I): # 如果临时路径是 Windows 格式
Backend.setOs(OS.WINDOWS) Backend.setOs(OS.WINDOWS) # 设置操作系统为 Windows
conf.tmpPath = normalizePath(conf.tmpPath) conf.tmpPath = normalizePath(conf.tmpPath) # 规范化临时路径
conf.tmpPath = ntToPosixSlashes(conf.tmpPath) conf.tmpPath = ntToPosixSlashes(conf.tmpPath) # 将临时路径转换为 POSIX 格式
singleTimeDebugMessage("going to use '%s' as temporary files directory" % conf.tmpPath) singleTimeDebugMessage("going to use '%s' as temporary files directory" % conf.tmpPath) # 输出调试信息
hashDBWrite(HASHDB_KEYS.CONF_TMP_PATH, conf.tmpPath) hashDBWrite(HASHDB_KEYS.CONF_TMP_PATH, conf.tmpPath) # 写入哈希数据库
return conf.tmpPath return conf.tmpPath # 返回临时路径
# 定义 getVersionFromBanner 方法,用于从 banner 中获取数据库版本
def getVersionFromBanner(self): def getVersionFromBanner(self):
if "dbmsVersion" in kb.bannerFp: if "dbmsVersion" in kb.bannerFp: # 如果 banner 中已经有版本信息
return return # 直接返回
infoMsg = "detecting back-end DBMS version from its banner" infoMsg = "detecting back-end DBMS version from its banner" # 输出信息
logger.info(infoMsg) logger.info(infoMsg)
query = queries[Backend.getIdentifiedDbms()].banner.query query = queries[Backend.getIdentifiedDbms()].banner.query # 获取 banner 查询语句
if conf.direct: if conf.direct: # 如果是直接连接
query = "SELECT %s" % query query = "SELECT %s" % query # 添加 SELECT 关键字
kb.bannerFp["dbmsVersion"] = unArrayizeValue(inject.getValue(query)) or "" kb.bannerFp["dbmsVersion"] = unArrayizeValue(inject.getValue(query)) or "" # 获取 banner 信息
match = re.search(r"\d[\d.-]*", kb.bannerFp["dbmsVersion"]) match = re.search(r"\d[\d.-]*", kb.bannerFp["dbmsVersion"]) # 使用正则表达式匹配版本号
if match: if match: # 如果匹配成功
kb.bannerFp["dbmsVersion"] = match.group(0) kb.bannerFp["dbmsVersion"] = match.group(0) # 设置版本号
# 定义 delRemoteFile 方法,用于删除远程文件
def delRemoteFile(self, filename): def delRemoteFile(self, filename):
if not filename: if not filename: # 如果文件名为空
return return # 直接返回
self.checkDbmsOs() self.checkDbmsOs() # 检测数据库操作系统
if Backend.isOs(OS.WINDOWS): if Backend.isOs(OS.WINDOWS): # 如果操作系统是 Windows
filename = posixToNtSlashes(filename) filename = posixToNtSlashes(filename) # 将路径转换为 Windows 格式
cmd = "del /F /Q %s" % filename cmd = "del /F /Q %s" % filename # 构建删除命令
else: else: # 如果操作系统不是 Windows
cmd = "rm -f %s" % filename cmd = "rm -f %s" % filename # 构建删除命令
self.execCmd(cmd, silent=True) self.execCmd(cmd, silent=True) # 执行删除命令
# 定义 createSupportTbl 方法,用于创建支持表
def createSupportTbl(self, tblName, tblField, tblType): def createSupportTbl(self, tblName, tblField, tblType):
inject.goStacked("DROP TABLE %s" % tblName, silent=True) inject.goStacked("DROP TABLE %s" % tblName, silent=True) # 删除表(如果存在)
if Backend.isDbms(DBMS.MSSQL) and tblName == self.cmdTblName: if Backend.isDbms(DBMS.MSSQL) and tblName == self.cmdTblName: # 如果是 MSSQL 并且表名是命令表
inject.goStacked("CREATE TABLE %s(id INT PRIMARY KEY IDENTITY, %s %s)" % (tblName, tblField, tblType)) inject.goStacked("CREATE TABLE %s(id INT PRIMARY KEY IDENTITY, %s %s)" % (tblName, tblField, tblType)) # 创建表,包含自增 id
else: else: # 如果不是 MSSQL 或表名不是命令表
inject.goStacked("CREATE TABLE %s(%s %s)" % (tblName, tblField, tblType)) inject.goStacked("CREATE TABLE %s(%s %s)" % (tblName, tblField, tblType)) # 创建表
# 定义 cleanup 方法,用于清理文件系统和数据库
def cleanup(self, onlyFileTbl=False, udfDict=None, web=False): def cleanup(self, onlyFileTbl=False, udfDict=None, web=False):
""" """
Cleanup file system and database from sqlmap create files, tables Cleanup file system and database from sqlmap create files, tables
and functions and functions
""" """
if web and self.webBackdoorFilePath: if web and self.webBackdoorFilePath: # 如果是 web 模式且有 web 后门文件路径
logger.info("cleaning up the web files uploaded") logger.info("cleaning up the web files uploaded") # 输出信息
self.delRemoteFile(self.webStagerFilePath) self.delRemoteFile(self.webStagerFilePath) # 删除 web stager 文件
self.delRemoteFile(self.webBackdoorFilePath) self.delRemoteFile(self.webBackdoorFilePath) # 删除 web 后门文件
if (not isStackingAvailable() or kb.udfFail) and not conf.direct: if (not isStackingAvailable() or kb.udfFail) and not conf.direct: # 如果不支持堆叠查询或 udf失败且不是直接连接
return return # 直接返回
if any((conf.osCmd, conf.osShell)) and Backend.isDbms(DBMS.PGSQL) and kb.copyExecTest: if any((conf.osCmd, conf.osShell)) and Backend.isDbms(DBMS.PGSQL) and kb.copyExecTest: # 如果执行系统命令/shell 且是 PostgreSQL 且 copyExecTest 为 True
return return # 直接返回
if Backend.isOs(OS.WINDOWS): if Backend.isOs(OS.WINDOWS): # 如果操作系统是 Windows
libtype = "dynamic-link library" libtype = "dynamic-link library" # 设置库类型为动态链接库
elif Backend.isOs(OS.LINUX): elif Backend.isOs(OS.LINUX): # 如果操作系统是 Linux
libtype = "shared object" libtype = "shared object" # 设置库类型为共享对象
else: else: # 如果是其他操作系统
libtype = "shared library" libtype = "shared library" # 设置库类型为共享库
if onlyFileTbl: if onlyFileTbl: # 如果只清理文件表
logger.debug("cleaning up the database management system") logger.debug("cleaning up the database management system") # 输出调试信息
else: else: # 如果清理所有
logger.info("cleaning up the database management system") logger.info("cleaning up the database management system") # 输出信息
logger.debug("removing support tables") logger.debug("removing support tables") # 输出调试信息
inject.goStacked("DROP TABLE %s" % self.fileTblName, silent=True) inject.goStacked("DROP TABLE %s" % self.fileTblName, silent=True) # 删除文件表
inject.goStacked("DROP TABLE %shex" % self.fileTblName, silent=True) inject.goStacked("DROP TABLE %shex" % self.fileTblName, silent=True) # 删除文件表 (hex)
if not onlyFileTbl: if not onlyFileTbl: # 如果不是只清理文件表
inject.goStacked("DROP TABLE %s" % self.cmdTblName, silent=True) inject.goStacked("DROP TABLE %s" % self.cmdTblName, silent=True) # 删除命令表
if Backend.isDbms(DBMS.MSSQL): if Backend.isDbms(DBMS.MSSQL): # 如果是 MSSQL
udfDict = {"master..new_xp_cmdshell": {}} udfDict = {"master..new_xp_cmdshell": {}} # 设置要删除的 udf (xp_cmdshell)
if udfDict is None: if udfDict is None: # 如果 udfDict 为空
udfDict = getattr(self, "sysUdfs", {}) udfDict = getattr(self, "sysUdfs", {}) # 获取系统 udf
for udf, inpRet in udfDict.items(): for udf, inpRet in udfDict.items(): # 遍历 udf
message = "do you want to remove UDF '%s'? [Y/n] " % udf message = "do you want to remove UDF '%s'? [Y/n] " % udf # 输出询问信息
if readInput(message, default='Y', boolean=True): if readInput(message, default='Y', boolean=True): # 获取用户输入
dropStr = "DROP FUNCTION %s" % udf dropStr = "DROP FUNCTION %s" % udf # 构建删除 udf 命令
if Backend.isDbms(DBMS.PGSQL): if Backend.isDbms(DBMS.PGSQL): # 如果是 PostgreSQL
inp = ", ".join(i for i in inpRet["input"]) inp = ", ".join(i for i in inpRet["input"]) # 获取输入参数
dropStr += "(%s)" % inp dropStr += "(%s)" % inp # 添加输入参数到删除命令
logger.debug("removing UDF '%s'" % udf) logger.debug("removing UDF '%s'" % udf) # 输出调试信息
inject.goStacked(dropStr, silent=True) inject.goStacked(dropStr, silent=True) # 删除 udf
logger.info("database management system cleanup finished") logger.info("database management system cleanup finished") # 输出信息
warnMsg = "remember that UDF %s files " % libtype warnMsg = "remember that UDF %s files " % libtype # 构建警告信息
if conf.osPwn: if conf.osPwn: # 如果开启 osPwn 功能
warnMsg += "and Metasploit related files in the temporary " warnMsg += "and Metasploit related files in the temporary " # 添加 Metasploit 相关文件信息
warnMsg += "folder " warnMsg += "folder "
warnMsg += "saved on the file system can only be deleted " warnMsg += "saved on the file system can only be deleted " # 添加手动删除信息
warnMsg += "manually" warnMsg += "manually"
logger.warning(warnMsg) logger.warning(warnMsg) # 输出警告信息
# 定义 likeOrExact 方法,用于选择 LIKE 或精确匹配
def likeOrExact(self, what): def likeOrExact(self, what):
message = "do you want sqlmap to consider provided %s(s):\n" % what message = "do you want sqlmap to consider provided %s(s):\
message += "[1] as LIKE %s names (default)\n" % what " % what # 构建询问信息
message += "[1] as LIKE %s names (default)\
" % what
message += "[2] as exact %s names" % what message += "[2] as exact %s names" % what
choice = readInput(message, default='1') choice = readInput(message, default='1') # 获取用户选择
if not choice or choice == '1': if not choice or choice == '1': # 如果选择 LIKE 匹配
choice = '1' choice = '1'
condParam = " LIKE '%%%s%%'" condParam = " LIKE '%%%s%%'" # 设置 LIKE 条件
elif choice == '2': elif choice == '2': # 如果选择精确匹配
condParam = "='%s'" condParam = "='%s'" # 设置精确匹配条件
else: else: # 如果输入非法
errMsg = "invalid value" errMsg = "invalid value" # 输出错误信息
raise SqlmapNoneDataException(errMsg) raise SqlmapNoneDataException(errMsg) # 抛出异常
return choice, condParam return choice, condParam # 返回选择和条件
Loading…
Cancel
Save