WordPress插件Acadlix LMS存在CVE-2026-103882高危漏洞(CVSS 9.1),其文件删除接口仅校验可从前台页面获取的nonce,且删除路径直接取自请求体未做规范化,任何访客均可构造POST请求删除服务器任意可写文件,删除wp-config.php即可接管站点,影响版本≤1.1.9,1.2.0已修复。
一个只验 nonce 的文件删除接口,路径直接取请求体,任何访客都能让服务器删掉任意文件;删中 wp-config.php,站点就是别人的了。
WordPress 生态里删文件的洞不算稀奇,稀奇的是这次两处失误叠在一起:权限判断只验 nonce,不管你是谁;删除路径来自请求体,不做任何规范化。结果就是评级里"需要订阅者权限"的那一层被彻底抹掉,一条 POST 请求、body 里一个绝对路径,服务器就执行 unlink。这个洞编号 CVE-2026-103882,CVSS 9.1。
01 漏洞速览
02 成因:一句 nonce 校验,一个没过滤的路径
入口是插件前台命名空间下的一条 REST 路由:
POST /wp-json/acadlix/v1/
front-quiz/{quiz_id}/
post-delete-assessment-file
权限回调全文只有一句,没有角色判断,没有能力检查:
// FrontQuizController.php L807
check_permission($request) {
return wp_verify_nonce(
$request->get_header(
'X-WP-Nonce'),
'wp_rest');
}
它只验一个 wp_rest nonce。问题是这个 nonce 不是秘密:插件在 Manager.php 第 570 行把同一个 nonce 塞进前台 acadlixOptions 对象,输出到每一个前台页面。任何人打开首页、读一下这个对象就拿到了,而 nonce 对未登录访客同样有效。所谓"需要订阅者权限"在事实上等于零权限。
第二处失误在处理函数。文件路径完全信任请求体,执行前没有 realpath、没有文件名过滤、没有目录前缀比对:
// 路径直接来自请求体,无校验
$file_path = $payload
['delete_file_data']['file_path'];
if (file_exists($file_path)) {
wp_delete_file($file_path);
}
同一个类里的上传函数老老实实把文件放在 wp-content/uploads/acadlix-assessment,删除逻辑却从没想过"是不是只该删这里面的文件"。正常业务场景是考生删掉自己上传的答卷附件,实际能力是删服务器上任何可写文件。
03 影响范围
· 受影响版本:Acadlix LMS ≤ 1.1.9
· 已修复版本:1.2.0(10 月 23 日发布)把 upload 和 delete 两条路由连同处理函数整段删掉,前台只剩读题、交卷、排行榜
· 判断方式:插件目录 acadlix/readme.txt 里的 Version,或后台插件列表版本号
这插件 2026 年才上架,安装量不大,但用途很清楚:在线考试、培训考核、课程售卖。这类站点的共同点是必须对外开放注册和文件上传,本身就在互联网暴露面上。把面收窄到装了插件的教育类站点,剩下的目标反而更值钱,里面通常有题库、学员手机号、付费订单。
04 危害推演:删掉 wp-config 之后
目前没有公开 EXP,但这条链不需要写代码。先读一遍首页,从页面里翻出 acadlixOptions 的 nonce,再构造请求把 file_path 指向 wp-config.php。WordPress 启动时发现这个文件不存在,会直接跳到安装向导:站点数据库连接信息没了,页面提示重新安装。攻击者此时填自己的库地址,走完安装流程拿到管理员账号,原有的站和库被隔离。
退一步,就算 wp-config 因为权限删不掉,能做的破坏也不少:
· 删 .htaccess:自定义防护规则、伪静态、部分 WAF 规则一并失效
· 删 uploads 下的文件:历史附件、证书、备份包直接消失
· 删某个插件或主题的主文件:站点白屏或 500,形成持久拒绝服务
· 删 advanced-cache.php 之类 drop-in:缓存层崩塌,流量全量打到数据库
能不能删成功,取决于 PHP 进程对目标文件有没有写权限。共享主机上 wp-config.php 属主往往就是 Web 用户,这种环境下基本一次成功。
还要强调一点:这条权限回调是整个前台命名空间共用的。同一个 check_permission 还守着交卷、保存成绩、查排行榜这些接口。它们没有 9.1 的评级,但同样能被未认证请求直接调用,伪造答题记录、改分、批量拉取学员榜单在理论上都做得到。这一层比删文件更隐蔽,出事之后很难从业务侧发现。
05 检测与排查
先确认版本,装上没有、装的是哪个版本:
cd wp-content/plugins/acadlix
grep -m1 'Version:' acadlix.php
grep -rn 'post-delete' .
第三条有输出、且版本低于 1.2.0,说明危险路由还在包里。接着看访问日志有没有人打过它:
grep -F 'post-delete-assessment'
/var/log/nginx/access.log
线上无害探测:拿一个绝对不存在的路径试,确认路由是否可达、权限判断是否形同虚设。
# 1. 首页拿前台 nonce
curl -s https://host/
| grep -o '"nonce":"[a-f0-9]*"'
# 2. 指向不存在的文件
CT='Content-Type: application/json'
curl -s -o /dev/null
-w '%{http_code}n' -X POST
https://host/wp-json/acadlix/v1/
front-quiz/1/
post-delete-assessment-file
-H 'X-WP-Nonce: NONCE'
-H "$CT"
-d '{"quiz_id":1,
"delete_file_data":
{"file_path":
"/tmp/acadlix-zz"}}'
结果这样读:返回 200 且 success 为真,说明路由活着、权限被绕过,只是文件不存在所以没删;返回 401 是 nonce 校验挡住了;返回 404 说明路由已删,1.2.0 及以上就是这种表现。别拿真实文件去验证,删了就是事故。
更快的排法:站点如果开了文件完整性监控,直接查 wp-content 下最近的删除记录,wp-config 消失、.htaccess 消失都是明确异常。
06 修复建议
1. 升级到 Acadlix LMS 1.2.0 或更高。官方的做法是直接移除上传和删除功能,升级后前台不再暴露这两条路由。
2. 短期升不动,就在网关层拦掉 post-delete-assessment-file 和 upload 这两条路径,一律返 403。
3. 自己改代码的话,路径必须做归属校验,只允许删上传目录内的文件:
$base = wp_upload_dir()['basedir']
. '/acadlix-assessment';
$real = realpath($file_path);
if (strpos($real, $base) !== 0) {
return new WP_Error(
'bad_path', 'denied',
['status' => 403]);
}
4. 权限回调补上能力判断,别只验 nonce。删附件属于改数据,至少要有 edit_posts 这类能力,或校验附件归属当前用户。
5. 兜底加固:wp-config.php 对 Web 用户设只读,打开 DISALLOW_FILE_MODS,插件目录设只读;wp-config 和数据库做离线备份,这是被删之后唯一能救回站点的东西。
07 红队视角
这类洞在实战里的价值被低估了。大家注意力都在反序列化和未授权 RCE,但删文件是通往接管最省事的一条捷径:不需要构造 payload,不需要理解业务逻辑,一个路径字符串就够了。门槛低到几乎没有,有前台页面就有 nonce,有 nonce 就能调接口。拿到手先测一个不存在的路径确认可达,再决定动不动手,全程不产生破坏性副作用。
报告口径要注意。这个洞很容易被写成"任意文件删除,需登录",因为漏洞描述里带着订阅者权限的字样,实际上 nonce 全站公开,实质是未认证。写报告时把 nonce 的出处点出来,前台每个页面都带、在 Manager.php 第 570 行注入,评审就不会再把它降级。分类落到 CWE-22 路径穿越,比 CWE-862 缺授权更贴,因为两层缺陷里路径校验缺失才是根因。
防守侧其实很好判断:凡是删除、下载、读取接口,只要入参里出现路径,就该问一句它凭什么保证这个路径在自己家目录里。nonce 只是防 CSRF 的,不是身份认证,这个混淆在 WordPress 插件里太常见了。
08 源码与复现资料
https://nvd.nist.gov/vuln/detail/CVE-2026-103882
https://plugins.svn.wordpress.org/acadlix/tags/1.1.8/includes/Common/REST/Front/FrontQuizController.php
https://plugins.svn.wordpress.org/acadlix/tags/1.2.0/includes/Common/REST/Front/FrontQuizController.php
说明:没有公开 EXP。把 1.1.8 和 1.2.0 两个版本的控制器源码并排看,就是最直接的补丁对比,删除路由的位置一眼可见。
下期继续蹲厂商补丁和 PoC 动静,关注后漏洞先知道,修复不踩坑。
— END —
原文始发于微信公众号(红队安全圈):未认证删任意文件:WordPress 插件 CVSS 9.1 可直接接管站点
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-


评论