135 lines
3.8 KiB
Ruby
135 lines
3.8 KiB
Ruby
##
|
|
# This module requires Metasploit: https://metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
require 'rex/java/serialization'
|
|
|
|
class MetasploitModule < Msf::Auxiliary
|
|
include Msf::Exploit::Remote::Java::Rmi::Client
|
|
include Msf::Auxiliary::Scanner
|
|
include Msf::Auxiliary::Report
|
|
|
|
def initialize
|
|
super(
|
|
'Name' => 'Java JMX Server Insecure Endpoint Code Execution Scanner',
|
|
'Description' => 'Detect Java JMX endpoints',
|
|
'Author' => ['rocktheboat'],
|
|
'License' => MSF_LICENSE,
|
|
'References' =>
|
|
[
|
|
['URL', 'https://docs.oracle.com/javase/8/docs/technotes/guides/jmx/JMX_1_4_specification.pdf'],
|
|
['URL', 'https://www.optiv.com/blog/exploiting-jmx-rmi'],
|
|
['CVE', '2015-2342']
|
|
],
|
|
'Platform' => 'java',
|
|
'DisclosureDate' => 'May 22 2013'
|
|
)
|
|
|
|
register_options(
|
|
[
|
|
Opt::RPORT(1099)
|
|
])
|
|
end
|
|
|
|
def run_host(target_host)
|
|
mbean_server = { "address" => rhost, "port" => rport }
|
|
|
|
connect
|
|
print_status("Sending RMI header...")
|
|
unless is_rmi?
|
|
print_status("#{rhost}:#{rport} Java JMX RMI not detected")
|
|
disconnect
|
|
return
|
|
end
|
|
|
|
mbean_server = discover_endpoint
|
|
disconnect
|
|
|
|
if mbean_server.nil?
|
|
print_status("#{rhost}:#{rport} Java JMX MBean not detected")
|
|
return
|
|
end
|
|
|
|
connect(true, { 'RHOST' => mbean_server[:address], 'RPORT' => mbean_server[:port] })
|
|
|
|
unless is_rmi?
|
|
print_status("#{rhost}:#{rport} Java JMX RMI not detected")
|
|
disconnect
|
|
return
|
|
end
|
|
|
|
jmx_endpoint = handshake(mbean_server)
|
|
disconnect
|
|
|
|
if jmx_endpoint == false
|
|
print_status("#{mbean_server[:address]}:#{mbean_server[:port]} Java JMX MBean authentication required")
|
|
return
|
|
elsif jmx_endpoint.nil?
|
|
print_status("#{mbean_server[:address]}:#{mbean_server[:port]} Java JMX MBean status unknown")
|
|
return
|
|
end
|
|
|
|
print_good("Handshake with JMX MBean server on #{jmx_endpoint[:address]}:#{jmx_endpoint[:port]}")
|
|
svc = report_service(:host => rhost, :port => rport, :name => "java-rmi", :info => "JMX MBean server accessible")
|
|
report_vuln(
|
|
:host => rhost,
|
|
:service => svc,
|
|
:name => self.name,
|
|
:info => "Module #{self.fullname} confirmed RCE via JMX RMI service",
|
|
:refs => self.references
|
|
)
|
|
end
|
|
|
|
def is_rmi?
|
|
send_header
|
|
ack = recv_protocol_ack
|
|
if ack.nil?
|
|
return false
|
|
end
|
|
|
|
true
|
|
end
|
|
|
|
def discover_endpoint
|
|
rmi_classes_and_interfaces = [
|
|
'javax.management.remote.rmi.RMIConnectionImpl',
|
|
'javax.management.remote.rmi.RMIConnectionImpl_Stub',
|
|
'javax.management.remote.rmi.RMIConnector',
|
|
'javax.management.remote.rmi.RMIConnectorServer',
|
|
'javax.management.remote.rmi.RMIIIOPServerImpl',
|
|
'javax.management.remote.rmi.RMIJRMPServerImpl',
|
|
'javax.management.remote.rmi.RMIServerImpl',
|
|
'javax.management.remote.rmi.RMIServerImpl_Stub',
|
|
'javax.management.remote.rmi.RMIConnection',
|
|
'javax.management.remote.rmi.RMIServer'
|
|
]
|
|
|
|
ref = send_registry_lookup(name: "jmxrmi")
|
|
return nil if ref.nil?
|
|
|
|
unless rmi_classes_and_interfaces.include? ref[:object]
|
|
vprint_error("JMXRMI discovery returned unexpected object #{ref[:object]}")
|
|
return nil
|
|
end
|
|
|
|
ref
|
|
end
|
|
|
|
def handshake(mbean)
|
|
opts = {
|
|
object_number: mbean[:object_number],
|
|
uid_number: mbean[:uid].number,
|
|
uid_time: mbean[:uid].time,
|
|
uid_count: mbean[:uid].count
|
|
}
|
|
send_new_client(opts)
|
|
rescue ::Rex::Proto::Rmi::Exception => e
|
|
vprint_error("JMXRMI discovery raised an exception of type #{e.message}")
|
|
if e.message == 'java.lang.SecurityException'
|
|
return false
|
|
end
|
|
return nil
|
|
end
|
|
end
|