131 lines
4.1 KiB
Ruby
131 lines
4.1 KiB
Ruby
##
|
|
# This file is part of the Metasploit Framework and may be subject to
|
|
# redistribution and commercial restrictions. Please see the Metasploit
|
|
# web site for more information on licensing and terms of use.
|
|
# http://metasploit.com/
|
|
##
|
|
|
|
require 'msf/core'
|
|
|
|
class Metasploit3 < Msf::Auxiliary
|
|
|
|
include Msf::Exploit::Remote::Tcp
|
|
include Msf::Auxiliary::Scanner
|
|
include Msf::Auxiliary::Report
|
|
|
|
def initialize
|
|
super(
|
|
'Name' => 'Java RMI Server Insecure Endpoint Code Execution Scanner',
|
|
'Description' => 'Detect Java RMI endpoints',
|
|
'Author' => ['mihi', 'hdm'],
|
|
'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'
|
|
)
|
|
|
|
register_options(
|
|
[
|
|
Opt::RPORT(1099)
|
|
], self.class)
|
|
end
|
|
|
|
def setup
|
|
buf = gen_rmi_loader_packet
|
|
|
|
jar = Rex::Text.rand_text_alpha(rand(8)+1) + '.jar'
|
|
old_url = "file:./rmidummy.jar"
|
|
new_url = "file:RMIClassLoaderSecurityTest/" + jar
|
|
|
|
# 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 = buf.index(find_me)
|
|
len = [new_url.length].pack("n")
|
|
|
|
# Now replace it with the new url
|
|
buf[idx, find_me.length] = len + new_url
|
|
|
|
@pkt = "JRMI" + [2,0x4b,0,0].pack("nCnN") + buf
|
|
end
|
|
|
|
def run_host(target_host)
|
|
|
|
begin
|
|
connect
|
|
sock.put("\x4a\x52\x4d\x49\0\x02\x4b")
|
|
res = sock.get_once
|
|
disconnect
|
|
|
|
if res and res =~ /^\x4e..([^\x00]+)\x00\x00/
|
|
info = $1
|
|
|
|
begin
|
|
# Determine if the instance allows remote class loading
|
|
connect
|
|
sock.put(@pkt) rescue nil
|
|
|
|
buf = ""
|
|
1.upto(6) do
|
|
res = sock.get_once(-1, 5) rescue nil
|
|
break if not res
|
|
buf << res
|
|
end
|
|
|
|
rescue ::Interrupt
|
|
raise $!
|
|
rescue ::Exception
|
|
ensure
|
|
disconnect
|
|
end
|
|
|
|
if buf =~ /RMI class loader disabled/
|
|
print_status("#{rhost}:#{rport} Java RMI Endpoint Detected: Class Loader Disabled")
|
|
report_service(:host => rhost, :port => rport, :name => "java-rmi", :info => "Class Loader: Disabled")
|
|
elsif buf.length > 0
|
|
print_good("#{rhost}:#{rport} Java RMI Endpoint Detected: Class Loader Enabled")
|
|
svc = report_service(:host => rhost, :port => rport, :name => "java-rmi", :info => "Class Loader: Enabled")
|
|
report_vuln(
|
|
:host => rhost,
|
|
:service => svc,
|
|
:name => self.name,
|
|
:info => "Module #{self.fullname} confirmed remote code execution via this RMI service",
|
|
:refs => self.references
|
|
)
|
|
else
|
|
print_status("#{rhost}:#{rport} Java RMI Endpoint Detected")
|
|
report_service(:host => rhost, :port => rport, :name => "java-rmi", :info => "")
|
|
end
|
|
|
|
end
|
|
|
|
rescue ::Interrupt
|
|
raise $!
|
|
rescue ::Rex::ConnectionError, ::IOError
|
|
ensure
|
|
disconnect
|
|
end
|
|
|
|
end
|
|
|
|
def gen_rmi_loader_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
|
|
|
|
end
|