#!/usr/bin/env python """ Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/) See the file 'LICENSE' for copying permission """ import re from xml.sax.handler import ContentHandler from lib.core.common import Backend from lib.core.common import parseXmlFile from lib.core.common import sanitizeStr from lib.core.data import kb from lib.core.data import paths from lib.core.enums import DBMS from lib.parse.handler import FingerprintHandler class MSSQLBannerHandler(ContentHandler): """ This class defines methods to parse and extract information from the given Microsoft SQL Server banner based upon the data in XML file """ def __init__(self, banner, info): ContentHandler.__init__(self) # 初始化banner self._banner = sanitizeStr(banner or "") # 初始化是否在version标签中 self._inVersion = False # 初始化是否在servicepack标签中 self._inServicePack = False # 初始化release self._release = None # 初始化version self._version = "" # 初始化versionAlt self._versionAlt = None # 初始化servicePack self._servicePack = "" # 初始化info self._info = info def _feedInfo(self, key, value): value = sanitizeStr(value) if value in (None, "None"): return self._info[key] = value def startElement(self, name, attrs): # 如果标签名为signatures,则获取release属性 if name == "signatures": self._release = sanitizeStr(attrs.get("release")) # 如果标签名为version,则设置_inVersion为True elif name == "version": self._inVersion = True # 如果标签名为servicepack,则设置_inServicePack为True elif name == "servicepack": self._inServicePack = True def characters(self, content): # 如果在version标签中,则将content添加到_version中 if self._inVersion: self._version += sanitizeStr(content) # 如果在servicepack标签中,则将content添加到_servicePack中 elif self._inServicePack: self._servicePack += sanitizeStr(content) def endElement(self, name): # 如果标签名为signature,则进行匹配 if name == "signature": for version in (self._version, self._versionAlt): # 如果version不为空,且banner不为空,且banner中包含version,则将release、version、servicePack添加到info中 if version and self._banner and re.search(r" %s[\.\ ]+" % re.escape(version), self._banner): self._feedInfo("dbmsRelease", self._release) self._feedInfo("dbmsVersion", self._version) self._feedInfo("dbmsServicePack", self._servicePack) break # 重置version、versionAlt、servicePack self._version = "" self._versionAlt = None self._servicePack = "" # 如果标签名为version,则将_version中的空格去除,并尝试匹配 elif name == "version": self._inVersion = False self._version = self._version.replace(" ", "") # 尝试匹配 match = re.search(r"\A(?P\d+)\.00\.(?P\d+)\Z", self._version) # 如果匹配成功,则将versionAlt设置为"%s.0.%s.0" % (match.group('major'), match.group('build')) self._versionAlt = "%s.0.%s.0" % (match.group('major'), match.group('build')) if match else None # 如果标签名为servicepack,则将_servicePack中的空格去除 elif name == "servicepack": self._inServicePack = False self._servicePack = self._servicePack.replace(" ", "") def bannerParser(banner): """ This function calls a class to extract information from the given DBMS banner based upon the data in XML file """ xmlfile = None # 如果数据库类型为MSSQL,则设置xmlfile为paths.MSSQL_XML if Backend.isDbms(DBMS.MSSQL): xmlfile = paths.MSSQL_XML # 如果数据库类型为MYSQL,则设置xmlfile为paths.MYSQL_XML elif Backend.isDbms(DBMS.MYSQL): xmlfile = paths.MYSQL_XML # 如果数据库类型为ORACLE,则设置xmlfile为paths.ORACLE_XML elif Backend.isDbms(DBMS.ORACLE): xmlfile = paths.ORACLE_XML # 如果数据库类型为PGSQL,则设置xmlfile为paths.PGSQL_XML elif Backend.isDbms(DBMS.PGSQL): xmlfile = paths.PGSQL_XML # 如果xmlfile为空,则返回 if not xmlfile: return # 如果数据库类型为MSSQL,则使用MSSQLBannerHandler解析xmlfile,并使用FingerprintHandler解析paths.GENERIC_XML if Backend.isDbms(DBMS.MSSQL): handler = MSSQLBannerHandler(banner, kb.bannerFp) parseXmlFile(xmlfile, handler) handler = FingerprintHandler(banner, kb.bannerFp) parseXmlFile(paths.GENERIC_XML, handler) # 否则,使用FingerprintHandler解析xmlfile和paths.GENERIC_XML else: handler = FingerprintHandler(banner, kb.bannerFp) parseXmlFile(xmlfile, handler) parseXmlFile(paths.GENERIC_XML, handler)