CVE-2022–21661 WordPress核心框架WP_Query SQL注入漏洞原理分析與復現
漏洞信息
近日,WordPress官方發布了多個漏洞信息:

其中一處關于`WP_Query`的SQL注入漏洞值得關注,編號為CVE-2022–21661。
`WP_Query`是WordPress提供的一個用于處理復雜SQL查詢的類,在WordPress核心框架和插件中使用范圍非常廣泛,用戶可以通過`WP_Query`類完成數據庫查詢操作,方便構建WordPress的輸出內容。
補丁對比
首先進行補丁對比,發現修改的文件不多,最關鍵的地方位于`class-wp-tax-query.php`文件的函數`clean_query`:

補丁中,對`$query['terms']`的賦值取決于`$query['field']`的取值。
觸發點分析
下面分析一下`clean_query`函數:

第559行通過`array_unique`函數移除`$query['terms']`數組中的重復項后,首先進行了一個`if`判斷:
if (is_taxonomy_hierarchical($query['taxonomy'])&&$query['include_children'])
可以通過控制`$query['taxonomy']`或者`$query['include_children']`的取值使得`if`判斷不成立,這樣就直接將`$query['terms']`帶入了函數`transform_query`:

可以設置`$query['field']`的值為`term_taxonomy_id`,這樣函數會直接返回,也就是說可以通過控制`$query`的取值來繞過`clean_query`函數的處理。下面查找一下`clean_query`函數被調用的情況:

只存在函數`get_sql_for_clause`這唯一的一個調用:

通過`clean_query`處理參數`$clause`的引用對象,然后賦值給`$terms`,當存在`IN`操作時,調用函數`implode`以`,`將數組`$terms`轉換為字符串,繼續往下走:

將`$terms`字符串拼接進入`$where`,并最終帶入SQL查詢語句。回顧`get_sql_for_clause`函數的處理過程,可以通過構造特殊`$query`,導致輸入參數無過濾處理就直接帶入SQL語句,導致出現SQL注入漏洞。
調用鏈分析
查找函數`get_sql_for_clause`的調用鏈:

可以構建一條從`WP_Query`構造函數出發,到達`get_sql_for_clause`函數的完整調用鏈條:
WP_Query#__construct WP_Query#query WP_Query#get_posts WP_Tax_Query#get_sql WP_Tax_Query#get_sql_clauses WP_Tax_Query#get_sql_for_query WP_Tax_Query#get_sql_for_clause

漏洞復現
通過前面分析,我們知道參數`$query`只需要滿足以下2個條件,就可以觸發SQL注入漏洞:
- `$query['include_children']`取值為`false`(或者`is_taxonomy_hierarchical($query['taxonomy'])`取值為`false`);
- `$query['field']`取值為`term_taxonomy_id`
分析WordPress核心框架本身的漏洞潛在觸發點:

一共找到205處調用,但是比較遺憾的是未能在WordPress核心框架中直接找到滿足漏洞觸發前提條件的場景。WordPress插件數量眾多,應該可以找到一些滿足條件的漏洞觸發點,有興趣的小伙伴可以自行去跟蹤研究。
為了方面驗證漏洞,這里構建一個自定義URL頁面模板。修改默認主題樣式的`applications.php`,手動增加一個名為`wp_ajax_nopriv_test`的AJAX請求定義:

為了方便測試,開啟DEBUG模式,然后構造請求進行發送:


修復方式
回顧前面的補丁對比,新版本`class-wp-tax-query.php`中的函數`clean_query`修改代碼如下:
if ( 'slug' === $query['field'] || 'name' === $query['field'] ) { $query['terms'] = array_unique( (array) $query['terms'] );} else { $query['terms'] = wp_parse_id_list($query['terms']);}
通過函數`wp_parse_id_list`限制了`$query['terms']`數組元素類型必須是整數。
