Add initial support for better RMI calls

This commit is contained in:
jvazquez-r7 2015-03-16 23:44:16 -05:00
parent ac0e23d783
commit 0a37df67a0
5 changed files with 124 additions and 19 deletions

View File

@ -76,6 +76,7 @@ require 'msf/http/jboss'
require 'msf/kerberos/client'
# Java RMI Support
require 'msf/java/rmi/util'
require 'msf/java/rmi/client'
# Java JMX Support

View File

@ -9,7 +9,9 @@ module Msf
module Client
require 'msf/java/rmi/client/streams'
require 'msf/java/rmi/util'
include Msf::Java::Rmi::Util
include Msf::Java::Rmi::Client::Streams
include Exploit::Remote::Tcp

View File

@ -30,17 +30,49 @@ module Msf
# Builds a RMI call stream
#
# @param opts [Hash{Symbol => <Fixnum, Rex::Java::Serialization::Model::Stream>}]
# @param opts [Hash{Symbol => <Fixnum, Array>}]
# @option opts [Fixnum] :message_id
# @option opts [Rex::Java::Serialization::Model::Stream] :call_data
# @option opts [Fixnum] :object_number Random to identify the object.
# @option opts [Fixnum] :uid_number Identifies the VM where the object was generated.
# @option opts [Fixnum] :uid_time Time where the object was generated.
# @option opts [Fixnum] :uid_count Identifies different instance of the same object generated from the same VM
# at the same time.
# @option opts [Fixnum] :operation On JDK 1.1 stub protocol the operation index in the interface. On JDK 1.2
# it is -1.
# @option opts [Fixnum] :method_hash On JDK 1.1 stub protocol the stub's interface hash. On JDK1.2 is a hash
# representing the method to call.
# @option opts [Array] :arguments
# @return [Rex::Proto::Rmi::Model::Call]
def build_call(opts = {})
message_id = opts[:message_id] || Rex::Proto::Rmi::Model::CALL_MESSAGE
call_data = opts[:call_data] || Rex::Java::Serialization::Model::Stream.new
object_number = opts[:object_number] || 0
uid_number = opts[:uid_number] || 0
uid_time = opts[:uid_time] || 0
uid_count = opts[:uid_count] || 0
operation = opts[:operation] || -1
method_hash = opts[:method_hash] || 0
arguments = opts[:arguments] || []
block_data = Rex::Java::Serialization::Model::BlockData.new
block_data.contents = [
object_number,
uid_number,
uid_time,
uid_count,
operation,
method_hash
].pack('qlqslq')
block_data.length = block_data.contents.length
call_data = Rex::Java::Serialization::Model::Stream.new
call_data.contents << block_data
arguments.each do |arg|
call_data.contents << arg
end
call = Rex::Proto::Rmi::Model::Call.new(
message_id: message_id,
call_data: call_data
message_id: message_id,
call_data: call_data
)
call

49
lib/msf/java/rmi/util.rb Normal file
View File

@ -0,0 +1,49 @@
# -*- coding: binary -*-
require 'rex/java/serialization'
require 'rex/text'
module Msf
module Java
module Rmi
module Util
# Calculates a method hash to make RMI calls as defined by the JDK 1.2
#
# @param signature [String] The remote method signature as specified by the JDK 1.2,
# method name + method descriptor (as explained in the Java Virtual Machine Specification)
# @return [Fixnum] The method hash
# @see http://docs.oracle.com/javase/8/docs/platform/rmi/spec/rmi-stubs24.html The RemoteRef Interface documentation to understand how method hashes are calculated
def calculate_method_hash(signature)
utf = Rex::Java::Serialization::Model::Utf.new(nil, signature)
sha1 = Rex::Text.sha1_raw(utf.encode)
sha1.unpack('Q<')[0]
end
# Calculates an interface hash to make RMI calls as defined by the JDK 1.1
#
# @param methods [Array] set of method names and their descriptors
# @param exceptions [Array] set of declared exceptions
# @return [Fixnum] The interface hash
# @see http://docs.oracle.com/javase/8/docs/platform/rmi/spec/rmi-stubs24.html The RemoteRef Interface documentation to understand how interface hashes are calculated
def calculate_interface_hash(methods, exceptions)
stream = ''
stream << [1].pack('N') # stub version number
methods.each do |m|
utf_method = Rex::Java::Serialization::Model::Utf.new(nil, m[:name])
utf_descriptor = Rex::Java::Serialization::Model::Utf.new(nil, m[:descriptor])
stream << utf_method.encode
stream << utf_descriptor.encode
exceptions.each do |e|
utf_exception = Rex::Java::Serialization::Model::Utf.new(nil, e)
stream << utf_exception.encode
end
end
sha1 = Rex::Text.sha1_raw(stream)
sha1.unpack('Q<')[0]
end
end
end
end
end

View File

@ -51,7 +51,27 @@ class Metasploit3 < Msf::Auxiliary
jar = Rex::Text.rand_text_alpha(rand(8)+1) + '.jar'
jar_url = "file:RMIClassLoaderSecurityTest/" + jar
send_call(call_data: build_gc_call_data(jar_url))
print_status(calculate_interface_hash(
[
#{name: 'clean', descriptor: '([Ljava.rmi.server.ObjID;;J;Ljava.rmi.dgc.VMID;;Z)V'},
#{name: 'dirty', descriptor: '([Ljava.rmi.server.ObjID;;J;Ljava.rmi.dgc.Lease;)Ljava.rmi.dgc.Lease;'}
{name: 'sayHello', descriptor: '()Ljava/lang/String;'},
{name: 'sayHelloTwo', descriptor: '(Ljava/lang/String;)Ljava/lang/String;'}
],
['java.rmi.RemoteException']
).to_s)
# JDK 1.1 stub protocol
# Interface hash: 0xf6b6898d8bf28643 (sun.rmi.transport.DGCImpl_Stub)
# Operation: 0 (public void clean(ObjID[] paramArrayOfObjID, long paramLong, VMID paramVMID, boolean paramBoolean))
send_call(
object_number: 2,
uid_number: 0,
uid_time: 0,
uid_count: 0,
operation: 0,
method_hash: 0xf6b6898d8bf28643,
arguments: build_dgc_clean_args(jar_url)
)
return_data = recv_return
if return_data.nil?
@ -90,14 +110,10 @@ class Metasploit3 < Msf::Auxiliary
false
end
def build_gc_call_data(jar_url)
stream = Rex::Java::Serialization::Model::Stream.new
block_data = Rex::Java::Serialization::Model::BlockData.new
block_data.contents = "\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"
block_data.length = block_data.contents.length
stream.contents << block_data
# class: sun.rmi.trasnport.DGC
# method: public void clean(ObjID[] paramArrayOfObjID, long paramLong, VMID paramVMID, boolean paramBoolean)
def build_dgc_clean_args(jar_url)
arguments = []
new_array_annotation = Rex::Java::Serialization::Model::Annotation.new
new_array_annotation.contents = [
@ -124,8 +140,11 @@ class Metasploit3 < Msf::Auxiliary
new_array.values = []
new_array.array_description = array_desc
stream.contents << new_array
stream.contents << Rex::Java::Serialization::Model::BlockData.new(nil, "\x00\x00\x00\x00\x00\x00\x00\x00")
# ObjID[] paramArrayOfObjID
arguments << new_array
# long paramLong
arguments << Rex::Java::Serialization::Model::BlockData.new(nil, "\x00\x00\x00\x00\x00\x00\x00\x00")
new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'metasploit.RMILoader')
@ -145,11 +164,13 @@ class Metasploit3 < Msf::Auxiliary
new_object.class_desc.description = new_class_desc
new_object.class_data = []
stream.contents << new_object
# VMID paramVMID
arguments << new_object
stream.contents << Rex::Java::Serialization::Model::BlockData.new(nil, "\x00")
# boolean paramBoolean
arguments << Rex::Java::Serialization::Model::BlockData.new(nil, "\x00")
stream
arguments
end
end