diff --git a/src/sqlmap-master/plugins/dbms/access/fingerprint.py b/src/sqlmap-master/plugins/dbms/access/fingerprint.py index 2ab6394..bd49218 100644 --- a/src/sqlmap-master/plugins/dbms/access/fingerprint.py +++ b/src/sqlmap-master/plugins/dbms/access/fingerprint.py @@ -7,94 +7,109 @@ See the file 'LICENSE' for copying permission import re -from lib.core.common import Backend -from lib.core.common import Format -from lib.core.common import getCurrentThreadData -from lib.core.common import randomStr -from lib.core.common import wasLastResponseDBMSError -from lib.core.data import conf -from lib.core.data import kb -from lib.core.data import logger -from lib.core.enums import DBMS -from lib.core.session import setDbms -from lib.core.settings import ACCESS_ALIASES -from lib.core.settings import METADB_SUFFIX -from lib.request import inject -from plugins.generic.fingerprint import Fingerprint as GenericFingerprint - +# 1. 从库中引入需要的模块和类 +from lib.core.common import Backend # 后端数据库信息 +from lib.core.common import Format # 格式化输出 +from lib.core.common import getCurrentThreadData # 获取当前线程的数据 +from lib.core.common import randomStr # 生成随机字符串 +from lib.core.common import wasLastResponseDBMSError # 判断最后响应是否包含数据库错误 +from lib.core.data import conf # 全局配置信息 +from lib.core.data import kb # 全局知识库 +from lib.core.data import logger # 日志记录器 +from lib.core.enums import DBMS # 数据库类型枚举 +from lib.core.session import setDbms # 设置当前数据库类型 +from lib.core.settings import ACCESS_ALIASES # ACCESS 数据库的别名 +from lib.core.settings import METADB_SUFFIX # 元数据表后缀 +from lib.request import inject # 注入相关函数 +from plugins.generic.fingerprint import Fingerprint as GenericFingerprint # 通用指纹识别类 + +# 2. 定义一个类 Fingerprint,继承自 GenericFingerprint class Fingerprint(GenericFingerprint): + # 3. 构造函数,初始化数据库类型 def __init__(self): GenericFingerprint.__init__(self, DBMS.ACCESS) + # 4. 私有方法,检查是否在沙盒中运行 def _sandBoxCheck(self): - # Reference: http://milw0rm.com/papers/198 + # 参考链接: http://milw0rm.com/papers/198 retVal = None table = None + # 5. 根据 Access 版本设置需要查询的表名 if Backend.isVersionWithin(("97", "2000")): table = "MSysAccessObjects" elif Backend.isVersionWithin(("2002-2003", "2007")): table = "MSysAccessStorage" + # 6. 如果有对应的表名,则执行查询判断是否处于沙盒环境 if table is not None: result = inject.checkBooleanExpression("EXISTS(SELECT CURDIR() FROM %s)" % table) retVal = "not sandboxed" if result else "sandboxed" + # 7. 返回检测结果 return retVal + # 8. 私有方法,检查系统表是否存在 def _sysTablesCheck(self): infoMsg = "executing system table(s) existence fingerprint" logger.info(infoMsg) - # Microsoft Access table reference updated on 01/2010 + # 9. 定义不同版本 Access 需要检查的系统表 sysTables = { "97": ("MSysModules2", "MSysAccessObjects"), "2000": ("!MSysModules2", "MSysAccessObjects"), "2002-2003": ("MSysAccessStorage", "!MSysNavPaneObjectIDs"), "2007": ("MSysAccessStorage", "MSysNavPaneObjectIDs"), } + # MSysAccessXML 是不稳定的系统表,因为它并非总是存在 - # MSysAccessXML is not a reliable system table because it doesn't always exist - # ("Access through Access", p6, should be "normally doesn't exist" instead of "is normally empty") - + # 10. 遍历系统表,进行检查 for version, tables in sysTables.items(): exist = True for table in tables: negate = False + # 11. 如果表名以 ! 开头,表示该表应该不存在 if table[0] == '!': negate = True table = table[1:] + # 12. 执行 SQL 查询,检查表是否存在 result = inject.checkBooleanExpression("EXISTS(SELECT * FROM %s WHERE [RANDNUM]=[RANDNUM])" % table) if result is None: result = False + # 13. 如果表不应该存在,则取反 if negate: result = not result - + # 14. 对所有表的结果进行与运算,只有都满足才能认为当前版本匹配 exist &= result if not exist: break - + # 15. 如果当前版本匹配,则返回版本号 if exist: return version - + # 16. 如果所有版本都不匹配,则返回 None return None + # 17. 私有方法,获取数据库所在目录 def _getDatabaseDir(self): retVal = None infoMsg = "searching for database directory" logger.info(infoMsg) + # 18. 生成随机字符串 randStr = randomStr() + # 19. 执行 SQL 查询,尝试触发错误,获取数据库目录 inject.checkBooleanExpression("EXISTS(SELECT * FROM %s.%s WHERE [RANDNUM]=[RANDNUM])" % (randStr, randStr)) + # 20. 如果最后响应包含数据库错误 if wasLastResponseDBMSError(): threadData = getCurrentThreadData() + # 21. 从错误信息中提取数据库目录 match = re.search(r"Could not find file\s+'([^']+?)'", threadData.lastErrorPage[1]) if match: @@ -102,92 +117,115 @@ class Fingerprint(GenericFingerprint): if retVal.endswith('\\'): retVal = retVal[:-1] - + # 22. 返回数据库目录 return retVal + # 23. 获取指纹信息 def getFingerprint(self): value = "" + # 24. 获取 Web 服务器操作系统指纹 wsOsFp = Format.getOs("web server", kb.headersFp) - + # 25. 将 Web 服务器操作系统指纹添加到输出 if wsOsFp: - value += "%s\n" % wsOsFp + value += "%s\ +" % wsOsFp + # 26. 如果有数据库 Banner 信息 if kb.data.banner: + # 27. 获取后端数据库操作系统指纹 dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp) - + # 28. 将后端数据库操作系统指纹添加到输出 if dbmsOsFp: - value += "%s\n" % dbmsOsFp + value += "%s\ +" % dbmsOsFp value += "back-end DBMS: " + # 29. 如果不是详细指纹,则返回数据库类型 if not conf.extensiveFp: value += DBMS.ACCESS return value + # 30. 获取活动的指纹信息 actVer = Format.getDbms() + " (%s)" % (self._sandBoxCheck()) blank = " " * 15 value += "active fingerprint: %s" % actVer + # 31. 如果有 Banner 解析指纹 if kb.bannerFp: banVer = kb.bannerFp.get("dbmsVersion") - + # 32. 如果有 Banner 版本号 if banVer: + # 33. 如果 Banner 信息包含 -log,则表示启用日志 if re.search(r"-log$", kb.data.banner or ""): banVer += ", logging enabled" - + # 34. 格式化 Banner 版本号 banVer = Format.getDbms([banVer]) - value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer) + value += "\ +%sbanner parsing fingerprint: %s" % (blank, banVer) + # 35. 获取 HTML 错误指纹 htmlErrorFp = Format.getErrorParsedDBMSes() + # 36. 将 HTML 错误指纹添加到输出 if htmlErrorFp: - value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp) - - value += "\ndatabase directory: '%s'" % self._getDatabaseDir() - + value += "\ +%shtml error message fingerprint: %s" % (blank, htmlErrorFp) + # 37. 获取数据库目录并添加到输出 + value += "\ +database directory: '%s'" % self._getDatabaseDir() + # 38. 返回完整的指纹信息 return value + # 39. 检查数据库类型是否为 Access def checkDbms(self): + # 40. 如果不是详细指纹,且当前数据库类型属于 Access 别名,则设置数据库类型为 Access 并返回 True if not conf.extensiveFp and Backend.isDbmsWithin(ACCESS_ALIASES): setDbms(DBMS.ACCESS) return True - + # 41. 输出正在测试的数据库类型 infoMsg = "testing %s" % DBMS.ACCESS logger.info(infoMsg) + # 42. 执行 SQL 查询,检查数据库类型是否为 Access result = inject.checkBooleanExpression("VAL(CVAR(1))=1") - + # 43. 如果查询成功 if result: infoMsg = "confirming %s" % DBMS.ACCESS logger.info(infoMsg) - + # 44. 执行 SQL 查询,再次确认数据库类型是否为 Access result = inject.checkBooleanExpression("IIF(ATN(2)>0,1,0) BETWEEN 2 AND 0") - + # 45. 如果再次确认失败,则输出警告信息,并返回 False if not result: warnMsg = "the back-end DBMS is not %s" % DBMS.ACCESS logger.warning(warnMsg) return False - + # 46. 设置数据库类型为 Access setDbms(DBMS.ACCESS) + # 47. 如果不是详细指纹,则返回 True if not conf.extensiveFp: return True - + # 48. 输出正在进行详细指纹识别 infoMsg = "actively fingerprinting %s" % DBMS.ACCESS logger.info(infoMsg) + # 49. 执行系统表检查,获取 Access 版本 version = self._sysTablesCheck() - + # 50. 如果获取到版本信息,则设置数据库版本 if version is not None: Backend.setVersion(version) - + # 51. 返回 True return True + # 52. 如果第一次查询失败,则输出警告信息,并返回 False else: warnMsg = "the back-end DBMS is not %s" % DBMS.ACCESS logger.warning(warnMsg) return False + # 53. 强制枚举数据库类型 def forceDbmsEnum(self): - conf.db = ("%s%s" % (DBMS.ACCESS, METADB_SUFFIX)).replace(' ', '_') + # 54. 设置数据库名称 + conf.db = ("%s%s" % (DBMS.ACCESS, METADB_SUFFIX)).replace(' ', '_') \ No newline at end of file