access_fingerprint

pull/18/head
Warmlight 2 months ago
parent 7033a8c210
commit bb4ebc7514

@ -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(' ', '_')
Loading…
Cancel
Save