WordPress Core <= 7.1.1 ثغرة تضمين ملفات محلية (LFI) غير مصادق عليها تؤدي إلى تنفيذ أوامر عن بُعد (RCE) - مختبر تحقق، إثبات مفهوم، قالب nuclei (GHSA-7hp8-65ch-5whp)
مواد بحث أمني لإعادة إنتاج والتحقق من CVE-2026-87902 (GHSA-7hp8-65ch-5whp) في مختبر Docker معزول يعمل على loopback فقط: تضمين ملف محلي غير مصادق عليه في حل قوالب صفحات نواة WordPress، قابل للتصعيد إلى تنفيذ تعليمات برمجية عن بُعد.
AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N)الحالة: مُثبت في المختبر المرفق.
يسمح WordPress 7.1.1 (قالب Twenty Twelve) لمهاجم غير مصادق عليه بتضمين ملفات PHP من خارج دليل القالب عبر متغير الاستعلام pagename، و- مع الإعداد الافتراضي register_argc_argv = On في صورة PHP الرسمية - بكتابة وتنفيذ ملف علامة عبر PEAR pearcmd.php:
WordPress: 7.1.1
Theme: twentytwelve (page-templates/ present)
PHP: 8.2 (official image, register_argc_argv=On, PEAR present)
Result: LFI oracle fired (<opml version="1.0">); marker probe executed as
uid=33(www-data) and self-deleted
يمنع WordPress 7.1.2 مع الإعداد المطابق الـ oracle تمامًا (التحكم السلبي). يوضح هذا تنفيذ التعليمات البرمجية كمستخدم خادم الويب WordPress داخل الحاوية. لا يوضح الوصول إلى root، أو الهروب من الحاوية، أو الحركة الجانبية، أو اختراق المضيف.
المتطلبات: Docker مع Compose v2، Python 3.10+، وصول شبكي إلى Docker Hub و wordpress.org (تثبيت القالب).
./lab verify
يقوم هذا ببناء المختبر المعرّض للثغرة، ويتطلب إطلاق LFI oracle وعلامة RCE، ثم يبني المختبر المرقّع ويتطلب بقاء الـ oracle صامتًا.
لاستخدام منفذ loopback آخر: LAB_PORT=9499 ./lab verify.
أزل كل شيء بعد ذلك باستخدام ./lab reset.
التحكم المعرّض للثغرة:
[+] page-* folder(s) reachable: page-templates (traversal can resolve)
[!!!] LFI CONFIRMED (safe oracle: wp-links-opml.php)
...
[RCE] pearcmd.php reachable and taking argv: /usr/local/lib/php/pearcmd.php
[!!!] RCE CONFIRMED (pearcmd.php config-create file write):
evidence: uid=33(www-data) (command `id` ran as the web user)
cleanup : probe self-deleted on execution: confirmed
RESULT: VULNERABLE CONTROL CONFIRMED
التحكم المرقّع:
[=] oracles did not fire: target patched (>= 7.1.2), ...
RESULT: PATCHED CONTROL CONFIRMED
لا يُقبل HTTP 200، أو حظر WAF، أو اجتياز جزئي بدون علامة الـ oracle كدليل.
./lab start vulnerable # fresh 7.1.1 lab on 127.0.0.1:9471
./lab test # assert LFI + RCE
./lab start patched # fresh 7.1.2 lab
./lab test # assert oracle absence
./lab status
./lab reset # containers, volumes, state
شغّل الأدوات يدويًا ضد المختبر قيد التشغيل:
python3 poc/triage_cve_2026_87902.py --url http://127.0.0.1:9471
python3 poc/poc_cve_2026_87902.py --url http://127.0.0.1:9471 --rce
nuclei -t nuclei/cve-2026-87902.yaml -u http://127.0.0.1:9471 -silent
للأنظمة التي تملكها أو المصرّح لك صراحةً باختبارها (نطاق bug-bounty، ارتباط مكتوب)، تتطلب برامج التشغيل التجاوز الصريح:
python3 poc/poc_cve_2026_87902.py --url https://target.example \
--allow-authorized-non-loopback [--insecure] [--rce]
تبني get_page_template() في wp-includes/template.php اسم ملف قالب مرشحًا من متغير الاستعلام pagename. يمرر الفرع الشقيق قبل ثلاثة أسطر أعلاه slug قالب الصفحة عبر validate_file()؛ لم يفعل فرع pagename ذلك أبدًا، ويضيف بالإضافة إلى ذلك مرشحًا إضافيًا مفكوك الترميز بـ urldecode():
// wp-includes/template.php, get_page_template(), WordPress <= 7.1.1
if ( $pagename ) {
$pagename_decoded = urldecode( $pagename );
if ( $pagename_decoded !== $pagename ) { // 7.1.2 adds validate_file()
$templates[] = "page-{$pagename_decoded}.php";
}
$templates[] = "page-{$pagename}.php";
}
يطبّق 7.1.2 validate_file() على المرشح المفكوك و يضيف بوابة احتواء (_wp_is_template_path_allowed()) يجب أن يجتازها كل مسار قالب محلول.
locate_template() كليهما)
يحتوي على دليل من المستوى الأعلى يبدأ بـ page-. القوالب الافتراضية القديمة
(Twenty Twelve، Twenty Fourteen) والعديد من قوالب wp.org (Neve، Hestia،
Sydney) تستوفي الشرط. القوالب التجارية التي تم بحثها (Divi، Avada، Flatsome،
Woodmart، Betheme، The7، Enfold، Salient، Jupiter/X، Porto، Houzez، XStore،
Kalium، Uncode) لا تحتوي على أي منها - لا يمكن للاجتياز أن يُحل؛ انظر
PRO_THEME_PAGE_DIRS في PoC للقائمة المستمدة من المرايا..php (يُضاف بواسطة الكود).register_argc_argv = On و pearcmd.php الخاص بـ PEAR.يمتنع التنبيه وكتابة Patchstack عن نشر طلب عملي. تم إثبات هذه التفاصيل تجريبيًا في هذا المختبر:
page_id إلزامية. pagename غير المحلول يقلب
is_404، الذي يحجب قالبه get_page_template() تمامًا. ثبّت
الاستعلام بأي page_id منشور قابل للحل.get_posts() كتابة pagename
عبر sanitize_title_for_query( wp_basename( … ) ): يتحول .. الخام إلى
-، لكن تسلسلات %hex تنجو؛ يكشف urldecode() الإضافي في
get_page_template() الاجتياز. فقط %252e/%252f يعمل.redirect_canonical توجيه GET بـ 301 ويسقط
الحمولة؛ يعود فورًا لغير GET/HEAD).../ من page-templates/ على docroot قياسي.$_POST في متغيرات
الاستعلام) - أساس طبقات تجاوز WAF.$argv، و
مُسلسِل إعدادات PEAR يهرّب نمطي علامات الاقتباس - ومن هنا المسبار
الخام، بلا علامات اقتباس، مفصول بـ +.| المسار | الغرض |
|---|---|
poc/poc_cve_2026_87902.py | PoC كامل: بصمة الإصدار + WAF، تعداد مجلد القالب/page-* (wp.org SVN، اكتشاف مرجع الأصول، خريطة القوالب التجارية المبحوثة)، اكتشاف المرساة، 8 متغيرات LFI oracle، oracle احتياطي مقارن بجسم فارغ، سلسلة pearcmd --rce، عرض docker --lab |
poc/triage_cve_2026_87902.py | حكم لكل هدف أو دفعة مع البوابة الفاشلة المسمّاة (EXPLOITABLE / NOT EXPLOITABLE / WAF SUSPECTED / INCONCLUSIVE) |
poc/bounty_screen.py | يعمل على قائمة أصول bug-bounty داخل النطاق: توسيع wildcard عبر crt.sh → تصفية WP → فحص الشروط المسبقة → تسليم المرشحين |
nuclei/cve-2026-87902.yaml | قالب Nuclei: LFI oracle آمن (174 حمولة: 10 بقايا page-*، طبقات مزدوجة/ثلاثية الترميز، معرفات 1–30) |
يغطي بصمة WAF كلاً من Imperva/Incapsula، Cloudflare، Akamai، AWS
CloudFront/WAF، Sucuri، F5. ثمانية متغيرات oracle: مزدوج الترميز، تهجئة
بديلة %25%32%65، تلويث المعاملات، ثلاثي الترميز - كل منها في سلسلة
الاستعلام وجسم POST. تم اختبار أجسام multipart والحمولات ذات الشرطة المائلة الخام ورُفضت (لا يعالجها WP لهذه النقطة).
| الإصدار | التقييم |
|---|---|
| WordPress 7.1.1 | أُعيد إنتاج LFI + pearcmd RCE من البداية إلى النهاية |
| WordPress 6.5.3 / 5.9.17 | أُعيد إنتاج LFI oracle |
| WordPress 4.7.0–7.1.1 (فروع أخرى) | مُبلّغ عنه كمتأثر؛ جدول الفروع حسب GHSA |
| WordPress 7.1.2 | أُعيد إنتاج التحكم السلبي المرقّع |
.
├── .github/workflows/validate.yml
├── .gitignore
├── LICENSE
├── README.md
├── SECURITY.md
├── docker-compose.yml
├── lab
├── nuclei/
│ └── cve-2026-87902.yaml
└── poc/
├── bounty_screen.py
├── poc_cve_2026_87902.py
└── triage_cve_2026_87902.py
غير مُلتزم به: .lab-state، __pycache__/، ملفات مخرجات screener.
| الادعاء | الحالة |
|---|---|
| LFI غير مصادق عليه خارج دليل القالب | مُثبت (7.1.1، 6.5.3، 5.9.17) |
RCE عبر pearcmd.php config-create كمستخدم الويب | مُثبت (مختبر 7.1.1) |
| الحذف الذاتي للمسبار / لا آثار دائمة | مُثبت |
| التحكم السلبي المرقّع (7.1.2) | مُثبت |
| كل إصدار متأثر وسيط تم اختباره | غير مختبر |
| متغيرات تجاوز WAF ضد WAFs تجارية حية | مستمدة من المختبر، غير مختبرة ضد WAF |
| صلاحية root / الهروب من الحاوية / اختراق المضيف | غير مُدّعى |
page_id والترميز المزدوج؛ مصدر
oracle المقارن بجسم فارغ wp-content/index.php، المُضمّن هنا كخيار
احتياطي للمواقع المُحصّنة)تم الإبلاغ عن الثغرة بواسطة Robert Ressl. هذا المستودع تحليل وأدوات طرف ثالث مستقلة.
MIT - انظر LICENSE.
شغّل هذا المستودع فقط على الأنظمة التي تملكها أو المصرّح لك صراحةً
باختبارها. يرفض مشغّل المختبر المتغيرات غير vulnerable/patched،
وترفض برامج Python أهداف غير loopback إلا إذا
تم توفير --allow-authorized-non-loopback، ومنفذ Compose مرتبط
بـ 127.0.0.1.
انظر SECURITY.md لمعالجة الإفصاح. لا يتضمن هذا المستودع أهداف إنتاج، أو بيانات عملاء، أو رموز وصول، أو أدلة من أنظمة حقيقية.
بشكل ملموس:
127.0.0.1 فقط.wp-links-opml.php، ملف نواة قياسي يطبع مستند OPML.--rce اختياري ويكتب مسبار علامة بلا علامات اقتباس، ذاتي الحذف
(<?=id,unlink(__FILE__)?>) عبر تقنية pearcmd.php
config-create الموثقة علنًا؛ يزيل المسبار نفسه عند تنفيذه الواحد
ويتحقق PoC من الحذف. لا shells، ولا callbacks، ولا استمرارية.start؛ لا
أدوات تتبع على الهدف.