CVE-2025-61638:Sanitizer::validateAttributes data-XSS

距离似乎已经 7 个月了……?是时候来写篇新的了,至于内容标题已经很明显了。这是一个关于说小不小说大不大的 CVE 的故事。

对了,如果你读过我之前的一些文章里会发现这次的文风不太一样,不过不用担心这次依旧是纯手写的,只是在尝试新的风格。

我们所经历的每个平凡的日常,也许就是连续发生的奇迹

机智的小鱼君写了个 MW 扩展(MoeImgTag),并在之后于萌娘百科中实装以在新 MW 版本中支持 <img /> 标签。

我在 左右注意到了这个,并进行了些基本的测试,例如 {{#img:|src=}} 的写法,并发现空的 src 会导致不生成标签,这和之前的行为不同可能导致一些问题。这时候已经要到我的凌晨 4 点了,该睡觉了。

吾好梦中编程

躺在床上瞎想着各种事并尝试入睡,我有很多好想法都源自于此。而这次在脑内回想 XSS Filter Evasion - OWASP Cheat Sheet Series ,突然想到由于一般的 <img data-/onerror="" /> 在 MW 中通常会被处理而无效,{{#img:|data-/onerror=}} 的写法可能没有被注意并过滤。

而在最简单的测试后发现确实没有被过滤,在技编群内提报给了小鱼君之后我便继续睡觉了……而当天是周日小鱼君不上班。

第零日

小鱼君检查了代码,并发现是 MW 自带的 Sanitizer::validateAttributes 中的漏洞:

# Allow any attribute beginning with "data-"
# However:
# * Disallow data attributes used by MediaWiki code
# * Ensure that the attribute is not namespaced by banning
#   colons.
if ( (
	!preg_match( '/^data-[^:]*$/i', $attribute ) &&
	!array_key_exists( $attribute, $allowed )
) || self::isReservedDataAttribute( $attribute ) ) {
	continue;
}

至此,漏洞的核心其实已经被挖掘出来了。我将这些聊天记录转发给了并不在群里的 MW、PHP 大佬 Func,让他也来看一眼。

在经过了一段时间群里的讨论以及 Func 的调查之后,他通过 MediaWiki Codesearch 搜索发现 Extension:CategoryTree 也使用了相同的写法,使得 {{#categorytree:测试|data-/onclick=alert(1);}} 的写法也能够进行 XSS。

但由于 Sanitizer::decodeTagAttributes 方法存在并可以防止这个问题,我们此时只认为这是一个由于 MW 代码不清晰加上扩展内错误写法的一个容易因犯错而导致的小漏洞。

如此生活三十年,直到大厦崩塌

直到……

是了,总该会有个“直到”的。

,Func 发现 {{#tag:pre|CLICK pre|data-/onclick=alert(1)}}{{#tag}} 的语法也能够使用此进行 XSS,而这意味着不止是个别扩展了,而是当时几乎所有使用 MW 的百科都能被攻击到。

接下来就是提报漏洞等杂项和小插曲了,没什么重点了,感兴趣的可以自行查看 Wikimedia Phabricator 的对应 T401099

那么如此严重,但似乎很容易被发现的漏洞存在了多久呢? 15 年……

草台班子