
استشارة تقنية وإثبات مفهوم لـ CVE-2026-97286، وهو XSS مخزّن يتطلب المصادقة في إضافة Strong Testimonials لـ WordPress، مع سلسلة الهجوم وPoC وتحليل الترقيع.
يمكن لمستخدم بدور Contributor مُصادَق عليه تخزين بيانات وصفية للصور من منصات يتحكم بها المهاجم في إضافة WordPress Strong Testimonials. قبل الإصدار 3.3.12، كانت الإضافة تعرض القيمة المخزّنة داخل سمة src لوسم الصورة دون تهريب سياقي. بعد أن ينشر المسؤول الشهادة المُصمَّمة ومنشورًا يعرضها، يُنفَّذ الحمولة للزوار الذين يفتحون ذلك المنشور، بما في ذلك الزوار غير المُصادَق عليهم.
أُجري هذا البحث في مختبر محلي مُصرَّح به وأُفصح عنه عبر Patchstack قبل الإصدار العام.
| الحقل | القيمة |
|---|---|
| CVE | CVE-2026-97286 |
| المنتج | Strong Testimonials |
| المورّد | WP Chill |
| معرّف الإضافة | strong-testimonials |
| الثغرة | XSS مخزّن مُصادَق عليه |
| الإصدارات المتأثرة | <= 3.3.11 |
| الإصدار المُصحَّح | 3.3.12 |
| الصلاحية المطلوبة | Contributor أو أعلى |
| CWE | CWE-79: التحايد غير السليم للمدخلات أثناء توليد صفحة الويب |
| CVSS v3.1 | 6.5 متوسط — CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:L |
| الباحث | Rully Miftahur Rozaq |
| تاريخ الإبلاغ | 16 سبتمبر 2026 |
| الإفصاح العام | 30 سبتمبر 2026 |
يصنّف Patchstack التنبيه على أنه منخفض الأولوية رغم أن شدة الأساس المُخصَّصة وفق CVSS v3.1 هي متوسط.
يقبل محرر الشهادات مصفوفة طلب custom ويحفظ كل مفتاح مُرسَل كبيانات وصفية للمنشور. المفاتيح غير الموجودة في تعريف الحقل المخصص المُهيَّأ تمر عبر sanitize_text_field(). يتيح ذلك لمستخدم بدور Contributor إرسال بيانات وصفية محجوزة للإضافة مثل platform وplatform_user_photo أثناء تحرير شهادة يملكها.
بالنسبة لمنصات التواصل الاجتماعي المدعومة، تسترجع الإضافة platform_user_photo، وتتحقق من أن عنوان URL يعيد استجابة HTTP 200، ثم تُدرج السلسلة الأصلية المخزّنة داخل سمة <img src="https://raw.githubusercontent.com/rully2212/cve-2026-97286/main/...">. لا يجعل التحقق من حالة HTTP السلسلة آمنة لسمة HTML. يمكن لعلامة اقتباس في جزء من عنوان URL أن تُنهي src وتُدخل معالج حدث.
سلسلة الهجوم المُتحقَّق منها هي:
الحقن مُصادَق عليه. لا يحتاج الزائر الذي يُشغّل الحمولة المنشورة مسبقًا إلى أن يكون مُصادَقًا عليه.
يوفر الاستغلال الناجح تنفيذًا مستمرًا لـ JavaScript في أصل WordPress المتأثر على الصفحات التي تعرض الشهادة المُصمَّمة عبر مسار الصورة المصغّرة المتأثر. يُنفَّذ الكود بصلاحيات المتصفح وجلسة WordPress الخاصة بالزائر، إن وُجدت.
يتطلب المسار المُعاد إنتاجه نشرًا من المسؤول، وهو ما يفسّر مقياس UI:R في CVSS. لم يُثبت هذا البحث حقنًا غير مُصادَق عليه، ولا تنفيذًا تلقائيًا عبر كل صفحات الموقع، ولا تصعيدًا للصلاحيات، ولا سرقة ملفات تعريف الارتباط، ولا اختراقًا كاملًا للموقع.
أُعيد إنتاج إثبات المفهوم بالإعداد التالي:
| المكوّن | الإعداد |
|---|---|
| WordPress | 7.1 |
| Strong Testimonials | 3.3.7، الإصدار المجاني |
| القالب | Twenty Twenty-Five |
| قالب العرض | default-theme |
| الصورة المصغّرة | مُفعَّلة |
| PHP / Apache | PHP 8.3.33 / Apache 2.4.68 |
| قاعدة البيانات | MariaDB 11.4 |
| دور المهاجم | Contributor |
| صلاحيات المهاجم | edit_posts=true، publish_posts=false، unfiltered_html=false |
كان الإصدار 3.3.7 هو الإصدار الدقيق المستخدم في المختبر. يحدد سجل CVE العام جميع الإصدارات حتى 3.3.11 كمتأثرة والإصدار 3.3.12 كمُصحَّح.
في admin/class-strong-testimonials-post-editor.php، تتكرر الدالة save_details() عبر كل إدخال في مصفوفة custom المُرسَلة. يصل المفتاح غير المعروف إلى فرع التعقيم العام ثم يُخزَّن باستخدام update_post_meta():
$custom = $_POST['custom'];
foreach ( $custom as $key => $value ) {
// ...
$sanitized_value = sanitize_text_field( $value );
update_post_meta( $post_id, $key, $sanitized_value );
}
يقوم المعالج الحقيقي بإجراء فحوصات nonce وتعقيم خاص بكل حقل. لا تعتمد النتيجة على تجاوز تلك الفحوصات أو تعديل شهادة مستخدم آخر. يقوم المساهم بتعديل شهادته الخاصة بشكل مشروع لكنه يزوّد المفاتيح المحجوزة platform وplatform_user_photo.
في الإصدارات المصابة، يقرأ includes/functions-image.php قيمة platform_user_photo، ويجري فحصًا لحالة HTTP عبر wpmtst_is_valid_image_url()، ويُدرج السلسلة الأصلية داخل سمة HTML:
$platform_user_photo = get_post_meta( $post_id, 'platform_user_photo', true );
if ( ! $platform_user_photo || ! wpmtst_is_valid_image_url( $platform_user_photo ) ) {
return $img;
}
return sprintf(
'<img src="https://raw.githubusercontent.com/rully2212/cve-2026-97286/main/%25s" %s %s/>',
$platform_user_photo,
$width ? "width='{$width}'" : '',
$height ? "height='{$height}'" : ''
);
لا يُرسَل الجزء المقتطع (fragment) من عنوان URL إلى خادم HTTP، لكنه يبقى في السلسلة النصية التي يعرضها PHP لاحقًا. لذلك يمكن للخادم أن يرى عنوان URL غير ضار يُرجع HTTP 200 بينما يتلقى المتصفح قيمة تحتوي على تسلسل كسر السمة (attribute-breakout).
يستدعي قالب default-theme الدالة wpmtst_get_thumbnail() ويُصدر مباشرةً ترميز الصورة المُعاد:
<figure class="wp-block-image wpmtst-testimonial-avatar">
<?php echo $wpmtst_avatar_html; ?>
</figure>
يفترض القالب أن المساعد أنتج بالفعل HTML آمنًا. في الإصدارات المتأثرة، لم يقم مساعد صور المنصة بتهريب عنوان URL الخاص بسياق src الخاص به.
أعد إنتاج هذه المشكلة فقط على نظام تملكه أو لديك إذن صريح باختباره.
<= 3.3.11 على موقع WordPress اختباري مصرح به.default-theme مع تفعيل الصور المصغرة.سجّل الدخول بصفتك Contributor وأنشئ مسودة شهادة جديدة.
التقط طلب الحفظ الشرعي POST /wp-admin/post.php باستخدام وكيل اعتراض. احتفظ بجسم النموذج الكامل، وكوكي الجلسة، وnonce جديد من WordPress، وnonce الخاص بالإضافة، ومعرّف الشهادة المملوكة لـ Contributor.
أضف هذه المعاملات إلى جسم النموذج:
custom[platform]=facebook
custom[platform_user_photo]=http://wordpress/index.php?rest_route=/#" onerror="alert(1)" x="
جزء نموذج مُرمَّز بعنوان URL:
&custom%5Bplatform%5D=facebook&custom%5Bplatform_user_photo%5D=http%3A%2F%2Fwordpress%2Findex.php%3Frest_route%3D%2F%23%22%20onerror%3D%22alert%281%29%22%20x%3D%22
اسم المضيف wordpress هو اسم خدمة Docker المستخدم في المختبر المحلي. في بيئة أخرى مصرّح بها، استبدله بنقطة نهاية اختبار يتحكم بها الباحث ويمكن الوصول إليها من WordPress وتعيد HTTP 200. لا تستهدف خدمات طرف ثالث أو خدمات داخلية حساسة.
أرسل طلب الحفظ المعدّل وقدّم الشهادة للمراجعة.
أنشئ منشور WordPress عاديًا يحتوي على كتلة Shortcode. استبدل المعرّفات النموذجية بمعرّف عرض Display ومعرّف الشهادة المصمّمة من تثبيت الاختبار:
[testimonial_view id="2" post_ids="22" thumbnail="1"]

أرسل المنشور للمراجعة. بصفتك مسؤولاً، انشر كلًا من الشهادة المُصاغة ومنشور التحفيز.
افتح منشور التحفيز المنشور في متصفح منفصل أو نافذة خاصة دون تسجيل الدخول إلى WordPress.
تم التحقق من القيمة المخزّنة مباشرةً من بيانات المنشور الوصفية:

احتوى رد الواجهة الأمامية على عنصر صورة مكافئ لـ:
<img src="http://wordpress/index.php?rest_route=/" onerror="alert(1)" x="" width="100" height="100">