
# مختبر Docker A/B + PoC لـ CVE-2026-32475 (رفع ملفات تعسفي غير مصادق عليه في نماذج Elementor Pro -> تنفيذ أوامر عن بُعد عبر عدم تزامن حلقة التحقق/النقل)
مختبر A/B يعيد إنتاج CVE-2026-32475 (CVSS 9.x، Patchstack؛ حقل رفع الملفات في Elementor Pro Forms، الإصدارات المتأثرة ≤ 4.2.1، تم الإصلاح في 4.2.2 بتاريخ 2026-08-19؛ تم الإبلاغ عنه بواسطة Tin Pham / TF1T). غير مصادق عليه، بدون تفاعل من المستخدم.
للاستخدام المصرح به / التعليمي فقط. يعمل هذا المختبر بالكامل على
127.0.0.1داخل حاويات Docker مؤقتة. لا توجه الـ PoC نحو أنظمة غير مصرح لك باختبارها صراحةً. يقومbuild.shبجلب كود Elementor Pro من مرآة GPL عامة؛ لا يتم إعادة توزيع أي كود مميز في هذا المستودع.
modules/forms/fields/upload.php. حلقتان تتكرران على نفس $_FILES['form_fields'][$id] المعاد تشكيله لكنهما تتعاملان مع الجزء الفارغ (UPLOAD_ERR_NO_FILE) بشكل مختلف:
// validation() — السطر ~269
foreach ( $_FILES['form_fields'][ $id ] as $index => $file ) {
if ( ! $field['required'] && UPLOAD_ERR_NO_FILE === $file['error'] ) {
return; // <-- يتخلى عن كل التحقق المتبقي لهذا الحقل
}
...
if ( ! $this->is_file_type_valid( $field, $file ) ) { // قائمة السماح/المنع للامتدادات
$ajax_handler->add_error( $id, 'This file type is not allowed.' );
}
}
// process_field() — السطر ~418
foreach ( $_FILES['form_fields'][ $id ] as $index => $file ) {
if ( UPLOAD_ERR_NO_FILE === $file['error'] ) {
continue; // <-- يتخطى الجزء الفارغ فقط، ويواصل
}
$filename = uniqid() . '.' . pathinfo( $file['name'], PATHINFO_EXTENSION ); // امتداد المهاجم، بدون إعادة فحص
move_uploaded_file( $file['tmp_name'], trailingslashit( $uploads_dir ) . $filename );
}
أرسل حقل رفع اختياريًا واحدًا مع جزأين — جزء فارغ أولاً، ثم حمولة PHP.
validation() يصطدم بالجزء الفارغ وينفذ return قبل فحص .php إطلاقًا؛
process_field() ينفذ continue متجاوزًا الجزء الفارغ وينقل .php إلى
wp-content/uploads/elementor/forms/<uniqid()>.php. قائمة الحظر get_blacklist_file_ext()
(php,phtml,pht,shtml,…) تعمل فقط داخل validation()، لذا يتم تجاوزها بالكامل.
غير مصادق بالكامل: wp_ajax_nopriv_elementor_pro_forms_send_form (ajax-handler.php:295).
get_ensure_upload_dir() يضع ملف .htaccess في مجلد النماذج يحتوي فقط على
Options -Indexes + Header set Content-Disposition attachment. هذا تلميح لتنزيل المتصفح —
على Apache + mod_php فإن .php يُنفَّذ من جانب الخادم؛ المهاجم (عبر curl) ببساطة
يستلم مخرجات الأوامر مع ترويسة تنزيل. وحدة النماذج لا تحتوي على تنظيف unlink،
لذا تبقى الصدفة مستمرة.
صفحة منشورة تحتوي على أداة Form من Elementor Pro مع حقل رفع ملفات حيث
Required = No (فرع ! $field['required']). يتم قراءة إعدادات الحقل من جانب الخادم من
_elementor_data، لذا لا يمكن للمهاجم تبديلها — لكن حقول "المرفقات الاختيارية" شائعة.
الاسم المخزن = uniqid() = %08x%05x = (ثانية يونكس)(ميكروثانية). الثانية تُكشف
بدقة عبر ترويسة استجابة Date في HTTP؛ فقط الميكروثانية (0–999999) غير معروفة →
هجوم تخمين GET عبر الإنترنت محدود بـ ≤10⁶. poc.py --recover يثبّت الميكروثانية على
وقت وصول الاستجابة (في نفس الموقع / متزامن مع NTP ⇒ ثوانٍ–دقائق؛ هنا: ~26 ألف طلب) ويحوّل
الكتابة إلى تنفيذ أوامر عن بُعد.
| الخدمة | المنفذ | Elementor Pro |
|---|---|---|
wp-vuln | http://127.0.0.1:8975 | 3.6.4 — ثغرة أمنية (شجرة أصلية؛ عدم تطابق validation() مطابق تمامًا لـ ≤4.2.1) |
wp-patched | http://127.0.0.1:8976 | 3.6.4 مع إصلاح مكافئ لـ 4.2.2 (return → continue، بمحاذاة الحلقتين) |
التقنية: wordpress:php7.4-apache (mod_php) + MariaDB 10.6 + Elementor (مجاني) 3.6.8 + Elementor Pro 3.6.4.
كل نسخة تحتوي على مسؤول (admin/labpass) وصفحة منشورة "CVE-2026-32475 Lab"
(post_id=5، form_id=frm00001، حقل الرفع field_cv، Required=No).
ملاحظة الإصدار. لا يوجد كود مصدر نظيف لـ 4.2.1/4.2.2 قابل لإعادة التوزيع علنًا، لذا يعمل المختبر على شجرة 3.6.4 الأصلية، التي يكون عدم تطابق
validation()/process_field()فيها مطابقًا بايتًا ببايت للكود الذي يصفه CVE-2026-32475 (الثغرة قديمة؛ 4.2.2 قام بمحاذاة الحلقتين). بناء A/B "المصحح" يطبق هذه المحاذاة بالضبط.
يتطلب Docker + Docker Compose واتصال شبكة خارجي (لسحب الصور، Elementor المجاني، ومرآة
كود Elementor Pro). build.sh يستنسخ شجرة Elementor Pro الأصلية تلقائيًا.
git clone https://github.com/dinosn/cve-2026-32475-elementor-pro-lab
cd cve-2026-32475-elementor-pro-lab
bash build.sh # استنساخ الإضافة + compose up + تثبيت WP/Elementor + إنشاء صفحة النموذج (كلا النسختين)
bash verify.sh # إثبات A/B: الثغرة تكتب وتنفذ صدفة؛ المصحح يرفض. ينظف.
# RCE غير مصادق عن بُعد بالكامل (يستخرج post_id/form_id/field_id تلقائيًا من الصفحة):
python3 poc.py -t http://127.0.0.1:8975 --page-id 5 --recover -c "id; uname -a"
# فقط لإثبات تجاوز قائمة الحظر (اترك الصدفة للفحص):
python3 poc.py -t http://127.0.0.1:8975 --post-id 5 --form-id frm00001 --field-id field_cv
docker-compose.yml — 2× (WordPress + MariaDB)، الثغرة:8975 / المصحح:8976elementor-pro-vuln/ — Elementor Pro 3.6.4 الأصلي (به ثغرة)؛ مُنشأ بواسطة build.sh، مستثنى من gitelementor-pro-patched/ — نفس الشجرة، validation() return→continue؛ مُنشأ بواسطة patch_pro.sh، مستثنى من gitevidence/verify_transcript.txt — سجل محفوظ لتشغيل verify.sh ناجحinstall_wp.sh — تثبيت wp-cli لـ WP + Elementor المجاني + تفعيل Pro + إنشاء صفحة النموذج + إصلاح صلاحيات uploadssetup_page.php — يبني صفحة نموذج Elementor مع حقل رفع اختياريpatch_pro.sh — يشتق الشجرة المصححة + يطبع الفرق المكوّن من سطر واحدpoc.py — رفع عدم تطابق غير مصادق + استعادة اسم ملف uniqid() + RCEverify.sh — إثبات A/B مع مصدر تحقق مستقل لنظام الملفات (يثبت التنفيذ، وليس الكتابة فقط)build.sh — بناء لمرة واحدةcd /root/cve-2026-32475-lab && docker compose down -v