未认证删任意文件:WordPress 插件 CVSS 9.1 可直接接管站点

admin 2026年11月1日22:51:28评论0 views字数 4214阅读14分2秒阅读模式

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  漏洞速览

漏洞编号CVE-2026-103882(CWE-22)
影响产品Acadlix LMS 插件 ≤ 1.1.9
漏洞类型路径穿越导致任意文件删除
危害等级9.1 严重(CVSS 3.1)
在野利用暂无公开记录
公开 PoC无独立 EXP,路由与源码已公开
攻击前提站点启用该插件,能打开前台页面
影响面PHP 进程有权写的任意文件

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 可直接接管站点

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2026年11月1日22:51:28
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   未认证删任意文件:WordPress 插件 CVSS 9.1 可直接接管站点http://cn-sec.com/archives/5547904.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息