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