
Schritt-für-Schritt technische Analyse von CVE-2019-1698, einer SQL-Injection-Sicherheitslücke in einem WordPress-Plugin, mit Code-Diff-Review, Identifizierung der verwundbaren Funktion und Ausnutzungsdemonstration mit curl.
Code-Referenz 1: https://plugins.trac.wordpress.org/changeset/3040809/notificationx/trunk/includes/Core/Rest/Analytics.php

Code-Referenz 2: https://plugins.trac.wordpress.org/changeset/3040809/notificationx/trunk/includes/Core/Database.php

Daher ist die folgende Datei für diese CVE relevant:
wp-content/plugins/notificationx/includes/Core/Rest/Analytics.php
Nun werden wir prüfen, ob die Datei anfälligen Code enthält:
Konzentrieren Sie sich auf die Funktion insert_analytics():
Sie empfängt $request (kommt vom Benutzer) und extrahiert den Parameter type.
Dieser Wert wird dann an die Funktion CoreAnalytics::get_instance()->insert_analytics() übergeben:

Um diesen Code auszulösen, können wir die zugeordnete Route (aus der Klasse Analytics, innerhalb der Funktion register_routes()) erkennen:
$this->namespace . '/' . $this->rest_base
Und der Konstruktor der Klasse Analytics gibt die Werte für die Variablen namespace und rest_base preis:
public function __construct() {
$this->namespace = 'notificationx/v1';
$this->rest_base = 'analytics';
add_action('rest_api_init', [$this, 'register_routes']);
}
Der relevante (anfällige) Code, der den vom Benutzer bereitgestellten Parameter type akzeptiert, ist also über die folgende Route erreichbar:
notificationx/v1/analytics
Aber mit welcher Methode erfolgt die Ausnutzung und wo befindet sich die SQL-Abfrage für die Injektion?
Da der vom Benutzer bereitgestellte Parameter type an folgende Funktion übergeben wird:
CoreAnalytics::get_instance()->insert_analytics( absint( $params['nx_id'] ), $type );
Lokalisieren dieser Funktion:
Überprüfen wir diesen Funktionscode in der hervorgehobenen Datei:
wp-content/plugins/notificationx/includes/Core/Analytics.php:

Wenn Sie glauben, dass die Sicherheitslücke in der Funktion increment_count() liegt, liegen Sie absolut richtig!
Hier ist die Funktion increment_count (und sie hat den Parameter $type vom Benutzer):

Diese Funktion ruft wiederum die Funktion update_analytics() auf. Betrachten wir sie:


Die Funktion update_analytics erstellt dynamisch eine SQL-Abfrage, und die nicht bereinigte Benutzereingabe ist ein Teil davon. Das riecht verdächtig? Sollte es auch, denn das verursacht die Sicherheitslücke.
Der Parameter $col entspricht dem Parameter type, der vom Benutzer in der HTTP-Anfrage gesendet wird.
Der $table_name ist auf nx_stats gesetzt:
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';
}
Um das korrekte Verb zu identifizieren, habe ich die WordPress REST API genutzt:
http://localhost/wp-json/

Die API-Route /notificationx/v1/analytics kann durch eine POST-Anfrage ausgelöst werden, und wir müssen nx_id (eine Ganzzahl) und (optional) type (einen String) übergeben.
Denken Sie daran, dass die Analyseinformationen in der Tabelle nx_stats aktualisiert wurden, die wir zuvor anhand dieser Code-Ausschnitte aus wp-content/plugins/notificationx/includes/Core/Database.php abgeleitet haben:
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;

Unser Plan ist, die konstruierte SQL-Abfrage zu sehen, wenn wir unsere Nutzlast in der Anfrage übergeben.
Und jetzt senden wir unsere curl-Anfrage (mit dem SQLi-Payload) erneut:
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)-- -'
