You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sqlmap/src/sqlmap-master/plugins/dbms/mssqlserver/fingerprint.py

209 lines
10 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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