☰
深入解析 WPScan 动态指纹识别:如何从 CHANGELOG.md 精准定位 WordPress 插件版本(以 tag-pages 为例)
2026/9/27 7:48:41 网站建设 项目流程
  • 网络安全
  • 漏洞扫描
  • 渗透测试
  • 应用安全
  • CLI

【免费下载链接】wpscan

WPScan WordPress security scanner. Written for security professionals and blog maintainers to test the security of their WordPress websites. Contact us via contact@wpscan.com

项目地址:https://gitcode.com/gh_mirrors/wp/wpscan
点击查看免费下载

WPScan 是面向安全专业人员和博客维护者的 WordPress 安全扫描器,其核心能力之一是在不登录后台的情况下识别站点正在运行的插件及其精确版本。本文以插件tag-pages的变更日志文件(CHANGELOG.md)为例,从 WPScan 的 Dynamic Finders(动态查找器)机制出发,完整讲解「变更日志指纹」从数据库配置、运行时类生成、HTTP 请求、正则匹配到版本回填的整条调用链。读完本文,你将掌握 WPScan 如何利用CHANGELOG.md/changelog.txt等公开文件做插件版本检测,理解BodyPattern动态查找器的实现原理与置信度设计,并能依据现有模式为自己的插件或新插件编写可被 WPScan 识别的版本指纹规则。

变更日志为什么能成为版本指纹

WordPress 插件目录中的绝大多数插件都会随包附带变更日志文件,常见命名为CHANGELOG.md、changelog.txt等。这些文件位于插件目录根路径下(如wp-content/plugins/tag-pages/CHANGELOG.md),通常以明文记录每个发行版本号、发布日期与修复内容,且完全无需认证即可通过 HTTP 直接访问。这意味着攻击者与扫描器都能通过它快速确认目标站点的插件版本,进而比对已知漏洞库判断风险。

tag-pages插件的变更日志(spec/fixtures/dynamic_finders/plugin_version/tag-pages/change_log/CHANGELOG.md)内容如下:

Changelog ========= #### 1.0.2 - Feb 2, 2019 **Fixes** - Gutenberg does not show tags on page create/edit screen #### 1.0.1 - June 21, 2016 **Fixes** - Unable to save bulk edit of tag filtered posts in wp-admin.

这份文件记录了该插件的两个发行版本:1.0.2(2019 年 2 月 2 日发布,修复 Gutenberg 编辑器在页面创建/编辑界面不显示标签的问题)与1.0.1(2016 年 6 月 21 日发布,修复 wp-admin 中按标签筛选文章的批量编辑无法保存的问题)。对 WPScan 而言,关键的指纹信息是第 4 行标题格式#### 1.0.2 - Feb 2, 2019——版本号出现在四个井号后的固定位置,这一格式被 WPScan 的正则模式精确捕获。

从数据库配置到查找器类:一条动态生成链路

WPScan 并不为每个插件手写检测代码,而是将所有插件的指纹规则集中存放在一个 YAML 数据库中,运行时按需动态生成查找器类。tag-pages在数据库配置(spec/fixtures/db/dynamic_finders.yml)中对应如下条目:

tag-pages: ChangeLog: class: BodyPattern path: CHANGELOG.md pattern: !ruby/regexp /^\#\#\#\# (?<v>\d+\.[\.\d]+) \- [^\r\n]+$/i version: true Readme: path: readme.txt

逐字段解读:

  • ChangeLog:查找器名称,即 YAML 键名;在无显式class时它同时被当作查找器类型名。
  • class: BodyPattern:指明该规则使用BodyPattern这一动态查找器子类——适用于响应体不是 HTML 文档、无法用 XPath 解析的场景(如纯文本的 changelog)。
  • path: CHANGELOG.md:目标文件在插件目录下的相对路径。存在path意味着该查找器只能通过 aggressive(激进)模式触发,因为它需要主动请求特定文件。
  • pattern:Ruby 正则,用于从文件正文中提取版本号。对tag-pages而言,^\#\#\#\# (?<v>\d+\.[\.\d]+) \- [^\r\n]+$/i精确匹配以####开头的行,并将版本号捕获到命名分组(?<v>...),其中\d+\.[\.\d]+匹配1.0.2这类点分数字序列。
  • version: true:标志该配置产出的是版本信息,是versions_finders_configs收集规则的关键过滤条件。

在运行时,lib/wpscan/db/dynamic_finders/plugin.rb 通过versions_finders_configs遍历数据库,筛选出所有携带version键的配置,再由create_versions_finders(slug)为每个 slug 动态生成查找器类:先通过maybe_create_module将 slug 转换为 Ruby 常量名(tag-pages→TagPages),再调用version_finder_super_class(klass).create_child_class(mod, finder_class, config)创建子类。lib/wpscan/finders/dynamic_finder/finder.rb 中的create_child_class会把 YAML 中的path、pattern、confidence等配置逐一写入子类常量(PATH、PATTERN、CONFIDENCE),从而实现「一份 YAML 配置、动态生成一个专用查找器」的插件化架构。

BodyPattern 查找器:正则如何落地为版本对象

当配置被编译成查找器类后,真正执行匹配的是BodyPattern基类(lib/wpscan/finders/dynamic_finder/version/body_pattern.rb)。其核心find方法逻辑非常紧凑:

def find(response, _opts = {}) return unless response.code != 404 && response.body =~ self.class::PATTERN create_version( Regexp.last_match[:v], interesting_entries: ["#{response.effective_url}, Match: '#{Regexp.last_match}'"] ) end

该方法先排除 404 响应,再对响应正文执行子类的PATTERN正则;一旦命中,就从命名分组:v取出版本号,并构建一个WPScan::Model::Version对象。值得注意的是interesting_entries中记录了「实际 URL + 完整匹配文本」,这正是扫描报告里能溯源到具体证据行(例如http://wp.lab/wp-content/plugins/tag-pages/CHANGELOG.md, Match: '#### 1.0.2 - Feb 2, 2019')的原因。

BodyPattern子类还带有默认置信度CONFIDENCE: 60(见 lib/wpscan/finders/dynamic_finder/version/body_pattern.rb),而 lib/wpscan/finders/dynamic_finder/version/finder.rb 中的version_finding_opts会在配置未显式指定时回填该默认值,保证每个版本结果都带有可供过滤与排序的置信度评分。

被动与激进:两种检测模式的取舍

动态查找器基类(lib/wpscan/finders/dynamic_finder/finder.rb)将检测划分为两种模式:

  • passive(被动检测):仅当子类未定义PATH时生效,逻辑为先检查目标首页(homepage_res),未命中再检查 404 页面(error_404_res)。这类查找器(如QueryParameter、Comment)依赖页面中已泄露的资源 URL,不发起额外请求,隐蔽性更好。
  • aggressive(激进检测):仅当子类定义了PATH时生效,逻辑为直接请求target.url(self.class::PATH),即主动拉取CHANGELOG.md、readme.txt等已知路径。

tag-pages的ChangeLog规则带有path: CHANGELOG.md,因此属于 aggressive 检测:WPScan 会构造http://目标/wp-content/plugins/tag-pages/CHANGELOG.md请求,下载文件正文后用正则匹配版本。正因如此,它比从首页被动嗅探更精确,但也更依赖插件目录路径可被枚举的前提。对应地,插件自带Readme规则(path: readme.txt)则与 app/finders/plugin_version/readme.rb 中的Readme查找器协同工作,从readme.txt的Stable Tag行(置信度 80)或= 版本号 =格式的变更日志段(置信度 50)提取版本,两种手段互为补充。

测试体系:预期结果如何验证指纹规则

WPScan 对每条动态查找器规则都有自动化验证。全插件查找器的测试入口在 spec/lib/finders/dynamic_finder/plugin_version_spec.rb:它遍历versions_finders_configs中每个 slug,动态生成 RSpec 用例,并断言找到的版本与预期结果文件逐一比对。

tag-pages在预期结果文件(spec/fixtures/dynamic_finders/expected.yml)中的记录为:

tag-pages: ChangeLog: number: 1.0.2 found_by: Change Log (Aggressive Detection) interesting_entries: - 'http://wp.lab/wp-content/plugins/tag-pages/CHANGELOG.md, Match: ''#### 1.0.2 - Feb 2, 2019'''
  • number: 1.0.2证明规则从本仓库的 CHANGELOG.md 中提取出的版本正是最新版1.0.2(而非更早的1.0.1,因为正则命中后取命名分组值,且测试断言版本号等于该值);
  • found_by: Change Log (Aggressive Detection)对应测试中对found_by字段的期望;
  • interesting_entries记录了匹配证据行,与BodyPattern#find中构造的条目格式完全一致。

此外,spec/lib/finders/dynamic_finder/version/body_pattern_spec.rb 从单元层面验证了create_child_class的常量注入行为:默认CONFIDENCE为 60、PATH与CONFIDENCE可被配置覆盖、未指定PATH时基类常量保持nil。这意味着向数据库新增一条BodyPattern规则时,只需同步更新 YAML 配置、对应的变更日志 fixture 与expected.yml,测试套件便会自动覆盖被动/激进两种路径。

实战启示:如何为其他插件编写变更日志指纹

基于上述调用链,为任意插件添加「变更日志版本检测」只需满足三个条件:

  1. 文件可访问:插件包根目录存在CHANGELOG.md(或changelog.txt),且站点未通过 Web 服务器规则屏蔽该路径;
  2. 版本行格式固定:文件中至少有一行以#### 版本号开头的标题。正则^\#\#\#\# (?<v>\d+\.[\.\d]+) \- [^\r\n]+$/i要求####后紧跟点分数字、空格连字符、日期文本;若插件改用## Version 2.0.0、=== 3.1.4 ===等格式,则需要配置不同的pattern(可参照 app/finders/plugin_version/readme.rb 中从 readme 变更日志段提取版本的思路);
  3. 数据库配置就位:在dynamic_finders.yml的plugins段为 slug 增加ChangeLog规则,并配套 fixture 与expected.yml预期条目。

对扫描使用者而言,理解这一机制也有实际价值:当 WPScan 报告某插件版本「Found By: Change Log (Aggressive Detection)」时,说明版本结论直接来源于插件自带的变更日志文件,其可信度由BodyPattern的默认置信度 60 体现,且报告中给出的interesting_entries可作为人工复核的直接证据——只需打开对应 URL 核对#### 版本号行即可。

小结

变更日志是 WordPress 生态中一个既公开又可靠的信息源,WPScan 通过 Dynamic Finders 体系将其转化为可执行的版本指纹:dynamic_finders.yml定义规则,BodyPattern基类负责正则匹配与版本对象构造,plugin.rb动态生成类,测试套件用expected.yml兜底验证。以tag-pages的 CHANGELOG.md 为样本,本文梳理了从「#### 1.0.2 - Feb 2, 2019这一行文本」到「1.0.2版本结论」的完整链路,这既是 WPScan 源码级工作原理的切片,也为扫描结果的解读与自定义指纹规则的编写提供了可直接复用的范式。

  • 网络安全
  • 漏洞扫描
  • 渗透测试
  • 应用安全
  • CLI

【免费下载链接】wpscan

WPScan WordPress security scanner. Written for security professionals and blog maintainers to test the security of their WordPress websites. Contact us via contact@wpscan.com

项目地址:https://gitcode.com/gh_mirrors/wp/wpscan
点击查看免费下载

相关推荐

上一篇:meshio未来展望:网格处理技术发展趋势与路线图
下一篇:Remotion @remotion/openai-whisper 详解:将 OpenAI Whisper 转写结果转换为 Captions 字幕数据

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询