- 网络安全
- 漏洞扫描
- 渗透测试
- 应用安全
- 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
导读:本文以 WPScan 仓库中的
spec/fixtures/dynamic_finders/plugin_version/flash-show-and-hide-box/change_log/CHANGELOG.md为切入点,完整拆解"变更日志(Change Log)"这一版本探测手段从指纹定义、正则匹配到扫描验证的全链路原理。读完你将掌握:插件版本指纹(dynamic_finders.yml)的配置语法、BodyPattern匹配器的底层实现、WPScan 对"激进/被动"探测模式的调度逻辑,以及如何用规格测试(expected.yml)验证指纹有效性——这套方法论可直接复用于其他 WordPress 插件的版本识别研究。
一、案例背景:一份真实插件变更日志在 WPScan 中的角色
flash-show-and-hide-box是一个用于在 WordPress 页面中显示/隐藏 Flash 内容的插件(后因 Flash 技术衰落而停止活跃维护,其 CHANGELOG 的最后版本记录为 1.6 并"Transfer ownership"移交所有权)。本仓库中与其关联的文档是其 CHANGELOG.md,其内容并非一篇 README 式的说明文档,而是一个结构化的版本变更记录:
- 采用
### [版本号]的 Markdown 三级标题组织每个版本条目; - 每个条目下列出该版本的变更要点(Added / Fixed / New / Removed / Modified / Tested up to / Initial public release 等);
- 版本号从 1.0(Initial public release)一路演进到 1.6(Transfer ownership)。
这份文件之所以被收纳进 WPScan 的spec/fixtures/dynamic_finders/目录,是因为它担任了动态指纹(Dynamic Finder)的测试样本(fixture):WPScan 正是通过嗅探 WordPress 插件目录下可公开访问的CHANGELOG.md,再对其中形如### [1.6]的标题做正则匹配,从而被动地推导出目标站点所安装插件的版本号。
从 WPScan 的视角看,这份变更日志的真实价值不在其文字内容,而在于:
- 它提供了一条公开、稳定的版本号暴露路径(
/wp-content/plugins/flash-show-and-hide-box/CHANGELOG.md); - 其标题格式
### [x.y.z]具有高可识别性,可以被一个简单正则稳定提取出版本号; - 它是"Change Log"这一探测器(Finder)的规格样本,被两个关键配置文件与测试清单引用(见下文)。
二、指纹是如何被定义的:dynamic_finders.yml 中的 ChangeLog 配置
WPScan 将"针对某个插件 slug 如何探测版本"的规则集中存放在数据文件 spec/fixtures/db/dynamic_finders.yml(其生产数据对应lib/wpscan/db/dynamic_finders.yml,仓库内用 spec 下的拷贝作为测试基准)。在该文件的flash-show-and-hide-box条目下,定义了两种探测方式:
flash-show-and-hide-box: ChangeLog: class: BodyPattern path: CHANGELOG.md pattern: !ruby/regexp /\#\#\# \[(?<v>\d+\.[\.\d]+)\]/i version: true Readme: path: - readme.txt - README.md逐字段解读这条指纹规则:
ChangeLog:指纹名称(Finder 名称),在运行时会被映射为动态生成的探测类;class: BodyPattern:指定使用的匹配器类型。BodyPattern表示"对响应体(response body)做正则匹配",适用于CHANGELOG.md这类非 HTML 文档(因为 XPath 需要解析 HTML 结构,而纯文本文件不适合);在 lib/wpscan/db/dynamic_finders/base.rb 的allowed_classes中,BodyPattern与Comment / Xpath / HeaderPattern / JavascriptVar / QueryParameter / ConfigParser一同被列为合法类型;path: CHANGELOG.md:要请求的相对文件路径(相对于插件的根目录)。注意:配置了path的指纹属于激进探测(Aggressive Detection),因为扫描器需要额外发起一次针对该文件的 HTTP 请求;反之path为空的规则(如Readme条目的path:为空列表)则是被动探测,仅依赖扫描主页等已有响应;pattern: /\#\#\# \[(?<v>\d+\.[\.\d]+)\]/i:版本提取正则。它匹配### [1.6]这样的三级标题,并通过命名捕获组(?<v>...)捕获版本号。该正则的\.在 YAML 的!ruby/regexp标记下按 Ruby 正则语义解析(在 spec 加载时通过permitted_classes: [Regexp]安全反序列化,见 base.rb);version: true:声明该指纹可以产出版本号,使其进入versions_finders_configs列表(在 lib/wpscan/db/dynamic_finders/plugin.rb 中,Plugin.versions_finders_configs只收集含version键的配置)。
三、底层实现:BodyPattern 如何完成"请求 + 匹配 + 产出 Version"
指纹配置只描述"做什么",真正执行"怎么做"的是动态生成的探测类。当 WPScan 需要为flash-show-and-hide-box生成版本探测器时,会通过 lib/wpscan/db/dynamic_finders/plugin.rb 的create_versions_finders(slug)动态创建类,其父类由version_finder_super_class(klass)解析为WPScan::Finders::DynamicFinder::WpItemVersion::BodyPattern(定义于 lib/wpscan/finders/dynamic_finder/wp_item_version.rb,它自身又继承自通用版本探测基类)。
真正执行匹配的find方法位于 lib/wpscan/finders/dynamic_finder/version/body_pattern.rb:
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 过滤:若目标站点不存在该
CHANGELOG.md(返回 404),直接放弃匹配——这也解释了为何path型指纹需要额外的请求成本,属于"先探测文件是否存在、再提取版本"的两段式流程; - 正则命中即版本:只要响应体命中了
PATTERN(即配置中的/\#\#\# \[(?<v>\d+\.[\.\d]+)\]/i),就通过Regexp.last_match[:v]取出命名捕获组v作为版本号; - 证据留痕:
interesting_entries记录了"哪个 URL、命中了什么内容",例如http://wp.lab/wp-content/plugins/flash-show-and-hide-box/CHANGELOG.md, Match: '### [1.6]'。这是 WPScan 输出报告中"Interesting Entries"(关键证据)的来源,保证每个版本结论都有可追溯的原始证据。
此外,BodyPattern类在 body_pattern.rb 中为子类注入了默认CONFIDENCE: 60,即默认置信度 60。注释也解释了设计意图:BodyPattern 典型用于响应不是 HTML 文档、无法使用 XPath 的场景——CHANGELOG.md正是这样的纯文本文件。
四、从被动到激进:ChangeLog 在扫描调度中的定位
WPScan 的插件版本探测会根据是否额外发请求分为两类,其调度逻辑体现在 lib/wpscan/db/dynamic_finders/plugin.rb 的finder_configs(finder_class, aggressive:):
- 被动探测(aggressive: false):选取
path为空的配置,复用扫描主页、404 页等既有响应中的指纹(如 JavaScript 变量、注释、QueryParameter 等),零额外请求; - 激进探测(aggressive: true):选取
path非空的配置,针对插件目录下发起的请求,如本案例的CHANGELOG.md。
flash-show-and-hide-box的ChangeLog指纹配置了path: CHANGELOG.md,因此属于激进探测:只有在 WPScan 认为需要深入确认插件版本(或未能在被动阶段确定版本)时,才会请求…/plugins/flash-show-and-hide-box/CHANGELOG.md并应用上述正则。
五、规格验证:expected.yml 如何断言指纹结果
WPScan 用一组期望清单(expected.yml)来"倒逼"验证指纹配置的正确性。在 spec/fixtures/dynamic_finders/expected.yml 中,与本案例对应的期望条目为:
flash-show-and-hide-box: ChangeLog: number: '1.6' found_by: Change Log (Aggressive Detection) interesting_entries: - 'http://wp.lab/wp-content/plugins/flash-show-and-hide-box/CHANGELOG.md, Match: ''### [1.6]'''它完整断言了三个事实:
number: '1.6':给定 fixture 变更日志(内容止于### [1.6]),指纹应当产出版本 1.6(注意字符串形式'1.6',对应正则捕获组输出);found_by: Change Log (Aggressive Detection):确认该结论的发现方式标签,与"激进探测 + ChangeLog 指纹"的定位一致;interesting_entries:期望输出中携带的证据条目,精确到 URL 与命中的正则片段。
这套"fixture 文件(变更日志)→ dynamic_finders.yml 指纹 → expected.yml 期望"的三元组,构成了 WPScan 动态指纹的闭环测试体系:fixture 提供输入样本,指纹描述提取规则,期望清单锁定期望结果。任何对指纹正则或匹配逻辑的改动,都能通过规格测试(rspec下的dynamic_finders相关用例)立刻发现回归。
六、实战要点与局限
基于以上源码级拆解,可以总结出将"Change Log 指纹"用于 WordPress 插件安全评估时的关键实践点:
实战要点
- 优先在被动阶段尝试
Readme、QueryParameter等零成本指纹;当需要确认版本(如核对已知漏洞影响范围)时,再依赖ChangeLog等激进指纹发起定向请求; - 变更日志类的指纹依赖插件开发者保留 CHANGELOG 文件且保持
### [版本]标题格式;本案例的插件在 1.5 版本后还加入了 translate.wordpress.org 的翻译接入,这类维护行为往往意味着 CHANGELOG 会持续更新,间接提升指纹的可用性; - 报告中
interesting_entries直接引用了匹配原文(如### [1.6]),可作为审计复核的原始证据链。
已知局限
BodyPattern仅做响应体正则匹配,不解析 HTML 结构,因此若 CHANGELOG 被站点做了转义、压缩或改造成其他格式(如<h3>[1.6]</h3>),默认正则将无法命中;- 配置了
path的指纹每次都要额外请求,存在被 WAF/反爬策略拦截或产生告警日志的可能,这也是 WPScan 将其归入 Aggressive Detection 的原因; - 版本号提取依赖开发者维护变更日志的习惯——若插件长期不更新 CHANGELOG(如本插件在 1.6 后所有权移交、实质停更),指纹产出的版本可能与真实安装版本脱节。
七、扩展阅读:深入该指纹体系的相关代码
若希望继续深入 WPScan 的动态指纹体系,可依次阅读以下仓库文件:
- spec/fixtures/db/dynamic_finders.yml:
flash-show-and-hide-box指纹的原始定义(ChangeLog + Readme 双通道); - spec/fixtures/dynamic_finders/expected.yml:本指纹的规格期望与证据断言;
- lib/wpscan/finders/dynamic_finder/version/body_pattern.rb:
BodyPattern匹配器的find实现; - lib/wpscan/finders/dynamic_finder/wp_item_version.rb:插件/主题版本动态指纹的类族(含 Xpath、QueryParameter 等兄弟实现);
- lib/wpscan/db/dynamic_finders/plugin.rb:指纹配置加载、类生成与被动/激进调度的核心逻辑;
- lib/wpscan/db/dynamic_finders/base.rb:
allowed_classes白名单与 YAML 安全加载。
通过"fixture 变更日志 → 指纹配置 → 匹配器源码 → 期望断言"这条链路,你可以把本案例的方法论迁移到任意插件的版本识别研究:只需为新的插件 slug 补充 CHANGELOG 样本与正则,即可在 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
相关推荐
WPScan 插件版本探测:以 gravity-forms-dps-pxpay 的 changelog.md 为例解析 Dynamic Finder 机制
WPScan 插件版本探测:以 gravity forms dps pxpay 的 changelog.md 为例解析 Dynamic Finder 机制 导读
网络安全漏洞扫描渗透测试应用安全CLI深入解析 WPScan 插件版本探测:以 cod-network 的 changelog.md 动态指纹为例
深入解析 WPScan 插件版本探测:以 cod network 的 changelog.md 动态指纹为例 导读 本文以 WPScan 仓库中的真实指纹样本
网络安全漏洞扫描渗透测试应用安全CLIWPScan 动态指纹识别实战:以 Courier Notices 插件的 CHANGELOG.md 版本检测为例
WPScan 动态指纹识别实战:以 Courier Notices 插件的 CHANGELOG.md 版本检测为例 本文以 WPScan 仓库中 Courier
网络安全漏洞扫描渗透测试应用安全CLI
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考