دروبال 11.4.8 - عالي - عن بُعد - رفع - رفع صور CKEditor 5 لا يزال يتخطى FileIsImage
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · drupal-ckeditor-fileisimage
المقال: https://abraxaslabs.tech/research/drupal-ckeditor-fileisimage
الفئة: رفع غير مقيّد / XSS مخزّن الوصول: عن بُعد
Drupal core 11.4.8 (61044508) - Drupal
أضاف SA-CORE-2026-009 القيد FileIsImage على حقول الصور في JSON:API وREST. لا تزال الدالة CKEditor5ImageController::getImageUploadValidators تُرجع FileExtension وFileSizeLimit وFileImageDimensions فقط. وتُعيد FileImageDimensions دون أي انتهاك عندما لا يكون الملف صورة صالحة. ويبقى امتداد اسم الملف هو الفحص المتبقي.
يمكن لمستخدم يستخدم تنسيق نص مع رفع صور CKEditor 5 أن يرسل بايتات غير صور باسم x.png إلى /ckeditor5/upload-image/{editor} فيحصل على 201 بالإضافة إلى رابط ملفات عام.
| المعرّف | لا يوجد CVE بعد |
| الفئة | رفع غير مقيّد / XSS مخزّن في حال الاستنشاق |
| الوصول | عن بُعد (مستخدم مصادَق عليه لتنسيق نص) |
| CWE | CWE-434، CWE-79 |
| CVSS | متوسط: 5.4 CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N |
| المنتج | Drupal core |
| المتأثر | 11.4.8 (61044508071749629aaf3380aa85971e94df9e84) |
| المصادقة | مستخدم مصادَق عليه لتنسيق نص مع رفع صور CKEditor 5 (basic_html / full_html على Standard) |
| الترخيص | GNU Affero GPL v3.0 |
| المختبر | 127.0.0.1 فقط |
يحتاج إلى حساب يستطيع استخدام تنسيق يكون فيه محرّره image_upload.status بقيمة true. على Standard هذان هما basic_html وfull_html. لا يمكن لشخص غريب تمامًا بلا حساب أن يصل إلى هذا المسار (_entity_access: editor.use بالإضافة إلى CSRF).
| الصلاحية | الطريقة / نقطة الوصول | النوع | مُثبت مختبريًا أم مُستنتج |
|---|---|---|---|
كتابة بايتات غير صور إلى ملف .png عام تحت sites/default/files/inline-images/ | POST /ckeditor5/upload-image/{editor} متعدد الأجزاء upload | السلامة | مُثبت مختبريًا. أعاد x.png الرمز 201 وurl=/sites/default/files/inline-images/x.png |
| قراءة تلك البايتات مجددًا من رابط الملفات العام | GET على url في JSON | استطلاع | مُثبت مختبريًا. 200، 49 بايتًا، واحتوى الجسم على DRUPAL-CKEDITOR-FILEISIMAGE-WITNESS |
| XSS مخزّن في زائر إذا استنشق خادم الويب أو المتصفح الملف كـ HTML/JS | نفس الرابط العام، Content-Type ليس صورة | السلامة (أصل الزائر) | مُستنتج. لم يغيّر هذا المختبر MIME في Apache. خزّن Drupal البايتات. |
| رفع صورة حقيقية عبر نفس المسار | التحكم control.png صورة PNG بحجم 1x1 | مقصود | مُثبت مختبريًا. 201 |
مغلق في هذه البقايا: PHP/RCE عبر .php (مُثبت مختبريًا 422 FileExtension)؛ الرفع غير المصادَق عليه؛ ImageItem في JSON:API/REST (تلك المسارات تضيف FileIsImage بالفعل)؛ LPE؛ صدفة على قائمة امتدادات الصور الافتراضية المسموح بها.
ثبّتت Drupal 11.4.8 بعد موجة SA-CORE لعام 2026. يضيف JSON:API بالفعل القيد المفقود:
if (\is_a($field_definition->getItemDefinition()->getClass(), ImageItem::class, TRUE) && !array_key_exists('FileIsImage', $validators)) {
$validators['FileIsImage'] = [];
}
REST FileUploadResource.php يفعل الشيء نفسه. تم ترك CKEditor 5 على اسم الملف + الحجم + الأبعاد:
return [
'FileExtension' => [
'extensions' => implode(' ', $allowed_extensions),
],
'FileSizeLimit' => [
'fileLimit' => $max_filesize,
],
'FileImageDimensions' => [
'maxDimensions' => $max_dimensions,
],
];
FileImageDimensionsConstraintValidator يعود دون انتهاك عندما لا يكون الملف صورة صالحة. تم رفع Hub drupal:11.4 إلى 11.4.9؛ هذا التثبيت هو composer-exact drupal/recommended-project:11.4.8. أزالت 11.4.0 نوع Article من Standard، لذا تُطبّق الصورة core/recipes/article_content_type بعد التثبيت حتى يُحمّل /node/add/article محرر CKEditor 5.
الأخطاء التي سُجّلت بالفعل: التعامل مع FileImageDimensions كفحص MIME (فهو يتحقق من الأبعاد على صورة صالحة، ولا يفعل شيئًا بخلاف ذلك)؛ الادعاء بوجود PHP shell في القائمة الافتراضية المسموح بها (.php يعيد 422)؛ استخدام وسم hub العائم ومراقبة ظهور 11.4.9. مسرحية: reverse shell. المعيار هو 201 على x.png مزيف بالإضافة إلى 422 على نفس البايتات المسماة x.php.
بقايا نفس التثبيت: oEmbed second-hop SSRF.
python3 drupal-ckeditor-fileisimage-Abraxas-Labs.py
أو
cd lab
./run.sh
استهدف فقط http://127.0.0.1:19500. نسخة Drupal 11.4.8 Standard حيّة على php:8.4-apache-trixie، وSQLite.
SUCCESS drupal-ckeditor-fileisimage png-http=201 php-http=422 control-png-http=201 editor=basic_html stored-http=200 stored-has-witness=yes url=/sites/default/files/inline-images/x.png DRUPAL-CKEDITOR-FILEISIMAGE-WITNESS
أضف 'FileIsImage' => [] إلى CKEditor5ImageController::getImageUploadValidators. أبقِ على FileExtension حتى يبقى .php عند 422. يجب أن تستخدم أنواع وسائط الصور في مكتبة الوسائط ImageItem بدلاً من FileItem العام حتى ترث نفس القيد.
61044508071749629aaf3380aa85971e94df9e84)CKEditor5ImageController.phpGNU Affero GPL v3.0. راجع LICENSE. مختبر loopback فقط. دون أي ضمان.